קלט/פלט · נתונים באורך קבוע

syswrite#

כתיבת בתים למטפל קובץ באמצעות קריאת המערכת הגולמית write(2), תוך עקיפת ה־I/O המבוצר של Perl.

syswrite מעביר LENGTH בתים מ־SCALAR ישירות לקרנל באמצעות write(2), תוך דילוג על הבאפר של PerlIO ש־print, printf, ו־write עוברים דרכו. הקרנל עשוי לקבל פחות בתים מהמבוקש - syswrite מחזיר את מה שהוא באמת כתב, וקוד כתוב היטב תמיד בודק. אם LENGTH מושמט, כל ה־SCALAR נכתב. OFFSET אופציונלי מתחיל את הכתיבה במיקום שאינו תחילת המחרוזת.

תקציר#

syswrite FILEHANDLE, SCALAR, LENGTH, OFFSET
syswrite FILEHANDLE, SCALAR, LENGTH
syswrite FILEHANDLE, SCALAR

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

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

my $off = 0;
my $len = length $buf;
while ($off < $len) {
    my $n = syswrite $fh, $buf, $len - $off, $off;
    defined $n or die "write failed: $!";
    $off += $n;
}

החזרה של 0 חוקית ומשמעה ״לא נכתבו בתים בקריאה זו, נסו שוב״ - לא סוף־זרם. undef הוא איתות השגיאה היחיד.

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

  • $! - מוגדר בשגיאה (כל החזרה של undef).

  • אין אינטראקציה עם $,, $\, או $|. syswrite אינו מפרמט, אינו מצרף מפרידי רשומות, ואינו מתחשב בדגל autoflush משום שאין buffer לרוקן - בתים הולכים ישר לקרנל.

  • אין אינטראקציה עם מטפל הקובץ הנבחר מ־select. FILEHANDLE הוא חובה; אין ברירת מחדל.

דוגמאות#

כתיבת מחרוזת מילולית ל־STDOUT, ללא הוספת מפרידים:

syswrite STDOUT, "hello\n";        # 6 bytes written

כתיבת רשומה בגודל קבוע ובדיקת כתיבה קצרה:

my $rec = pack "A8 N", $name, $id;   # 12 bytes
my $n = syswrite $fh, $rec;
defined $n or die "syswrite: $!";
$n == length $rec or die "short write: $n of ${\length $rec}";

כתיבה מאמצע ה־buffer באמצעות OFFSET. שימושי בתוך לולאת ניקוז שבה $off עוקב אחרי כמה התקבל עד כה:

my $buf = "ABCDEFGHIJ";
syswrite $fh, $buf, 4, 3;          # writes "DEFG"

OFFSET שלילי נספר מהסוף:

my $buf = "ABCDEFGHIJ";
syswrite $fh, $buf, 3, -4;         # writes "GHI"

כתיבה לסוקט לא־חוסם וטיפול ב־EAGAIN:

use Errno qw(EAGAIN EWOULDBLOCK);

my $n = syswrite $sock, $buf;
if (!defined $n) {
    if ($! == EAGAIN || $! == EWOULDBLOCK) {
        # kernel buffer full - try again after select()
    } else {
        die "syswrite: $!";
    }
}

מקרי קצה#

  • אל תערבבו עם I/O מבוצר על אותו מטפל. syswrite עוקף את PerlIO, אך print, printf, write, seek, tell, ו־eof כולם עוברים דרך שכבות הבאפרינג :perlio ו־:crlf. שילובם על מטפל אחד מקלקל את סדר הפלט. בחרו מצב אחד לכל מטפל. אם חייבים לערבב, השתמשו בכללי הסימטריה של read / sysread ופעלו במכוון.

  • כתיבות קצרות הן הנורמה. pipe־ים, סוקטים, טרמינלים, ומטפלים לא־חוסמים מקבלים שגרתית פחות בתים ממה שהוצע. אידיום לולאת הניקוז לעיל הוא התבנית הנכונה לכל מטפל שבו כתיבות קצרות חשובות.

  • ערך ההחזרה 0 משמעו שהקרנל קיבל אפס בתים בקריאה זו. זה לא סוף־זרם ולא שגיאה; נסו שוב.

  • אורך גדול מהנתונים הזמינים: אם LENGTH חורג מ־length(SCALAR) - OFFSET, רק הבתים הזמינים נכתבים והספירה הזו מוחזרת.

  • SCALAR ריק: אם ל־SCALAR יש אורך אפס, OFFSET חייב להיות 0. כל ערך אחר מעלה חריגה.

  • שכבות :utf8 ו־:encoding(...) מעלות חריגה. syswrite פועל על בתים, לא תווים, ומסרב לכל מטפל הנושא שכבת קידוד UTF-8. :encoding(...) מוסיף :utf8 באופן מובלע, אז הוא אסור באותה מידה. השתמשו ב־binmode להסרת השכבה, או כתבו דרך print במקום זאת.

  • תווים מעל U+00FF במטפל במצב־בתים גם מעלים חריגה - אין דרך לסריאליז את נקודת קוד גדולה מ־0xFF כבית יחיד. קודדו את המחרוזת מפורשות לפני קריאה ל־syswrite:

    use Encode qw(encode);
    syswrite $fh, encode("UTF-8", $text);
    
  • pipe שבור / סוקט סגור מעלה SIGPIPE. הפעולה כברירת מחדל מסיימת את התהליך. התקינו $SIG{PIPE} = 'IGNORE' (או מטפל) כדי להפוך זאת לשגיאת syswrite רגילה כאשר $! מוגדר ל־EPIPE.

  • מטפל קובץ סגור מחזיר undef כאשר $! מוגדר ל־"Bad file descriptor"; תחת use warnings נפלטת אזהרת syswrite() on closed filehandle.

הבדלים מ־upstream#

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

ראו גם#

  • sysread - המקבילה לקריאה; אותה סמנטיקת עקיפת־buffer ואותה אזהרת קריאה־קצרה

  • sysopen - פתיחת מטפל ברמת open(2) כך ש־syswrite יכול לתקשר איתו ללא שכבות תרגום PerlIO בדרך

  • sysseek - מיקום מחדש של המטפל באמצעות lseek(2), משולב עם syswrite ל־I/O עם גישה אקראית על מטפלים גולמיים

  • print - המקבילה המבוצרת שבדרך כלל רוצים במקום; מתחשב ב־$,, $\, ו־$|

  • binmode - הסרת שכבת :utf8 או :encoding(...) ממטפל כך שניתן להשתמש ב־syswrite עליו

  • $! - בחנו אחרי החזרה של undef כדי להבחין בין EAGAIN לכישלון אמיתי