tell#
מחזיר את מיקום הבית הנוכחי של מטפל קובץ.
tell מדווח היכן הקריאה או הכתיבה הבאה ב־FILEHANDLE תתרחש, נמדדת בבתים מתחילת הקובץ. שלבו אותו עם seek כדי לשמור מיקום עכשיו ולחזור אליו מאוחר יותר. אם FILEHANDLE מושמט, tell מדווח את המיקום של המטפל שממנו נקרא לאחרונה - כולל המטפל המשתמע בתוך לולאות while (<FH>).
תקציר#
tell FILEHANDLE
tell
מה מקבלים בחזרה#
offset של בית שלם אי־שלילי בהצלחה, -1 בשגיאה. הערך מתאים כארגומנט POSITION ל־seek כאשר WHENCE מוגדר ל־0 (seek מוחלט). על pipeים, FIFOים, סוקטים, ולפעמים על הזרמים הסטנדרטיים, למערכת ההפעלה הבסיסית אין מיקום שניתן לחפש בו ו־tell מחזיר -1; $! לא בהכרח מוגדר במקרה זה, אז התייחסו ל־-1 כאות הכישלון הסמכותי.
my $pos = tell $fh;
die "not a seekable handle" if $pos < 0;
# ... read or write ...
seek $fh, $pos, 0; # back to where we were
מצב גלובלי שהוא נוגע בו#
מטפל קובץ אחרון־שנקרא: צורת
tellללא ארגומנט משתמשת במטפל שממנו נקרא לאחרונה בתחום הנוכחי. כלreadline,<FH>, או<>מעדכן את זה. ערבובtellללא ארגומנט עם מספר מטפלים פעילים הוא מקור לתוצאות מפתיעות - שמו את המטפל במפורש כשבספק.$!אינו ערוץ שגיאה אמין כאן. בדקו-1ישירות במקום לבדוק את$!לאחר הקריאה.
בתים, לא תווים#
tell תמיד מחזיר offset של בית, גם כאשר למטפל יש שכבת PerlIO מוכוונת־תווים כגון :encoding(UTF-8) או :utf8. זה מכוון: תרגום של ספירת תווים ל־offset של בית בקידוד ברוחב משתנה היה דורש קריאה מחדש של הקובץ מההתחלה. אותו כלל חל על seek ו־sysseek - כולם מדברים בתים.
תוצאה: על קובץ טקסט UTF-8 בדרך כלל אינכם יכולים להשתמש ב־tell כדי לספור תווים. השתמשו בו רק כדי לסמן מיקום שאתם מתכוונים להזין חזרה לתוך seek.
דוגמאות#
זכירת מיקום, קריאה קדימה, חזרה:
open my $fh, "<", "log.txt" or die $!;
my $mark = tell $fh; # 0
my $first = <$fh>; # read one line
seek $fh, $mark, 0; # rewind to the mark
my $again = <$fh>; # same line again
רישום ה־offset של סוף־הכותרת כדי שקוד מאוחר יותר יוכל לסרוק מחדש את הגוף ללא פירסור מחדש של הכותרת:
while (my $line = <$fh>) {
last if $line =~ /^\r?\n\z/; # blank line ends headers
}
my $body_start = tell $fh;
# ... process body ...
seek $fh, $body_start, 0; # second pass over the body
הצורה ללא־ארגומנט משתמשת במטפל שממנו נקרא לאחרונה. בתוך לולאת while (<>) אותו מטפל הוא ה־ARGV המשתמע:
while (<>) {
print "at ", tell, ": $_"; # offset within the current file
}
tell על pipe מחזיר -1 מכיוון ש־pipeים אינם ניתנים לחיפוש:
open my $ph, "-|", "ls" or die $!;
my $pos = tell $ph; # -1
מטפלי קובץ בתוך ביטויים מורכבים זקוקים לאותה צורת בלוק כמו עם print - tell $handles[0] היא שגיאת תחביר. השתמשו ב:
my @handles = (\*STDIN, $fh);
my $pos = tell { $handles[1] };
מקרי קצה#
מטפל קובץ סגור: מחזיר
-1. תחתuse warningsנפלטת אזהרהtell() on closed filehandle.צורה ללא־ארגומנט, דבר לא נקרא עדיין: מחזיר
-1. ה־״מטפל קובץ אחרון־שנקרא״ משמעותי רק לאחר קריאה ממשית.לאחר
sysread/syswrite/sysseek: אל תשתמשו ב־tellעל מטפל שטיפלתם בו עם משפחת ה־sys*. הפונקציות האלה עוקפות buffering של PerlIO;tellמדווח את המיקום המאוגר, שיהיה שגוי בכמות תוכן ה־buffer. השתמשו ב־sysseekעם whence של1ו־offset של0כתשאול מיקום בטוח ל־sys*.זרמים סטנדרטיים:
tell STDIN,tell STDOUT,tell STDERRעשויים להחזיר-1או offset משמעותי בתלות אם הזרם מגובה על ידי קובץ רגיל (הפניית shell) או טרמינל, pipe, או סוקט.אין
systell: אין פונקציה נפרדת למיקום עוקף־buffering. הניב הוא:my $pos = sysseek $fh, 0, 1;
מצב בינארי לעומת מצב טקסט בפלטפורמות שאינן Linux: pperl מכוון ל־Linux בלבד, אז ה־offsetים של
tellתמיד תואמים לבתי הקובץ הגולמיים. שכבות תרגום CRLF המסבכות אתtellב־Perl של משפחת Windows אינן חלות כאן.מצב append (
>>): לאחרopen my $fh, ">>", ..., ה־tell $fhההתחלתי עשוי לדווח0עד הכתיבה הראשונה, מכיוון שפלטפורמות מסוימות ממקמות את המטפל בסוף־הקובץ רק בכל כתיבה. אל תסתמכו על המיקום ההתחלתי; כתבו פעם אחת, ואזtell.
הבדלים מהמקור#
תאימות מלאה עם Perl 5.42 המקורי.