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

read#

קורא כמות קבועה של קלט buffered ממטפל קובץ לתוך סקלר.

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

תקציר#

read FILEHANDLE, SCALAR, LENGTH
read FILEHANDLE, SCALAR, LENGTH, OFFSET

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

  • מספר התווים שנקראו, שיכול להיות פחות מ־LENGTH.

  • 0 בסוף הקובץ.

  • undef בשגיאה, כאשר $! מוגדר.

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

קריאה קצרה אינה שגיאה. על קובץ רגיל זה בדרך כלל אומר שהגעתם לסוף הקובץ; על pipe, socket, או טרמינל זה אומר שאין יותר נתונים זמינים ברגע זה. יש ללולל עד שיש לכם או את הבייטים שצריך או ש־read מחזיר 0 / undef:

my $buf = "";
my $want = 4096;
while ($want > 0) {
    my $got = read($fh, $buf, $want, length $buf);
    die "read error: $!" unless defined $got;
    last if $got == 0;                 # EOF
    $want -= $got;
}

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

  • $! - מוגדר כאשר read מחזיר undef.

  • ${^UTF8CACHE} / שכבות ה־PerlIO של המטפל - קובעות אם LENGTH נספר בבייטים או בתווים (ראו סמנטיקת תו מול בייט להלן).

read אינו מתקיים באינטראקציה עם $_, $/, $\, או $,. שלא כמו readline, לא אכפת לו ממפריד הרשומות של הקלט.

הארגומנט OFFSET#

OFFSET שולט ב־איפה ב־SCALAR הנתונים הנכנסים נוחתים. הוא אינו מבצע seek במטפל הקובץ.

  • מושמט - הנתונים מחליפים את כל תוכן SCALAR.

  • חיובי, בתוך האורך - הנתונים נכתבים החל מהמיקום OFFSET. תווים לפני OFFSET נשמרים; תווים מ־OFFSET עד סוף SCALAR נדרסים או מורחבים.

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

  • שלילי - סופר אחורה מסוף SCALAR. -1 משמעו ”דרוס את התו האחרון וצרף משם.“

my $buf = "HEADER";
read($fh, $buf, 16, length $buf);      # append 16 chars after "HEADER"

my $slab = "";
read($fh, $slab, 512, 1024);           # pad to 1024 "\0" bytes, then
                                       # read 512 chars - $slab is
                                       # now 1536 chars long

סמנטיקת תו מול בייט#

LENGTH נמדד ביחידה שבה המטפל עוסק:

  • מטפל במצב בייטים (ברירת המחדל, וכל מטפל הנפתח ללא שכבת קידוד): LENGTH הוא ספירת בייטים. read($fh, $buf, 10) מושך 10 בייטים ו־length $buf הוא 10.

  • שכבת :utf8: LENGTH הוא ספירת תווים. Perl מפענח UTF-8 בכניסה, ו־$buf מחזיק נקודות קוד מפוענחות. מספר הבייטים הנצרכים מהקובץ יכול להיות בכל מקום בין LENGTH ל־4 * LENGTH, תלוי בטקסט.

  • שכבת :encoding(...): אותו כלל כמו :utf8, עבור כל קידוד שהשכבה מכירה.

open my $fh, "<:utf8", "greek.txt" or die $!;
read($fh, my $buf, 5);                 # 5 characters, not 5 bytes

ערבוב קריאה במצב בייטים עם נתוני UTF-8 מייצר mojibake, ותחת use warnings, אזהרת Malformed UTF-8 אם תפענחו את התוצאה מאוחר יותר. יש לבחור את השכבה בזמן open ולהיצמד אליה.

קלט/פלט buffered מול לא־buffered#

read הוא stdio-buffered דרך PerlIO - באופן פנימי הוא קורא ל־fread(3) (או למחליף של PerlIO) מול ה־buffer של המטפל. לכך שתי השלכות שכדאי לזכור:

  • ניתן לערבב את read, readline / <$fh>, getc, ו־seek בחופשיות על אותו מטפל. כולם רואים את אותו buffer.

  • אסור לערבב את read עם sysread על אותו מטפל. sysread עוקף את ה־buffer ועובר ישר ל־read(2); כל בייט שכבר נמשך לתוך ה־buffer על ידי read קודם הופך לבלתי נראה ל־sysread, ולהפך. אם צריך סמנטיקת syscall גולמית, יש להשתמש ב־sysread באופן בלעדי על אותו מטפל.

לקלט מדויק בבייטים, לא־buffered - למשל על socket לא־חוסם, או בעת מימוש פרוטוקול שבו קריאה קצרה היא משמעותית במקום ”נסה שוב“ - יש לפנות ל־sysread.

דוגמאות#

קריאת כותרת בגודל קבוע מקובץ בינארי:

