קלט/פלט

truncate#

קיצור (או הארכת) קובץ לאורך בתים מדויק.

truncate מתאים את גודל הקובץ הפתוח על FILEHANDLE, או את הקובץ הנקרא על־ידי EXPR, כך שיהיה בדיוק LENGTH בתים אורך. בתים מעבר ל־LENGTH מושלכים. מיקום הקריאה/כתיבה הנוכחי של הקובץ אינו משתנה - מטפל שיושב מעבר לסוף־הקובץ החדש נשאר שם, וזה כמעט אף פעם לא מה שרוצים, ולכן יש לתכנן seek לפני הכתיבה הבאה.

תקציר#

truncate FILEHANDLE, LENGTH
truncate EXPR, LENGTH

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

1 בהצלחה, undef בכישלון עם $! שנקבע ל־errno הבסיסי. מימוש פלטפורמה חסר מעלה חריגה במקום להחזיר undef; זוהי תכונה של זמן־התקנה, לא משהו להסתעף עליו בזמן ריצה.

truncate $fh, 0
    or die "truncate failed: $!";

צורת מטפל קובץ מול צורת שם קובץ#

שתי צורות, נבחרות לפי מה שכבר ביד:

  • truncate FILEHANDLE, LENGTH - המטפל חייב להיות פתוח לכתיבה (או לקריאה/כתיבה). יש להשתמש בזה כאשר הקורא כבר מחזיק במטפל כתיבה פתוח; זה נמנע מנסיעה הלוך־ושוב טריה של open/close ועובד גם לאחר ש־unlink בוצע על הקובץ.

  • truncate EXPR, LENGTH - EXPR מומר למחרוזת כשם נתיב. הקובץ נפתח, מקוצר ונסגר פנימית. יש להשתמש בזה כאשר יש רק נתיב ואין צורך במטפל לאחר מכן.

שתי הצורות דורשות הרשאת כתיבה על היעד. בצורת מטפל הקובץ, זוהי תכונה של מצב הפתיחה; בצורת שם הנתיב, של הרשאות מערכת הקבצים.

סמנטיקת LENGTH#

  • LENGTH הוא בבתים, לא בתווים. שכבות קידוד על מטפל הקובץ אינן רלוונטיות - ארגומנט האורך הולך ישר למערכת ההפעלה.

  • LENGTH קטן מגודל הקובץ הנוכחי משליך את הזנב.

  • LENGTH שווה לגודל הנוכחי הוא no-op שעדיין מצליח.

  • LENGTH גדול מהגודל הנוכחי מאריך את הקובץ עם חור של בתי אפס במערכות קבצים שתומכות בקבצים sparse, או עם בתי אפס ליטרליים אחרת. perlfunc של upstream מכנה מקרה זה כבלתי־מוגדר; בפועל הוא מתנהג כמו POSIX ftruncate(2) בלינוקס, וזה מה ש־pperl מכוונת אליו.

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

  • $! נקבע בכישלון ל־errno הבסיסי.

דוגמאות#

ריקון קובץ לוג מבלי לסגור את המטפל שאליו שאר התוכנית עדיין כותבת:

open my $log, "+<", "app.log" or die $!;
truncate $log, 0 or die "truncate: $!";
seek $log, 0, 0;                # rewind; see "Position is not reset"

קיצור קובץ לפי שם, ללא מטפל מעורב:

truncate "scratch.dat", 0
    or die "truncate scratch.dat: $!";

סיבוב קובץ buffer מוקצה מראש למטה לחלק שנעשה בו שימוש:

my $used = tell $fh;            # bytes actually written
truncate $fh, $used
    or die "truncate: $!";

הארכת קובץ לגודל קבוע (חור sparse בלינוקס):

open my $fh, ">", "image.raw" or die $!;
truncate $fh, 1024 * 1024 * 1024   # 1 GiB sparse file
    or die "truncate: $!";

מקרי קצה#

  • המיקום אינו מאופס. לאחר truncate $fh, 0, המטפל עדיין זוכר את ה־offset שהיה לו. print $fh ... עוקב ללא seek באמצע עשוי לכתוב מעבר לסוף־הקובץ החדש, ולהותיר חור מלא־אפסים.

  • מטפל קריאה־בלבד: קיצור מטפל שנפתח עם < נכשל עם EBADF / EINVAL בהתאם לפלטפורמה. יש לפתוח עם +< (קריאה/כתיבה) או עם >> בתוספת מצב מתאים אם נחוץ לקצר דרך אותו מטפל ממנו קוראים.

  • LENGTH שלילי: הקרנל דוחה אותו ו־truncate מחזיר undef עם $! שנקבע ל־EINVAL.

  • ספרייה כ־EXPR: נכשל עם EISDIR. truncate הוא פעולת קובץ באופן מובהק.

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

  • LENGTH גדול מהגודל הנוכחי: בלינוקס זה מאריך עם חור sparse; קריאת החור מניבה בתי "\0". perlfunc של upstream מסמן זאת כבלתי־מוגדר, ולכן קוד נייד לא צריך להסתמך על כך.

  • פלטפורמה ללא ftruncate/truncate: מעלה חריגה (The truncate function is unimplemented). לא בעיה בפלטפורמה הנתמכת של pperl (לינוקס), אבל חשוב עבור קוד נייד.

הבדלים מ־upstream#

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

ראו גם#

  • open - מפיק מטפל קובץ בר־כתיבה המתאים לצורת מטפל הקובץ של truncate

  • seek - מיקום מחדש של המטפל לאחר קיצור, לפני כתיבה חוזרת

  • tell - ה־offset הנוכחי, שימושי כארגומנט LENGTH בעת חיתוך ל־״מה שכתבתי עד עכשיו״

  • sysopen - open ברמה נמוכה יותר כשנחוצים דגלים מפורשים (O_TRUNC מקצר בזמן פתיחה; truncate הוא המקבילה שלאחר־מעשה)

  • unlink - יש לפנות לזה במקום כאשר רוצים שהקובץ ייעלם, ולא רק יתרוקן

  • $! - errno בכישלון