קלט/פלט

seek#

מיקום מחדש של מטפל קובץ עבור קריאות או כתיבות בגישה אקראית.

seek מזיז את מצביע הקריאה/כתיבה של FILEHANDLE ל־offset בתים חדש, ומשקף את קריאת C fseek(3). לאחר seek מוצלח, ה־read, readline או print הבא על המטפל מתחיל מהמיקום החדש. POSITION הוא offset בתים עם סימן; WHENCE בוחר את העוגן שממנו הוא נמדד.

תקציר#

seek FILEHANDLE, POSITION, WHENCE
seek $fh, 0, 0             # rewind to start
seek $fh, 0, 1             # no-op: clear EOF, keep position
seek $fh, -1024, 2         # 1024 bytes before EOF

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

1 בהצלחה, ערך שקר בכישלון (עם $! שנקבע). תמיד יש לבדוק את ערך ההחזרה - seek מעבר לקובץ קצר, על מטפל שאינו ניתן לחיפוש (pipe, socket, TTY), או אחרי שגיאת כתיבה - כולם נכשלים כאן ולא בקריאה הבאה.

seek $fh, $offset, 0
    or die "seek to $offset failed: $!";

ערכי WHENCE#

WHENCE הוא מספר שלם עם שלושה ערכים בעלי משמעות. יש להשתמש בקבועים הסימבוליים מ־Fcntl לקריאוּת:

  • 0 / SEEK_SET - POSITION נמדד מתחילת הקובץ. POSITION חייב להיות אי־שלילי.

  • 1 / SEEK_CUR - POSITION מתווסף למיקום הנוכחי. ערכים שליליים נעים אחורה, ערכים חיוביים קדימה. seek $fh, 0, 1 הוא האידיום הקנוני ״לא לנוע לשום מקום, אבל לנקות EOF״.

  • 2 / SEEK_END - POSITION מתווסף ל־offset של סוף־הקובץ. POSITION הוא בדרך־כלל אפס או שלילי.

use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END);

seek $fh, 0,     SEEK_SET;   # rewind
seek $fh, 0,     SEEK_END;   # go to EOF (e.g. to append)
seek $fh, -$n,   SEEK_CUR;   # $n bytes back from here

בתים, לא תווים#

גם כאשר למטפל יש שכבה מוכוונת־תווים כגון :encoding(UTF-8), seek, tell, ומשפחת sysseek פועלים על offsets של בתים. seek ל־offset של בתים שנוחת באמצע רצף רב־בתי יפיק שגיאות פענוח או תווי החלפה בקריאה הבאה.

אם נחוץ למקם לפי תווים, יש לקרוא קדימה מגבול בתים ידוע במקום לנסות לתרגם ספירות תווים ל־offsets של בתים. ערכי tell בטוחים להזין בחזרה ל־seek כי הם יוצרו בגבולות בתים ששכבת ה־I/O כבר חצתה נקי.

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

  • $! - נקבע להודעת שגיאת המערכת בכישלון.

  • ה־buffer של PerlIO של מטפל הקובץ מושלך בהצלחה, ולכן כל נתון שנקרא מראש על־ידי buffering נזרק והקריאה הבאה מושכת בתים טריים מהקובץ הבסיסי.

  • דגל סוף־הקובץ על FILEHANDLE מנוקה בהצלחה, גם כאשר POSITION ו־WHENCE משאירים את המיקום ללא שינוי.

דוגמאות#

החזרה לתחילת קובץ לפני קריאתו מחדש:

seek $fh, 0, 0 or die "rewind failed: $!";
while (my $line = <$fh>) { ... }

הוספה על־ידי מיקום בסוף־הקובץ, ואז כתיבה. לשימוש הוספה־בלבד, יש להעדיף פתיחה עם >> - צורה זו מיועדת למטפלים שכבר פתוחים לקריאה־כתיבה:

seek $fh, 0, 2 or die $!;           # SEEK_END
print $fh "appended line\n";

קריאת רשומה ברוחב קבוע לפי אינדקס, כאשר כל רשומה היא 128 בתים:

my $record = 42;
seek $fh, $record * 128, 0 or die $!;
read $fh, my $buf, 128;

חיקוי של tail -f - ה־seek $fh, 0, 1 מאפס את תנאי ה־EOF כך ש־readline הבא מנסה שוב את הקובץ לנתונים חדשים:

while (1) {
    while (my $line = <$fh>) { print $line }
    sleep 1;
    seek $fh, 0, 1;                 # clear EOF, keep position
}

שמירת מיקום עם tell, קריאה קדימה, ואז שחזור:

my $mark = tell $fh;
my $peek = <$fh>;
seek $fh, $mark, 0 or die $!;       # back to where we were

מקרי קצה#

  • מטפלים שאינם ניתנים לחיפוש: pipes, sockets, TTYs, ורוב ההתקנים המיוחדים מחזירים שקר וקובעים $! ל־ESPIPE (Illegal seek). יש לבדוק את ערך ההחזרה; אין להניח שכל מטפל קובץ ניתן לחיפוש.

  • ערבוב קריאות וכתיבות על אותו מטפל על קובץ שנפתח עם +< או +> דורש seek (או tell, או flush מפורש) בעת החלפת כיוון. WHENCE של 1 עם POSITION של 0 הוא המפריד no-op הרגיל:

    seek $fh, 0, 1;                   # allowed to switch read <-> write
    
  • Seek מעבר ל־EOF על קובץ שנפתח לכתיבה הוא חוקי ויוצר חור sparse עד POSITION במערכות קבצים שתומכות בחורים; הכתיבה הבאה ממלאת חלק מהחור והבתים שביניהם נקראים בחזרה כ־"\0".

  • משתמשי sysread / syswrite: אין לערבב seek עם sysread או syswrite. seek פועל על שכבת ה־buffer של PerlIO; משפחת ה־sys ללא־buffering עוקפת אותה, ולכן המיקומים האפקטיביים שלהם נסחפים זה מזה. יש להשתמש ב־sysseek עבור מטפלים שניגשים אליהם דרך משפחת ה־sys.

  • Offsets של תווים דרך אריתמטיקה: כפל ספירת תווים ברוחב קידוד מונח שגוי עבור UTF-8 וקידודים אחרים ברוחב משתנה. יש להשתמש ב־offsets של בתים שמושגים מ־tell, או לקרוא קדימה מגבול ידוע.

  • מטפלי ספרייה: seek אינו עובד על מטפלי ספרייה. יש להשתמש ב־seekdir עם מיקום מ־telldir.

  • מטפל קובץ סגור: מחזיר ערך שקר וקובע $!; תחת use warnings מנופקת אזהרה seek() on closed filehandle.

הבדלים מ־upstream#

תואם מלא ל־upstream Perl 5.42.

ראו גם#

  • tell - קריאת ה־offset הנוכחי של בתים; הערך עובר הלוך־ושוב בבטחה דרך seek עם WHENCE 0

  • sysseek - seek ללא buffering עבור מטפלים שניגשים אליהם דרך sysread / syswrite; להשתמש בו במקום seek בעת עקיפת PerlIO

  • read - קריאה באורך קבוע עם buffering; השותף הטבעי למיקום לפי offset של בתים

  • readline - קריאה מוכוונת־שורה; seek $fh, 0, 1 לפני ניסיון חוזר הוא האידיום של tail -f

  • eof - בדיקה לסוף־הקובץ; seek מנקה את דגל ה־EOF שקריאה קודמת אולי קבעה

  • Fcntl - מקור הקבועים SEEK_SET, SEEK_CUR, SEEK_END