I/O

seek#

Επανατοποθετεί ένα filehandle για αναγνώσεις ή εγγραφές τυχαίας πρόσβασης.

Η seek μετακινεί τον δείκτη ανάγνωσης/εγγραφής του FILEHANDLE σε νέο offset bytes, αντικατοπτρίζοντας την κλήση C fseek(3). Μετά από επιτυχημένη seek, η επόμενη read, readline ή print επί του handle ξεκινά από τη νέα θέση. Το POSITION είναι προσημασμένο offset bytes· το 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 σε επιτυχία, ψευδής τιμή σε αποτυχία (με το $! τεθειμένο). Ελέγχετε πάντοτε την τιμή επιστροφής - η μετάβαση πέρα από κοντό αρχείο, σε μη-seekable handle (σωλήνας, υποδοχή, 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

Bytes, όχι χαρακτήρες#

Ακόμη και όταν το handle έχει στρώμα προσανατολισμένο σε χαρακτήρες όπως :encoding(UTF-8), οι seek, tell και η οικογένεια της sysseek λειτουργούν επί offsets bytes. Μια seek σε offset bytes που προσγειώνεται στη μέση πολυβυτικής ακολουθίας θα παραγάγει σφάλματα αποκωδικοποίησης ή χαρακτήρες αντικατάστασης στην επόμενη ανάγνωση.

Αν χρειάζεται να τοποθετηθείτε κατά χαρακτήρες, διαβάστε προς τα εμπρός από γνωστό όριο bytes αντί να προσπαθήσετε να μεταφράσετε καταμετρήσεις χαρακτήρων σε offsets bytes. Οι τιμές της tell είναι ασφαλές να τροφοδοτηθούν πίσω στη seek επειδή παράχθηκαν σε όρια bytes που το στρώμα I/O είχε ήδη διασχίσει καθαρά.

Καθολική κατάσταση που επηρεάζει#

  • $! - τίθεται στο μήνυμα σφάλματος συστήματος σε αποτυχία.

  • Ο ενταμιευτής PerlIO του filehandle απορρίπτεται σε επιτυχία, οπότε όποια δεδομένα έχουν προαναγνωσθεί από την ενταμίευση χάνονται και η επόμενη ανάγνωση τραβά φρέσκα bytes από το υποκείμενο αρχείο.

  • Η σημαία τέλους αρχείου επί του FILEHANDLE καθαρίζεται σε επιτυχία, ακόμη και όταν τα POSITION και WHENCE αφήνουν τη θέση αμετάβλητη.

Παραδείγματα#

Επαναφορά στην αρχή αρχείου πριν την επανανάγνωσή του:

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

Προσθήκη με τοποθέτηση στο τέλος αρχείου, και μετά εγγραφή. Για χρήση μόνο προσθήκης, προτιμήστε άνοιγμα με >> - αυτή η μορφή είναι για handles ήδη ανοιγμένα για ανάγνωση-εγγραφή:

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

Ανάγνωση εγγραφής σταθερού πλάτους κατά δείκτη, όπου κάθε εγγραφή είναι 128 bytes:

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

Οριακές περιπτώσεις#

  • Μη-seekable handles: σωλήνες, υποδοχές, TTYs και οι περισσότερες ειδικές συσκευές επιστρέφουν ψευδές και θέτουν το $! σε ESPIPE (Illegal seek). Ελέγξτε την τιμή επιστροφής· μη θεωρείτε δεδομένο ότι κάθε filehandle είναι seekable.

  • Ανάμειξη αναγνώσεων και εγγραφών στο ίδιο handle σε αρχείο ανοιγμένο με +< ή +> απαιτεί μια seektell, ή ρητή εκκένωση) κατά την αλλαγή κατεύθυνσης. Ένα WHENCE 1 με POSITION 0 είναι ο συνηθισμένος no-op διαχωριστής:

    seek $fh, 0, 1;                   # allowed to switch read <-> write
    
  • Μετάβαση πέρα από το EOF σε αρχείο ανοιγμένο για εγγραφή είναι νόμιμη και δημιουργεί αραιή τρύπα έως το POSITION σε filesystems που υποστηρίζουν τρύπες· η επόμενη εγγραφή γεμίζει μέρος της τρύπας και τα bytes ενδιάμεσα διαβάζονται πίσω ως "\0".

  • Χρήστες sysread / syswrite: μην αναμειγνύετε τη seek με sysread ή syswrite. Η seek λειτουργεί στο στρώμα ενταμιευτή PerlIO· η μη ενταμιευμένη sys-οικογένεια το παρακάμπτει, οπότε οι ενεργές τους θέσεις αποκλίνουν. Χρησιμοποιήστε την sysseek για handles που προσπελάζετε μέσω της sys-οικογένειας.

  • Offsets χαρακτήρων μέσω αριθμητικής: ο πολλαπλασιασμός καταμέτρησης χαρακτήρων με υποτιθέμενο πλάτος κωδικοποίησης είναι εσφαλμένος για UTF-8 και άλλες κωδικοποιήσεις μεταβλητού μήκους. Χρησιμοποιήστε offsets bytes που λαμβάνονται από την tell, ή διαβάστε προς τα εμπρός από γνωστό όριο.

  • Handles καταλόγου: η seek δεν λειτουργεί σε handles καταλόγου. Χρησιμοποιήστε seekdir με θέση από την telldir.

  • Κλειστό filehandle: επιστρέφει ψευδή τιμή και θέτει το $!· υπό use warnings εκπέμπεται προειδοποίηση seek() on closed filehandle.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • tell - διαβάστε το τρέχον offset bytes· η τιμή κάνει πλήρη κύκλο με ασφάλεια μέσω της seek με WHENCE 0

  • sysseek - μη ενταμιευμένη seek για handles που προσπελάζονται μέσω sysread / syswrite· χρησιμοποιήστε αυτή αντί της seek όταν παρακάμπτετε το PerlIO

  • read - ενταμιευμένη ανάγνωση σταθερού μήκους· ο φυσικός συνεργάτης για τοποθέτηση με offset bytes

  • readline - γραμμοκεντρική ανάγνωση· η seek $fh, 0, 1 πριν από επανάληψη είναι το ιδίωμα tail -f

  • eof - δοκιμάστε για τέλος αρχείου· η seek καθαρίζει τη σημαία EOF που μπορεί να έθεσε προηγούμενη ανάγνωση

  • Fcntl - πηγή των σταθερών SEEK_SET, SEEK_CUR, SEEK_END