קלט/פלט

binmode#

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

binmode מגדיר מחדש את FILEHANDLE כך שקריאות וכתיבות עוקבות עוברות דרך מחסנית שכבות PerlIO מסוימת. בצורה החד־ארגומנטית הוא מעביר את המטפל למצב בינארי גולמי (ללא תרגום CRLF, ללא פענוח תווים). בצורה הדו־ארגומנטית הוא דוחף (או, עבור מספר שכבות־מדומות בודדות, מחליף או שולף) את שכבות הקלט/פלט הנקובות אל מחסנית המטפל. יש לקרוא לו אחרי open ולפני כל קלט/פלט על המטפל, פרט ל־:encoding, שניתן להחיל באמצע הזרם.

תקציר#

binmode FILEHANDLE
binmode FILEHANDLE, LAYER

מה מוחזר#

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

binmode $fh, ":encoding($enc)"
    or die "bad encoding '$enc': $!";

אם FILEHANDLE הוא ביטוי ולא bareword או סקלר פשוט, ערכו נלקח כשם המטפל, לפי כללי פתרון מטפלי הקובץ של open ושל print.

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

binmode עצמו אינו קורא משתנים מיוחדים, אך השכבות שהוא מתקין משנות כיצד קלט/פלט מאוחר יותר על המטפל מקיים אינטראקציה אִתם. מחסנית השכבות שולטת בדרך שבה $/ (מפריד רשומות קלט) ו־$\ (מפריד רשומות פלט) מותאמים ונפלטים מול זרם הבתים החיצוני - בפלטפורמות שבהן מצב טקסט מתרגם \n לרצף מרובה־בתים, התרגום מתבצע בתוך השכבה, לא במשתנה.

שכבות PerlIO#

שכבה היא מחרוזת המתחילה ב־: ושמה מסמן מסנן במחסנית PerlIO - ראו PerlIO לקטלוג המלא. ניתן לתת מספר שכבות בקריאה אחת על־ידי שרשורן:

binmode $fh, ":raw:utf8";

הסדר הוא מלמטה למעלה: :raw מוחל ראשון (הקרוב ביותר ל־descriptor הקובץ של מערכת ההפעלה), ואז :utf8 יושב מעליו. קריאות חוצות את המחסנית מלמטה למעלה; כתיבות חוצות אותה מלמעלה למטה.

השכבות הנפוצות בשימוש:

  • :raw - מפשיט את המטפל לקלט/פלט בית־מול־בית. מכבה תרגום CRLF, מסיר כל שכבה של קידוד תווים, ומסמן את המטפל כבתים. למרות טענות מזדמנות הפוכות, :raw אינו פשוט ההפך של :crlf; הוא גם משבית כל שכבה אחרת שתשנה את האופי הבינארי של הזרם. זה מה שהצורה החד־ארגומנטית מתקינה.

  • :crlf - מתרגם רצפי \r\n ל־\n בקלט ו־\n ל־\r\n בפלט. זוהי ברירת המחדל במערכות ממשפחת Windows / DOS עבור מטפלים במצב טקסט; החלתו במפורש מאלצת תרגום CRLF בכל פלטפורמה.

  • :utf8 - מסמן נתונים על המטפל כ־UTF-8. ללא אימות בקלט: בתים מתקבלים ומסומנים כתווים. בפלט, תווים מקודדים לבתי UTF-8. מהיר, אך סומך על המקור.

  • :encoding(NAME) - מפענח בתים לתווים בקלט ומקודד תווים לבתים בפלט, באמצעות הקידוד הנקוב (UTF-8, iso-8859-1, shiftjis, וכו«). קלט שאינו תקף לקידוד מפעיל אזהרה והחלפה. :encoding דוחף באופן מובלע :utf8 מעל עצמו משום ש־Perl עובד פנימית ב־UTF-8. ראו PerlIO::encoding לפרטים ולאפשרויות כיוונון.

  • :bytes - ההפך של :utf8; מסמן נתונים על המטפל כבתים, ומשבית כל דגל של סמנטיקת תווים שהוגדר על־ידי שכבה גבוהה יותר.

שתי שכבות־מדומות שולטות בצורת המחסנית במקום בסינון:

  • :pop - מסיר את השכבה העליונה מהמטפל.

  • :push - בשימוש עם :via(...) כדי לערום מודול שכבה מותאם.

:raw בצורה הדו־ארגומנטית פועל כאיפוס: הוא שולף שכבות עד שהמטפל נמצא במצב המינימלי ביותר שלו, במקום לדחוף שכבה חדשה מעל.

דוגמאות#

הצורה החד־ארגומנטית, לקריאת קובץ בינארי בצורה ניידת:

open my $img, "<", "photo.jpg" or die $!;
binmode $img;
my $bytes = do { local $/; <$img> };

קריאת קובץ טקסט UTF-8 עם אימות:

