קלט/פלט

readline#

קורא רשומה אחת או יותר ממטפל קובץ.

readline הוא פרימיטיב הקלט מאחורי אופרטור היהלום <FH>. הוא קורא ממטפל הקובץ ששמו נקוב ב־EXPR (typeglob, הפניית glob, או IO::Handle), משתמש בערך הנוכחי של $/ כדי להחליט היכן מסתיימת רשומה אחת. אם EXPR הושמט, *ARGV נקרא. בהקשר סקלרי הוא מחזיר את הרשומה הבאה; בהקשר רשימה הוא מחזיר את כל הרשומות הנותרות. סוף־קובץ מסומן על־ידי undef (סקלרי) או רשימה ריקה.

תקציר#

my $line  = readline $fh;       # one record, scalar context
my @all   = readline $fh;       # every remaining record
my $line  = <$fh>;              # same as scalar readline $fh
my @all   = <$fh>;              # same as list  readline $fh
readline;                       # reads from *ARGV

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

  • הקשר סקלרי: הרשומה הבאה כמחרוזת, או undef בסוף־קובץ או בשגיאה. הרשומה כוללת את מסיים השורה שלה ($/ הנוכחי) אלא אם לרשומה האחרונה בקובץ חסר אחד. לאחר הערך המוחזר, $. מוגדל - ראו את הסעיף על מצב גלובלי למטה.

  • הקשר רשימה: רשימה של כל הרשומות הנותרות עד סוף־קובץ. רשימה ריקה משמעה שהמטפל כבר היה ב־EOF.

  • מצב slurp בקובץ ריק: כאשר $/ הוא undef וההקשר סקלרי, הקריאה הראשונה על מטפל באפס בייטים מחזירה '' (מחרוזת ריקה, מוגדרת); הקריאה הבאה מחזירה undef. זה מאפשר ל־defined($slurp = readline $fh) להבחין בין קובץ ריק לחסר ללא בדיקת -s נפרדת.

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

  • $/ - מפריד רשומת קלט. שולט על מה שנחשב ״רשומה אחת״. ברירת המחדל היא "\n". ערכים מיוחדים מכוסים תחת מצבי רשומה למטה. ידוע גם בשם $INPUT_RECORD_SEPARATOR או $RS תחת use English.

  • $. - מספר השורה הנוכחי של הקלט מהמטפל האחרון שנקרא. readline מגדיל את $. פעם אחת לכל רשומה שמוחזרת. $. מאופס כאשר המטפל close במפורש, אך לא כאשר *ARGV מתגלגל מקובץ אחד לבא - זה ממשיך לספור על־פני כל הקלט. גם $INPUT_LINE_NUMBER או $NR תחת use English.

  • $_ - הסקלר ברירת המחדל. כאשר קריאת readline (או ה־<FH> המקביל שלה) משמשת כתנאי של לולאת while או for, Perl משייך באופן מובלע את התוצאה ל־$_ ובודק defined, לא אמת. while (<$fh>) { ... } בטוח לכן בשורות המכילות "0" או "".

  • $! - errno. בשגיאת קריאה, readline מחזיר undef (סקלרי) או רשימה חתוכה, וקובע את $! לשגיאת מערכת ההפעלה.

  • @ARGV - כאשר EXPR הושמט (או שהמטפל הוא ARGV), כל סוף־קובץ גורם ל־Perl לעשות open לשם הקובץ הבא מ־@ARGV ולהמשיך לקרוא. @ARGV ריק גורם ל־ARGV לקרוא את STDIN.

מצבי רשומה#

$/ בוחר אחד מארבעה מצבי קריאה:

  • מצב שורה (ברירת מחדל) - $/ הוא מחרוזת לא־ריקה. רשומה מסתיימת בהופעה הבאה של אותה מחרוזת. עם ברירת המחדל "\n", קריאה אחת מחזירה שורה אחת כולל ירידת השורה שלה.

  • מצב פסקה - $/ = "". רשומה מסתיימת ברצף הבא של שתי ירידות שורה רצופות או יותר. שורות ריקות מובילות לפני הפסקה הראשונה מדולגות; השורות הריקות המסיימות נכללות במחרוזת המוחזרת. השתמשו ב־local $/ = "" כדי להגביל את השינוי לבלוק.

  • מצב slurp - $/ = undef. הקריאה הראשונה מחזירה את כל התוכן הנותר של המטפל כמחרוזת אחת; הקריאה הבאה מחזירה undef. בקובץ ריק, ראו את המקרה המיוחד תחת מה מקבלים בחזרה.

  • מצב רשומה־קבועה - $/ = \N (הפניה למספר שלם חיובי) או $/ = \"N". כל קריאה קוראת בדיוק N בייטים, או פחות בסוף־קובץ. שימושי למסגור בינארי. התוצאה עדיין נספרת כרשומה אחת עבור $..

שינויים ל־$/ נכנסים לתוקף בקריאת ה־readline הבאה. תחמו אותם עם local כך שתת־שגרה לא תשנה בשקט את התפיסה של הקורא לגבי ״שורה״.

דוגמאות#

קריאה אידיומטית שורה־אחר־שורה. תנאי ה־while משייך באופן מובלע ל־$_ ובודק defined:

