Probleme mit CRLF unter Windows

22/01/2009 - 13:11 von Alexander Dahl | Report spam
Hallo zusammen,

ich hab ein Skript geschrieben, das plattformunabhàngig laufen soll
und dabei Text in eine neue Datei schreibt. Dies soll es mit den
plattformspezifischen Zeilentrennern tun, d.h. unter Linux soll ein LF
am Ende stehen und unter Windows ein CRLF. Die Probanden sind ein
Debian Lenny und ein Windows XP mit ActivePerl, beides in Version
5.10. Ich hab das große Skript mal auf ein kleineres Beispiel
eingedampft, das den Effekt zeigt:

{{{
#!/usr/bin/perl -w
use strict;
use warnings;

use Data::Dumper;
use File::Spec::Functions qw( curdir );
use File::Temp qw( tempfile );

my $FH;
my $filename;

( $FH, $filename ) = tempfile( DIR => curdir );
print "Layers after opening temp file:";
print Dumper( PerlIO::get_layers($FH) );

binmode $FH, ':encoding(iso-8859-15)';
print "Layers after resetting binmode:";
print Dumper( PerlIO::get_layers($FH) );

print $FH 'Line with trailing ' . "";
print $FH 'Line with trailing ' . "";

close $FH;
}}}

Die Ausgabe unter Windows:
{{{
Layers after opening temp file:
$VAR1 = 'unix';
$VAR2 = 'crlf';
Layers after resetting binmode:
$VAR1 = 'unix';
$VAR2 = 'crlf';
$VAR3 = 'encoding(iso-8859-15)';
$VAR4 = 'utf8';
}}}

Die Ausgabe unter Linux:
{{{
Layers after opening temp file:
$VAR1 = 'unix';
$VAR2 = 'perlio';
Layers after resetting binmode:
$VAR1 = 'unix';
$VAR2 = 'perlio';
$VAR3 = 'encoding(iso-8859-15)';
$VAR4 = 'utf8';
}}}

Das Problem besteht nun darin, dass in der Datei, die unter Windows
geschrieben wird keine CRLF an den Zeilenenden stehen sondern nur LF.
Unter Linux sieht das so aus, wie ich es erwarte, nàmlich mit LF am
Ende.

Ich könnte jetzt beim Setzen des Encoding noch den Layer ':crlf' mit
dazu nehmen, das funktioniert auch, allerdings so gut, dass unter
Linux auch CRLF an die Zeilenenden wandern und das will ich ja gerade
nicht. Die Statusausgaben dieser Variante unter Windows sehen dann
übrigens genauso aus, als wenn ich ':crlf' nicht explizit mitgebe.

Warum schreibt Perl unter Windows keine CRLF, obwohl das entsprechende
Layer augenscheinlich aktiviert ist? Wieso sieht die Ausgabe der
aktiven Layer über PerlIO::get_layers nach dem expliziten Setzen von
':crlf' genauso aus wie vorher, aber plötzlich funktioniert es doch?
Wie kann ich das Problem lösen ohne extra Erkennungsroutinen für das
aktuell laufende System mit in das Skript einzubauen?

Gruß
Alex
 

Lesen sie die antworten

#1 ekkehard.horner
22/01/2009 - 15:09 | Warnen spam
Alexander Dahl schrieb:
Hallo zusammen,

ich hab ein Skript geschrieben, das plattformunabhàngig laufen soll
und dabei Text in eine neue Datei schreibt. Dies soll es mit den
plattformspezifischen Zeilentrennern tun, d.h. unter Linux soll ein LF
am Ende stehen und unter Windows ein CRLF. Die Probanden sind ein
Debian Lenny und ein Windows XP mit ActivePerl, beides in Version
5.10. Ich hab das große Skript mal auf ein kleineres Beispiel
eingedampft, das den Effekt zeigt:


[...]

Durch binmode wird die LF => CRLF Uebersetzung abgeschaltet:

... In other
systems like OS/2, DOS and the various flavors of MS-Windows
your program sees a "" as a simple "\cJ", but what's stored in
text files are the two characters "\cM\cJ". That means that, if
you don't use binmode() on these systems, "\cM\cJ" sequences on
disk will be converted to "" on input, and any "" in your
program will be converted back to "\cM\cJ" on output. This is
what you want for text files, but it can be disastrous for
binary files.

Das Problem besteht nun darin, dass in der Datei, die unter Windows
geschrieben wird keine CRLF an den Zeilenenden stehen sondern nur LF.
Unter Linux sieht das so aus, wie ich es erwarte, nàmlich mit LF am
Ende.



Das war also zu erwarten. Was ich jedenfalls nicht erwartet hatte, ist
dass beide durch

( $FH, $filename ) = tempfile( DIR => curdir );
print $FH "";
close $FH;

( $FH, $filename ) = tempfile( DIR => curdir );
binmode $FH;
print $FH "";
close $FH;

unter Windows geschriebenen Dateien nur LF enthalten. Ich vermute einen
Bug oder ein Feature in File::Temp. Jedenfalls verhaelt sich Code wie:

$filename = "1.txt";
open $FH, ">", $filename;
print $FH "";
close $FH;

$filename = "2.txt";
open $FH, ">", $filename;
binmode $FH;
print $FH "";
close $FH;

anstaendig:

dir ?.txt
...
22.01.2009 14:53 2 1.txt
22.01.2009 14:53 1 2.txt

Ähnliche fragen