open my $fh, "<", "notes.txt" or die $!;
binmode $fh, ":encoding(UTF-8)";
while (my $line = <$fh>) {
    # $line contains decoded characters, not bytes
}

כתיבת סופי שורה בסגנון Windows בכל פלטפורמה:

open my $out, ">", "dos.txt" or die $!;
binmode $out, ":crlf";
print $out "one\ntwo\nthree\n";    # written as one\r\ntwo\r\nthree\r\n

הסרת שכבת קידוד שהוחלה קודם וחזרה לבתים:

binmode $fh, ":pop";               # remove topmost layer
binmode $fh, ":raw";               # or: flatten to bare bytes

אימות קידוד שסופק על־ידי המשתמש לפני התחייבות אליו:

my $enc = $ENV{INPUT_ENCODING} // "UTF-8";
binmode $fh, ":encoding($enc)"
    or die "unsupported encoding '$enc': $!";

מקרי קצה#

  • יש לקרוא אחרי open, לפני קלט/פלט. binmode על מטפל שכבר נקרא ממנו או נכתב אליו מפיק תוצאות מוגדרות אך תלויות־מימוש; רוב השכבות שוטפות בופרים ממתינים בעת ההתקנה, מה שעלול לאבד נתונים שחצו את גבול השכבה. :encoding הוא היוצא־מן־הכלל המתועד - ניתן לדחוף אותו באמצע הזרם ללא שטיפה.

  • הצורה החד־ארגומנטית היא :raw, לא ״לא לעשות כלום״. ב־Unix האפקט הנצפה הוא לעתים קרובות אפסי כי מטפלים כבר נמצאים במצב מכוון־בתים, אך ב־Windows הוא משבית את תרגום ה־CRLF. יש לכתוב קוד נייד כאילו binmode $fh תמיד משמעותי.

  • CRLF ב־Windows / DOS. ללא binmode, ה־C runtime בפלטפורמות אלה ממיר \r\n ל־\n בקלט ולהיפך בפלט. עבור פורמטים בינאריים (תמונות, נתונים דחוסים, מבנים מסודרים) זה מקלקל את הזרם בשקט. binmode הוא חובה שם.

  • Ctrl-Z כסוף־קובץ. במערכות ממשפחת Microsoft, מטפלים במצב טקסט מתייחסים אל \cZ (בית 0x1A) כסוף־קובץ. נתונים בינאריים שבמקרה מכילים את הבית הזה ייראו קטומים אלא אם נעשה שימוש ב־binmode.

  • :utf8 הוא מצב־אמון בלבד. מטפל קלט עם :utf8 ללא :encoding(UTF-8) ימסור לכם בשמחה UTF-8 לא תקין מסומן כתווים. יש להשתמש ב־:encoding(UTF-8) כשהמקור אינו אמין.

  • :encoding מושך אִתו את :utf8. אחרי binmode $fh, ":encoding(shiftjis)" למטפל יש גם את :encoding(shiftjis) וגם את :utf8 במחסנית - הצורה הפנימית של perl היא UTF-8 ללא קשר לקידוד החוט.

  • ביטויי מטפל קובץ. binmode $handles[0], ":utf8" עובד; כל ביטוי שמניב ערך מטפל קובץ מתקבל כארגומנט הראשון, ומוערך כדי לנקוב בשם המטפל.

  • משפיע על כל פרימיטיב קלט/פלט על המטפל. מחסנית השכבות שולטת על read, sysread, syswrite, seek, tell, print, ו־readline באותה מידה. בפרט, sysread ו־syswrite על מטפל המסומן ב־:utf8 עדיין עוברים דרך השכבה ועלולים להחזיר תווים חלקיים.

  • אינטראקציה עם הפרגמה open. use open ":encoding(UTF-8)" מתקין סט שכבות ברירת מחדל עבור מטפלים שייפתחו בהמשך. binmode מפורש דורס את ברירת המחדל הזו עבור מטפל נתון.

הבדלים מהמעלה־הזרם#

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

ראו גם#

  • open - יצירת מטפל הקובץ מלכתחילה; מקבל שכבות ישירות במחרוזת המצב (<:encoding(UTF-8)) כדי לדלג על קריאת binmode עוקבת

  • Encode - קידוד ופענוח מחרוזות בזיכרון, ללא תלות במטפל קובץ כלשהו

  • PerlIO - קטלוג מלא של שכבות, כולל שכבות פחות נפוצות כגון :scalar, :via, ו־:mmap

  • read / sysread - פרימיטיבי קלט שסמנטיקת הבתים / התווים שלהם תלויה במחסנית השכבות

  • print / syswrite - פרימיטיבי פלט שהקידוד והתנהגות סופי השורה שלהם תלויים במחסנית השכבות

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

  • $\ - מפריד רשומות פלט, נכתב דרך מחסנית השכבות