קלט/פלט · נתונים באורך קבוע

sysread#

קריאת בתים גולמיים ממטפל קובץ על־ידי קריאה לקריאת המערכת read(2) שבבסיס.

sysread מנסה לקרוא LENGTH בתים מ־FILEHANDLE ולאחסן אותם ב־SCALAR. הוא עוקף את מחסנית ה־buffering של PerlIO, שזו כל המטרה - קריאות הולכות ישר לקרנל ומחזירות את כל מה ש־read(2) יחיד מחזיר, שיכול להיות פחות בתים מהמבוקש. יש להשתמש בו עבור סוקטים, pipes, התקנים, וכל מצב אחר שבו רוצים שליטה על קריאות מערכת בודדות במקום קלט מוכוון־שורות או מוכוון־רשומות.

תקציר#

sysread FILEHANDLE, SCALAR, LENGTH
sysread FILEHANDLE, SCALAR, LENGTH, OFFSET

מה מקבלים בחזרה#

  • מספר הבתים שנקראו בפועל, שעשוי להיות פחות מ־LENGTH בסוקטים, pipes, ttys, ובמהלך הפסקת אות.

  • 0 בסוף קובץ.

  • undef בשגיאה, עם $! מוגדר ל־errno מה־read(2) שנכשלה.

SCALAR גדל או מצטמצם כך שהבית האחרון שנקרא הופך לבית האחרון של הסקלר. לאחר קריאה קצרה, הסקלר מחזיק רק את הבתים שאכן התקבלו - דבר אינו מרופד באפסים עד ל־LENGTH.

my $n = sysread $sock, my $buf, 4096;
defined $n           or die "read failed: $!";
$n == 0              and return;          # peer closed
process_chunk($buf);                      # length($buf) == $n

מצב גלובלי שהוא נוגע בו#

  • $! - מוגדר כאשר sysread מחזיר undef. קריאות שהופסקו מופיעות כ־EINTR; קריאות שהיו נחסמות על מטפלים לא־חוסמים מופיעות כ־EAGAIN / EWOULDBLOCK.

  • SCALAR עצמו - תמיד מוקצה לו, גם בכישלון (הוא נחתך ל־OFFSET בתים כאשר OFFSET ניתן והקריאה נכשלת או מחזירה אפס).

  • מיקום הבית של מטפל הקובץ מתקדם במספר הבתים שהוחזרו; זהו אותו מיקום ברמת הקרנל המתופעל על־ידי sysseek.

sysread אינו מתייעץ או נוגע ב־$/, $\, $,, או $_. זהו פרימיטיב ברמת הבית; סמנטיקה של רשומות אינה חלה.

OFFSET - היכן הבתים נוחתים בתוך SCALAR#

ללא OFFSET, SCALAR מוחלף בבתים שנקראו.

עם OFFSET, הבתים נכתבים לתוך SCALAR החל מאותו מיקום:

  • OFFSET >= 0 - להתחיל לכתוב בבית OFFSET. אם OFFSET גדול מהאורך הנוכחי של SCALAR, המחרוזת מרופדת תחילה בבתי "\0" עד ל־OFFSET, ואז הנתונים החדשים מצורפים.

  • OFFSET < 0 - נספר לאחור מסוף SCALAR. -1 פירושו ״לדרוס את הבית האחרון״, -10 פירושו ״לדרוס את 10 הבתים האחרונים״.

כך מגדילים buffer באופן הדרגתי בלי לשרשר שוב ושוב:

my $buf = "";
while ((my $n = sysread $fh, $buf, 8192, length $buf) > 0) {
    # each call appends at the current end of $buf
}
defined $n or die "read failed: $!";

דוגמאות#

קריאה של עד 64 בתים מקובץ. $buf מסתיים באורך של בדיוק $n בתים:

open my $fh, "<", "input.bin" or die $!;
my $n = sysread $fh, my $buf, 64;
defined $n or die "sysread: $!";

קריאה של עד 32 בתים והנחתם החל ממיקום 512 ב־$buf, עם ריפוד ב־"\0" אם $buf היה קצר יותר:

my $buf = "header";
my $n = sysread $fh, $buf, 32, 512;   # $buf is now 512 + $n bytes

לרוקן סוקט עד שהעמית סוגר. בדיקה ל־0 - לא eof - היא בדיקת סוף־הזרם הנכונה היחידה עבור sysread:

while (1) {
    my $n = sysread $sock, my $chunk, 4096;
    defined $n or die "read: $!";
    last if $n == 0;                  # orderly shutdown from peer
    handle($chunk);
}

