从不同机器上生成的文件读取的不同行为

时间:2013-10-09 23:55:27

标签: perl readfile

我有几百个文本文件夹。每个文件都具有相同的格式,例如名称为ATextFile1.txt的文件读取

ATextFile1.txt  09 Oct 2013
1
2
3
4
...

我有一个简化的Perl脚本,它应该读取文件并在终端窗口中将其打印出来:

#!/usr/bin/Perl

use warnings;
use strict;

my $fileName = shift(@ARGV);

open(my $INFILE, "<:encoding(UTF-8)", $fileName) || die("Cannot open $fileName: $!.\n");

foreach (<$INFILE>){
   print("$_");  # Uses the newline character from the file
}

当我对生成ATextFile1.txt的程序的Windows版本生成的文件使用此脚本时,我的输出完全符合我的期望(作为文本文件的内容),但是,当我对由Mac版本的文件生成程序生成的文件运行此脚本,输出如下所示:

2016tFile1.txt  09 Oct 2013

经过一些测试后,似乎只打印文本的第一行,其中前4个字符被RegEx中表示为/[0-9][0-9]16/的内容覆盖。如果在我的Perl脚本中,我用print("\t$_");替换输出语句,我将以下行打印到STDOUT:

2016    ATextFile1.txt  09 Oct 2013

这些文件中的每一个都可以使用任何标准文本编辑器正常读取,但由于某种原因,我的Perl脚本似乎无法从文件中正确读取和写入。任何帮助将不胜感激(我希望这是一个显而易见的东西,我错过了)。提前谢谢!

1 个答案:

答案 0 :(得分:3)

请注意,如果您要将UTF-8字符打印到STDOUT,则需要使用

binmode STDOUT, ':encoding(utf8)';

预先。

看起来你的Mac文件只有CR作为行结尾。据我所知,最新版本的Macintosh系统使用LF作为行尾(与Linux相同),但Mac OS 9仅使用CR,而Windows使用文件中的两个字符CR LF,PerlIO层将其转换为LF当perl在Windows平台上运行时。

如果文件中没有换行符,那么Perl会将整个文件作为单个记录读取,打印它会将所有行重叠在一起。

只要文件相对较小,使用相同的Perl代码读取任一文件格式的最简单方法是读取整个文件并将其拆分为CR或LF。根据输入文件的来源,其他任何东西都需要不同的代码。

试用此版本的代码。

use strict;
use warnings;

my @contents = do {
  open my $fh, '<:encoding(utf8)', $ARGV[0];
  local $/;
  my $contents = <$fh>;
  split /[\r\n]+/, $contents;
}

print "$_\n" for @contents;

<强>更新

您可能尝试的另一种方法是使用PerlIO::eol模块,该模块提供PerlIO层,在读取记录时将任何行转换为LF。我不确定它与UTF-8有什么关系,但只要你在 encoding层之后添加就应该没问题。

它不是核心模块,因此您可能需要安装它,但之后程序就变成了

use strict;
use warnings;

open my $fh, '<:encoding(UTF-8):eol(LF)', $ARGV[0];
binmode STDOUT, ':encoding(utf8)';

print while <$fh>;

我创建了Windows,Linux和Mac风格的文本文件,这个程序在所有这些文件中运行良好,但是我无法检查作为其编码的一部分的0x0D或0x0A的UTF-8字符是否是通过得当,所以要小心。

更新2

在简要地思考这个之后,当然没有包含CR或LF的UTF-8编码,除了这些字符本身。 ASCII范围之外的所有字符仅包含设置了最高位的字节,因此它们超过0x80且永远不会是0x0D0x0A