open my $fh, "<", "input.txt" or die "open: $!";
while (<$fh>) {
    chomp;
    print "line $.: $_\n";
}
close $fh;

readline מפורש עם זיהוי שגיאות. יש לבדוק את eof בנפרד מערך ההחזרה, מאחר ששורה לגיטימית יכולה להיות המחרוזת הריקה:

while ( ! eof($fh) ) {
    defined( my $line = readline $fh )
        or die "readline failed: $!";
    # ... process $line ...
}

Slurp של קובץ שלם לתוך סקלר:

my $contents = do {
    local $/;                   # undef - slurp mode
    open my $fh, "<", $path or die "open $path: $!";
    readline $fh;
};

מצב פסקה - קריאת בלוק כותרות הודעה בסגנון RFC-822:

open my $fh, "<", "message.eml" or die $!;
local $/ = "";
my $headers = <$fh>;            # up to the first blank line
my $body    = do { local $/; <$fh> };

מצב רשומה־קבועה - קריאת בלוקים של 512 בייטים מקובץ התקן:

open my $fh, "<:raw", "/dev/sda" or die $!;
local $/ = \512;
while (defined(my $block = <$fh>)) {
    last if length($block) < 512;   # short read at EOF
    # ... process $block ...
}

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

open my $fh, "<", "hosts" or die $!;
my @lines = <$fh>;              # every line, including terminators
chomp @lines;

קריאה מ־*ARGV ללא מטפל מפורש - הניב הקלאסי של מסנן Perl. @ARGV נצרך כרשימת שמות קבצים, או STDIN נקרא אם @ARGV ריק:

while (defined(my $line = readline)) {
    print $line;                # cat(1) in one line
}

מקרי קצה#

  • EOF מול שגיאה: readline סקלרי מחזיר undef לשניהם. קראו ל־eof($fh) או בדקו את $! כדי להבחין ביניהם. בתוך while (<$fh>) הלולאה יוצאת בכל אחד מהם; הוסיפו בדיקת defined מפורשת בתוספת $! כשצריך להבדיל ביניהם.

  • קובץ ללא ירידת שורה נגררת: הרשומה האחרונה מוחזרת ללא מסיים במצב שורה. chomp הוא חסר־פעולה על ערך כזה, וזו ההתנהגות הנכונה.

  • מצב פסקה על קובץ עם שורות ריקות בלבד: מחזיר undef מיד - אין פסקה לא־ריקה להניב.

  • מצב slurp, קובץ ריק: הקריאה הראשונה מחזירה '' (מוגדרת, באורך אפס); השנייה מחזירה undef. אל תסתעפו על אמיתיוּת הקריאה הראשונה.

  • מצב רשומה־קבועה עם קריאה קצרה ב־EOF: מחזיר את הבייטים הנותרים (אולי פחות מ־N), ואז undef בקריאה הבאה. בדקו length אם אתם צריכים בדיוק N.

  • מטפל הקסם ARGV: בקריאה מ־*ARGV, eof() ללא ארגומנט מחזיר אמת רק בסוף ממש של כל קבצי @ARGV, בעוד eof(ARGV) הוא אמת בסוף כל קובץ. אינכם יכולים להשתמש בניב defined(readline) or die "...: $!" מול *ARGV להבחין בין EOF לשגיאה - פתחו כל שם קובץ בעצמכם אם אתם זקוקים לכך.

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

  • שכבות קידוד: readline מחזיר את מה שמחסנית ה־PerlIO של המטפל מפיקה. שכבת :utf8 או :encoding(...) מפענחת בייטים לתווים; מטפל :raw מחזיר בייטים. ערבוב $/ רב־בייטי עם מטפל בייטים יכול לפצל תווים.

  • שינוי $/ באמצע רשומה: רק קריאת ה־readline הבאה צופה במפריד החדש. כל נתון שכבר עבר buffering נסרק מחדש מולו.

  • <FH> מול <$fh> מול <>: כל אלה הם readline מתחת לקלעים. <FH> קורא מה־typeglob FH; <$fh> קורא מהמטפל ב־$fh; <> (או <<>> לטיפול בטוח יותר בשמות קבצים) קורא מ־*ARGV. צורת ה־<pattern> עם כל תוכן אחר היא glob, לא readline - פונקצייה שונה לחלוטין.

  • השמת תנאי לולאה: while (my $line = <$fh>) { ... } בודק defined, לא אמת, רק כי המפענח משכתב אותו. while (($line = <$fh>)) { ... } עם הסוגריים הנוספים אינו מקבל את השכתוב, ויעשה לולאה אינסופית על קלט המכיל "0\n".

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

תאימות מלאה עם Perl 5.42 המקורי.

ראו גם#

  • open - להשגת מטפל הקובץ ש־readline צורך

  • read - קריאת בייטים באורך קבוע המתעלמת מ־$/; השתמשו כשרוצים ספירת בייטים, לא רשומה

  • getc - קריאת תו בודד, מתעלם מ־$/ באותה דרך

  • eof - בדיקה האם ה־readline הבא היה מחזיר undef; מתנהג באופן מיוחד עבור *ARGV

  • $/ - מפריד רשומת קלט; שולט במצבי שורה, פסקה, slurp, ורשומה־קבועה

  • $. - מספר השורה הנוכחי של הקלט, מוגדל על־ידי כל readline מוצלח