I/O · Δεδομένα σταθερού μήκους
sysseek#
Επανατοποθέτηση filehandle σε επίπεδο συστήματος, παρακάμπτοντας την ενταμίευση PerlIO.
Η sysseek μετακινεί το offset περιγραφέα αρχείου πυρήνα του FILEHANDLE σε νέα θέση byte καλώντας απευθείας την υποκείμενη lseek(2). Είναι η συντρόφισσα των sysread και syswrite: οι τρεις σχηματίζουν την οικογένεια μη ενταμιευμένου I/O, που μιλά στον πυρήνα χωρίς να περνά μέσω της στοίβας buffer :perlio ή τύπου stdio της Perl. Χρησιμοποιήστε την sysseek σε handles στα οποία έχετε πρόσβαση με την sys-οικογένεια· χρησιμοποιήστε την seek σε handles με read, readline ή print.
Σύνοψη#
sysseek FILEHANDLE, POSITION, WHENCE
sysseek $fh, 0, 0 # rewind to start
sysseek $fh, 0, 1 # report current position
sysseek $fh, -1024, 2 # 1024 bytes before EOF
Τι επιστρέφεται#
Το νέο απόλυτο offset byte σε επιτυχία, ή undef σε αποτυχία (με την $! ορισμένη). Μια θέση μηδέν επιστρέφεται ως η dualvar συμβολοσειρά "0 but true" ώστε η τιμή να εκτυπώνεται ως 0 σε αριθμητικό περιβάλλον αλλά να παραμένει αληθής σε λογικό περιβάλλον - ένας έλεγχος όπως if (sysseek ...) είναι ασφαλής σε offset μηδέν.
defined(sysseek $fh, $offset, 0)
or die "sysseek to $offset failed: $!";
Επειδή η τιμή επιστροφής φέρει το νέο offset, η sysseek διπλασιάζεται ως πρωτογενής «πού βρίσκομαι» - ο λόγος που το ιδιωματικό systell είναι μία γραμμή:
use Fcntl 'SEEK_CUR';
sub systell { sysseek($_[0], 0, SEEK_CUR) }
Τιμές WHENCE#
Το WHENCE είναι ακέραιος με τρεις ουσιαστικές τιμές. Προτιμήστε τις συμβολικές σταθερές από το Fcntl - καθιστούν επίσης την κλήση φορητή σε πλατφόρμες που δεν χρησιμοποιούν 0 / 1 / 2:
0/SEEK_SET- τοPOSITIONμετριέται από την αρχή του αρχείου. ΤοPOSITIONπρέπει να είναι μη αρνητικό.1/SEEK_CUR- τοPOSITIONπροστίθεται στην τρέχουσα θέση. Αρνητικές τιμές μετακινούν προς τα πίσω, θετικές προς τα εμπρός. Ηsysseek $fh, 0, 1επιστρέφει το τρέχον offset χωρίς να μετακινήσει τον δείκτη.2/SEEK_END- τοPOSITIONπροστίθεται στο offset τέλους αρχείου. ΤοPOSITIONτυπικά είναι μηδέν ή αρνητικό.
use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END);
sysseek $fh, 0, SEEK_SET; # rewind
sysseek $fh, 0, SEEK_END; # move to EOF
sysseek $fh, -$n, SEEK_CUR; # $n bytes back from here
Bytes, όχι χαρακτήρες#
Η sysseek λειτουργεί σε offsets byte, πάντα. Ακόμη και όταν το handle έχει layer προσανατολισμένο σε χαρακτήρες όπως :encoding(UTF-8), το offset που δέχεται και επιστρέφει είναι αδρό πλήθος byte. Αυτό ταιριάζει με την οπτική του πυρήνα αλλά είναι άσχετο στην πράξη: η sysseek προορίζεται για handles που δεν χρησιμοποιούν layers PerlIO, και η ανάμειξή της με layer αποκωδικοποίησης είναι μία από τις παγίδες σύγχυσης που απαριθμούνται παρακάτω.
Αν τα δεδομένα είναι προσανατολισμένα σε χαρακτήρες, χρησιμοποιήστε τις seek και tell στην ενταμιευμένη πλευρά αντί της sysseek.
Μην αναμειγνύετε με ενταμιευμένο I/O#
Η sysseek μιλά απευθείας στον περιγραφέα αρχείου. Οι read, readline, print, write, seek, tell και eof μιλούν στον buffer PerlIO που βρίσκεται μπροστά από τον περιγραφέα. Η θέση του buffer και η θέση του πυρήνα είναι ανεξάρτητες - μια sysseek μετακινεί τον δείκτη του πυρήνα αλλά δεν εκκενώνει ούτε ακυρώνει τον buffer, οπότε η επόμενη ενταμιευμένη ανάγνωση επιστρέφει παλιά bytes πριν από τη sysseek, και η επόμενη ενταμιευμένη εγγραφή προσγειώνεται όπου νόμιζε ο buffer ότι ήταν.
Ο κανόνας είναι απλός: επιλέξτε μία οικογένεια ανά handle.
Καθολική κατάσταση που επηρεάζει#
$!- τίθεται στο μήνυμα σφάλματος συστήματος σε αποτυχία.Σε αντίθεση με την
seek, ηsysseekδεν εκκενώνει ούτε απορρίπτει τον buffer PerlIO και δεν καθαρίζει τη σημαία EOF στο handle. Αυτή η ασυμμετρία είναι η πηγή του κινδύνου «ανάμειξης» παραπάνω και ο λόγος που οι δύο οικογένειες δεν πρέπει να μοιράζονται handle.
Παραδείγματα#
Ανάγνωση τυχαίας πρόσβασης σε εγγραφή σταθερού μήκους. Το αρχείο κρατά εγγραφές 128 byte· μετάβαση κατευθείαν στην εγγραφή 42:
use Fcntl 'SEEK_SET';
sysopen my $fh, $path, O_RDONLY or die $!;
sysseek $fh, 42 * 128, SEEK_SET or die "sysseek: $!";
sysread $fh, my $rec, 128 or die "sysread: $!";
Αναφορά του τρέχοντος offset χωρίς μετακίνηση του δείκτη - το ιδίωμα systell:
use Fcntl 'SEEK_CUR';
my $pos = sysseek $fh, 0, SEEK_CUR;
defined $pos or die "sysseek: $!";
print "at byte $pos\n";
Προσθήκη σε αρχείο που κρατείται ανοιχτό για ανάγνωση-εγγραφή, και έπειτα επαναφορά για επανάληψη από την αρχή:
use Fcntl qw(SEEK_SET SEEK_END);
sysseek $fh, 0, SEEK_END or die $!;
syswrite $fh, $record or die $!;
sysseek $fh, 0, SEEK_SET or die $!;
Το μηδέν παραμένει αληθές - η dualvar σας επιτρέπει να γράψετε τη συνοπτική μορφή χωρίς να αντιμετωπίζετε κατά λάθος μια επιτυχή επαναφορά ως αποτυχία:
if (my $pos = sysseek $fh, 0, 0) {
# entered even when $pos stringifies to "0"
printf "rewound; pos=%d\n", $pos;
}
else {
die "sysseek failed: $!";
}
Μετάβαση πέρα από το τέλος αρχείου για δημιουργία αραιής τρύπας, και έπειτα εγγραφή του δείκτη ουράς:
use Fcntl 'SEEK_SET';
sysseek $fh, 1_000_000, SEEK_SET or die $!;
syswrite $fh, "END" or die $!;
Οριακές περιπτώσεις#
Μη επανατοποθετήσιμα handles: pipes, υποδοχές,
TTYs, και οι περισσότερες ειδικές συσκευές αποτυγχάνουν με την$!ορισμένη σεESPIPE(Illegal seek). Η τιμή επιστροφής είναιundef· ελέγχετε πάντα μεdefined.Μην αναμειγνύετε με ενταμιευμένο I/O στο ίδιο handle. Η
sysseekπαρακάμπτει τον buffer PerlIO· οιread,readline,print,write,seek,tellκαιeofτον χρησιμοποιούν. Η εναλλαγή των δύο οικογενειών παράγει σιωπηρά λάθος αποτελέσματα. Επιλέξτε μία οικογένεια ανά handle και μείνετε σε αυτή.Το μηδέν μετατρέπεται σε συμβολοσειρά ως
"0 but true". Οι λογικοί έλεγχοι λειτουργούν σε offset μηδέν - ηif (sysseek ...)παραμένει αληθής - αλλά οι συγκρίσεις συμβολοσειρών με την κυριολεκτική"0"όχι:my $pos = sysseek $fh, 0, 0; $pos == 0 or die; # true $pos eq "0" and die "nope"; # false - the string is "0 but true"
Χρησιμοποιήστε
definedγια ανίχνευση επιτυχίας/αποτυχίας και αριθμητική σύγκριση για την τιμή offset.Layers κωδικοποίησης: η
sysseekσε handle με layer:encoding(...)είναι σχεδόν πάντα λάθος - το offset byte μπορεί να προσγειωθεί στη μέση codepoint, και η sys-οικογένεια προορίζεται έτσι κι αλλιώς για αδρά bytes. Αν τα δεδομένα χρειάζονται αποκωδικοποίηση, χρησιμοποιήστεseekμε την ενταμιευμένη οικογένεια.Αρνητικά offsets με
SEEK_SET: τοPOSITIONπρέπει να είναι μη αρνητικό όταν τοWHENCEείναι0. Αρνητική τιμή αποτυγχάνει μεEINVAL.Πολύ μεγάλα αρχεία: η
sysseekεπιστρέφει το πλήρες 64-bit offset του πυρήνα· θέσεις πέραν των 2 GiB επιστρέφουν σωστά μέσω επόμενων κλήσεωνsysseekσε όλες τις υποστηριζόμενες 64-bit εκδόσεις.Κλειστό filehandle: επιστρέφει
undefκαι θέτει την$!· υπόuse warningsεκπέμπεται προειδοποίησηsysseek() on closed filehandle.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
seek- το ενταμιευμένο αντίστοιχο· χρησιμοποιήστε την σε handles που προσπελάζονται μέσωread,readlineήprintsysread- η μη ενταμιευμένη ανάγνωση που συνδυάζεται με τηsysseek· και οι δύο παρακάμπτουν το PerlIO και μιλούν απευθείας στον περιγραφέα αρχείουsyswrite- η μη ενταμιευμένη εγγραφή· το τρίτο μέλος της οικογένειας που ανήκει στο ίδιο handle με τηsysseeksysopen- ανοίγει handle σε επίπεδο περιγραφέα, ο συνηθισμένος τρόπος να αποκτήσετε ένα handle που θα οδηγείτε αργότερα με τη sys-οικογένειαtell- ερώτημα τρέχοντος offset στην ενταμιευμένη πλευρά· συνδυάστε την με τηνseek, όχι με τηsysseekFcntl- πηγή των σταθερώνSEEK_SET,SEEK_CUR,SEEK_END