Für die Suche nach einem TL; DR, seek
und tell
Arbeit in Bytes. seek
sollte immer in Ordnung sein, wenn sie von tell
Die Dokumentation für Perl seek
Operator zurückgegebenen Werte verwendet, ist eher ungeschickt, aber es hat diese
FILEHANDLE, POSITION suchen, WHENCE
Die Werte für WHENCE sind 0, um die neue Position in Bytes auf POSITION zu setzen ...
und
Notiere die in Bytes: auch wenn die Dateikennung auf Zeichen für den Betrieb gesetzt wurde (zum Beispiel durch die :encoding(utf8)
offene Schicht verwendet wird), sagen() wird Byte-Offsets zurückgeben, keine Zeichenoffsets (weil die Implementierung das seek() und tell() eher langsam macht).
Während dies für das Problem anspielt ist es nicht explizit angegeben
seek
und tell
Verwendung und das Rück Byteversätze innerhalb der Datei, unabhängig von anderer PerlIO Schicht. Das heißt, sie zu ähnlichen Bedingungen zu sysread
arbeiten, die von Perl-Streaming-IO unabhängig ist, obwohl seek
und tell
Respekt Perl Pufferung während sysread
nicht
Es ist nicht nur :utf8
oder :encoding
Schichten, die verwirren, welche Einheiten man erwarten kann: die Die Windows-Ebene :crlf
hat auch einen Effekt, da CR-LF-Paare vor dem Streaming der Eingabe und nach der Ausgabe in LF konvertiert werden. Das verursacht eindeutig eine Diskrepanz für jede Textzeile, aber soweit ich das beurteilen kann, wird dies in Perls Dokumentation nicht erwähnt; Linux und OSX sind die aufdringlichen hässlichen Schwestern von so ziemlich jeder anderen Perl-Plattform
Schauen wir uns Ihren Code an. Ich habe diesen Code ausführen (es auf den Code in Ihrer Frage identisch ist, das verspreche ich) auf meinem Windows 10 und Windows 7-Systeme und gebootet sogar eine VM mit Windows 98 die gleichen
use warnings;
use strict;
open (my $f, '<', 'utf8.txt');
print join("+",PerlIO::get_layers($f)),"\n";
<$f>;
seek($f, -4, 1);
my $xyz = <$f>;
print "$xyz<";
Alle von versuchen, Sie geben diese
was ich erwartet habe, und nicht das, was Sie sagen, dass Sie bekommen. Dies ist von zentraler Bedeutung, da wir reden über Single-Byte-Offsets
Ihre Datei diesen
foo bar baz\r\none two three
enthält die erste Lese uns zu 13 Zeichen vom Anfang nimmt. Perl hat foo bar baz\r\n
gelesen und das CR entfernt, indem es foo bar baz\n
an das Programm übergeben hat, das es verwirft. Fein
Jetzt Sie seek($f, -4, 1)
Der dritte Parameter 1 SEEK_CUR
, was bedeutet, dass Sie die aktuellen Lesezeiger relativ zur aktuellen Position verschieben mögen.
Bitte
Bitte verwenden Sie keine magischen Zahlen. Perl enthüllt Ihnen hier den zugrunde liegenden C file library und Sie müssen dafür verantwortlich sein. 1 als dritten Parameter zu übergeben, ist geheimnisvoll und unverantwortlich.Niemand, der den Code liest, wird wissen, was Sie
Tun Sie dies
use Fcntl ':seek'
geschrieben haben, und dann können Sie verständlichen Code wie diesen schreiben. Wenigstens können die Menschen SEEK_CUR
google während der gleichen Versuch mit 1
schlimmer wäre als fruchtlos
seek($f, -4, SEEK_CUR)
wie es dem Rest von uns eine Chance gibt, den Code
zu verstehen, Sie sind also zu 13 Byte zu suchen, addieren -4, das ist 9. Das ist gerade nach dem b
von baz
, und so bekomme ich az
Das ist, was alle meine Ausführungen Ihres Codes auf all diesen verschiedenen Windows-Maschinen produziert. Ich muss denken, dass das Problem mit Ihrem Code-Steuerelement ist und nicht mit Perl, außer für das Problem mit CRLF
Ich hoffe, dass dies einige Anomalien für Sie erklärt, aber bitte überprüfen Sie Ihren Code und Ihre Ergebnisse.
Fügen Sie den folgenden Test nur nach 'open' in beiden Skripten hinzu:' print join ("+", PerlIO :: get_layers ($ f)), "\ n"; ' – AnFi
Bitte beachten Sie meine geänderte Frage –
Es ist verwandt mit die: crlf-Ebene. Umgehung: 'open (my $ f, '<', 'utf8.txt'); Binmodus ($ f); binmode ($ f, ': encoding (UTF-8)'); ' – ikegami