read#
קורא כמות קבועה של קלט buffered ממטפל קובץ לתוך סקלר.
read מושך עד LENGTH תווים מ־FILEHANDLE ומאחסן אותם ב־SCALAR, ומחזיר כמה נקראו בפועל. הוא עובר דרך מחסנית ה־PerlIO של המטפל ולכן הוא buffered על גבי קריאת מערכת ההפעלה הבסיסית - בניגוד ל־sysread, העוקף את ה־buffer וקורא ל־read(2) ישירות. הארגומנט האופציונלי OFFSET מאפשר לשלב את הנתונים הנכנסים באמצע SCALAR במקום לדרוס אותו.
תקציר#
read FILEHANDLE, SCALAR, LENGTH
read FILEHANDLE, SCALAR, LENGTH, OFFSET
מה מקבלים בחזרה#
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;
}
מצב גלובלי שהוא נוגע בו#
${^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.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- הדרך הנכונה לבדוק סוף קובץ, במקום לקרוא נתח באורך אפס