להפעיל מחדש קריאה שהופסקה על־ידי אות. על מטפל חוסם, EINTR הוא הכישלון היחיד שבדרך כלל מנסים שוב במקום להפיץ:

use Errno qw(EINTR);
my $n;
RETRY: {
    $n = sysread $fh, my $buf, $want;
    redo RETRY if !defined $n && $! == EINTR;
}
defined $n or die "read: $!";

מילוי רשומה בגודל קבוע, תוך סבילות לקריאות קצרות. sysread יחיד יכול להחזיר פחות בתים מהמבוקש גם בקובץ רגיל סמוך ל־EOF, ועושה זאת תדיר בסוקטים וב־pipes:

sub read_exact {
    my ($fh, $want) = @_;
    my $buf = "";
    while (length($buf) < $want) {
        my $n = sysread $fh, $buf, $want - length($buf), length $buf;
        defined $n        or die "read: $!";
        $n == 0 and die "short read: got ", length $buf, " of $want";
    }
    return $buf;
}

מקרי קצה#

  • לעולם אין לערבב עם I/O ב־buffer באותו מטפל. readline, read, <$fh>, getc, eof, seek, ו־tell כולם עוברים דרך buffers של PerlIO; sysread עוקף אותם. שילובם באותו מטפל משאיר נתונים תקועים ב־buffer ש־sysread לעולם לא יראה, או מדלג מעל נתונים שהקורא הב־buffer כבר צרך. יש להשתמש בסגנון אחד לכל מטפל.

  • :utf8 אסור. מטפל עם שכבת :utf8 (כולל השכבה המשתמעת המוספת על־ידי :encoding(...)) גורם ל־sysread לזרוק חריגה. יש להסיר את השכבה עם binmode - binmode $fh ללא ארגומנט שני משחזר בתים גולמיים - לפני קריאה ל־sysread.

  • :crlf / :perlio עדיין מבצעים buffering. גם ללא :utf8, מחסנית ברירת המחדל :perlio מבצעת buffer לקריאות ומתרגמת סופי שורה תחת :crlf. sysread מתעלם מהשכבות הללו, לכן בתים שהקורא הב־buffer כבר משך לתוך ה־buffer של PerlIO אובדים בשקט ל־sysread. יש לפתוח מטפלים המיועדים ל־sysread עם sysopen או לקרוא ל־binmode $fh כדי להשבית את :crlf.

  • קריאות קצרות הן רגילות, לא שגיאות. החזרה של $n עם 0 < $n < LENGTH היא הצלחה. רק undef מציין כישלון; 0 מציין EOF. יש לבצע לולאה עד שיש מה שצריך.

  • אין syseof. אין בדיקת סוף־קובץ נפרדת ל־sysread; eof מסתכל ב־buffer של PerlIO וחסר משמעות כאן. ערך ההחזרה 0 הוא אות סוף־הקובץ.

  • OFFSET מעבר לאורך הנוכחי. sysread $fh, $buf, 10, 1_000_000 מרפד את $buf במיליון בתי "\0" לפני הכתיבה. זה שימושי מדי פעם להקצאה מראש, אך בדרך כלל באג.

  • OFFSET שלילי נספר מהסוף הנוכחי של SCALAR, לא מ־LENGTH. sysread $fh, $buf, 4, -4 דורס את ארבעת הבתים האחרונים של מה ש־$buf מחזיק כעת.

  • מטפלים לא־חוסמים. על מטפל עם O_NONBLOCK מוגדר, קריאה ללא דבר זמין מחזירה undef עם $! שווה ל־EAGAIN או EWOULDBLOCK. יש להתייחס לזה כ־״לנסות שוב מאוחר יותר״, לא כשגיאה.

  • אותות. sysread חוסם שהופסק על־ידי אות מחזיר undef עם $! שווה ל־EINTR. יש לנסות את הקריאה שוב.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • syswrite - המקבילה בצד הכתיבה; אותם כללי buffering, אותה סמנטיקת I/O קצר

  • sysopen - פותח מטפל עם דגלי open(2) גולמיים, השותף הטבעי ל־sysread על קבצים

  • sysseek - seek מדויק־בית שמתרכב נכון עם sysread; אין לערבב את seek עם sysread

  • read - המקבילה הב־buffer; יש להשתמש בה עבור קלט מוכוון־שורות ומוכוון־רשומות, לא עבור סוקטים או קריאות חלקיות

  • binmode - להסיר :utf8 או :crlf ממטפל לפני שימוש ב־sysread

  • $! - ערך ה־errno לאחר sysread שנכשל, כולל EINTR, EAGAIN, ו־EWOULDBLOCK