open my $fh, "<", "packet.bin" or die "open: $!";
binmode $fh;
my $header;
my $n = read($fh, $header, 16);
die "short header: got $n bytes" unless $n == 16;

צירוף 16 בייטים לסוף buffer קיים על ידי שימוש ב־OFFSET השווה לאורך הנוכחי:

my $buf = "PRELUDE:";
read($fh, $buf, 16, length $buf);      # $buf is now "PRELUDE:" . 16 new bytes

קריאה למיקום 1024 של סקלר, ריפוד הפער ב־"\0":

my $slot = "";
read($fh, $slot, 64, 1024);            # length($slot) == 1088
                                       # substr($slot, 0, 1024) is "\0" x 1024

ללולל עד שיש לכם בדיוק N בייטים או מגיעים ל־EOF - הדפוס הנכון עבור pipes ו־sockets שבהם read יחיד מחזיר לעיתים קרובות פחות בייטים מהמבוקש:

sub read_exact {
    my ($fh, $n) = @_;
    my $buf = "";
    while (length($buf) < $n) {
        my $got = read($fh, $buf, $n - length($buf), length $buf);
        return undef unless defined $got;
        return $buf if $got == 0;       # EOF; caller inspects length
        # loop
    }
    return $buf;
}

קריאה בספירת תווים דרך שכבת UTF-8:

open my $fh, "<:encoding(UTF-8)", "notes.txt" or die $!;
read($fh, my $chunk, 100);             # 100 characters
printf "chars=%d bytes=%d\n", length $chunk, do {
    use bytes; length $chunk;
};

מקרי קצה#

  • מטפל קובץ סגור: מחזיר undef ומגדיר את $! ל־"Bad file descriptor". תחת use warnings מונפקת אזהרת read() on closed filehandle.

  • מטפל קובץ לא־פתוח: כמו סגור - undef ו־$! מוגדר.

  • LENGTH של 0: read מחזיר 0 מיד ואינו נוגע ב־SCALAR. זה לא בדיקת EOF אמינה; יש להשתמש ב־eof לכך.

  • LENGTH שלילי: שגיאת זמן ריצה קטלנית (Negative length at ...). יש לאמת את LENGTH לפני הקריאה.

  • OFFSET שלילי שגודלו עולה על האורך הנוכחי של SCALAR: שגיאת זמן ריצה קטלנית (Offset outside string). יש להגביל עם max($offset, -length $buf) כשה־offset מחושב.

  • קריאה קצרה על pipe או socket: אינה שגיאה. read מחזיר פחות תווים מהמבוקש בכל פעם שה־buffer של PerlIO מתרוקן לפני שמגיעים ל־LENGTH. יש ללולל אם צריך את הספירה המלאה.

  • EOF באמצע קריאה: מחזיר את הספירה החלקית. הקריאה הבאה מחזירה 0. אחרי זה, $fh נשאר ב־EOF עד שמבצעים seek או clearerr.

  • קריאה ממטפל מקושר: read מנתב למתודה READ של מחלקת הקישור, האחראית לכבד את LENGTH ו־OFFSET. מחלקות קישור שמתנהגות לא טוב יכולות להפר את החוזה ”להגדיל את SCALAR כך שהתו האחרון שנקרא הוא התו האחרון“.

  • אינטראקציה עם sysread: אסור לערבב אותם על מטפל אחד. read ממלא את ה־buffer של PerlIO בנתחים לפי בחירתו; sysread מתעלם מה־buffer לחלוטין.

  • נתונים בינאריים על מטפל במצב טקסט: במערכות דמויות Unix אין מצב טקסט נבדל, אך שכבת קידוד עדיין משנה בייטים. יש לבצע binmode $fh (או open ..., "<:raw", ...) לפני קריאת נתונים בינאריים.

  • FILEHANDLE כביטוי: bareword או סקלר פשוט בסדר. כל דבר מורכב יותר חייב להיות בסוגריים: read(($handles[$i]), $buf, $len).

הבדלים מהמקור#

תואם במלואו ל־Perl 5.42 במקור.

ראו גם#

  • open - רוכש את מטפל הקובץ וקובע אם read-ים עוקבים נספרים בבייטים או בתווים דרך שכבת הקלט/פלט

  • sysread - המקבילה הלא־buffered, קריאת מערכת read(2) ישירה; יש להשתמש בו לקלט/פלט לא־חוסם או כשקריאה קצרה משמעותית

  • readline / <$fh> - קלט מבוסס רשומה המכבד את $/ במקום ספירת בייט/תו

  • getc - קורא תו יחיד; פחות או יותר read($fh, $c, 1) אך עם דיווח EOF/undef שונה

  • binmode - מסיר או מוסיף שכבות קלט/פלט כך ש־LENGTH הוא חד־משמעית ספירת בייטים או ספירת תווים

  • eof - הדרך הנכונה לבדוק סוף קובץ, במקום לקרוא נתח באורך אפס