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בסוף קובץ.
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עםsysreadread- המקבילה הב־buffer; יש להשתמש בה עבור קלט מוכוון־שורות ומוכוון־רשומות, לא עבור סוקטים או קריאות חלקיותbinmode- להסיר:utf8או:crlfממטפל לפני שימוש ב־sysread$!- ערך ה־errnoלאחרsysreadשנכשל, כוללEINTR,EAGAIN, ו־EWOULDBLOCK