【问题标题】:The correct way to read a data file into an array将数据文件读入数组的正确方法
【发布时间】:2022-02-07 11:41:20
【问题描述】:

我有一个数据文件,每一行都有一个数字,比如

10
20
30
40

如何读取此文件并将数据存储到数组中?

这样我就可以对这个数组进行一些操作了。

【问题讨论】:

  • 这取决于文件的大小!上面的解决方案倾向于使用方便的速记将整个文件复制到内存中,这在许多情况下都可以使用。对于非常大的文件,您可能需要使用流式设计,其中逐行或以卡盘读取文件,处理块,然后从内存中丢弃它们。如果您需要,请参阅reading line by line with perl 上的答案。

标签: perl


【解决方案1】:

仅仅将文件读入一个数组,每个元素一行,是微不足道的:

open my $handle, '<', $path_to_file;
chomp(my @lines = <$handle>);
close $handle;

现在文件的行在数组@lines中。

如果您想确保对 openclose 进行错误处理,请执行以下操作(在下面的片段中,我们也是 open the file in UTF-8 mode):

my $handle;
unless (open $handle, "<:encoding(utf8)", $path_to_file) {
   print STDERR "Could not open file '$path_to_file': $!\n";
   # we return 'undefined', we could also 'die' or 'croak'
   return undef
}
chomp(my @lines = <$handle>);
unless (close $handle) {
   # what does it mean if close yields an error and you are just reading?
   print STDERR "Don't care error while closing '$path_to_file': $!\n";
} 

【讨论】:

  • 您应该通过检查返回值或使用 autodie 来真正处理“打开”失败的情况。为了正确正确,您也应该对“关闭”执行相同的操作。
【解决方案2】:

有最简单的方法,使用File::Slurp模块:

use File::Slurp;
my @lines = read_file("filename", chomp => 1); # will chomp() each line

如果您需要对每一行进行一些验证,您可以在read_file 前面使用grep

例如,过滤只包含整数的行:

my @lines = grep { /^\d+$/ } read_file("filename", chomp => 1);

【讨论】:

  • 并非如此。你忘了chomp。也许这会更好:我的@data = map {chomp $_; $_} read_file("文件名");
  • 一开始没注意,文件的每一行都包含一个数字。因此,最好将数字的正则表达式放入map 而不是chomp。已更新。
  • 第一。如果有人真的需要 chomp() 然后使用选项 read_file("filename", chomp => 1) 而不是 map。第二。我不认为有人真的需要验证。问题不是如何从文件中读取数字。第三。你不检查像 3.1415 这样的数字。向前。您可能想使用 grep { /^\d+/ } 而不是 map。
【解决方案3】:

我喜欢……

@data = `cat /var/tmp/somefile`;

它不像其他的那样迷人,但是,它的工作原理都是一样的。还有……

$todays_data = '/var/tmp/somefile' ;
open INFILE, "$todays_data" ; 
@data = <INFILE> ; 
close INFILE ;

干杯。

【讨论】:

  • 我建议添加chomp@data = grep { chomp; } `cat /var/tmp/somefile`;
  • 这不是一个很好或安全的方法。见perl-begin.org/tutorials/bad-elements/#slurp
  • 它不是特别安全,但如果你不关心它也很好。我通常添加'而不是$?或死亡'以防万一失败'。
【解决方案4】:

Tie::File 是你需要的:

概要

# This file documents Tie::File version 0.98
use Tie::File;

tie @array, 'Tie::File', 'filename' or die ...;

$array[13] = 'blah';     # line 13 of the file is now 'blah'
print $array[42];        # display line 42 of the file

$n_recs = @array;        # how many records are in the file?
$#array -= 2;            # chop two records off the end


for (@array) {
  s/PERL/Perl/g;         # Replace PERL with Perl everywhere in the file
}

# These are just like regular push, pop, unshift, shift, and splice
# Except that they modify the file in the way you would expect

push @array, new recs...;
my $r1 = pop @array;
unshift @array, new recs...;
my $r2 = shift @array;
@old_recs = splice @array, 3, 7, new recs...;

untie @array;            # all finished

【讨论】:

  • 恕我直言 Tie::File 对于读取文件并将内容放入数组这样的简单任务来说太过分了。
  • Tie::File 是多余的,除非你的文件很大。
【解决方案5】:

在数组上下文中使用“菱形运算符”(&lt;&gt;) 从文件句柄中读取所有剩余的未读行:

open(my $AAAA, '<', '/filepath/filename.txt');
my @array = <$AAAA>; # read all lines of the file into an array
close $AAAA;

【讨论】:

  • 请添加一些措辞来解释您的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-25
  • 2012-12-05
  • 2011-05-13
  • 2015-12-02
  • 1970-01-01
相关资源
最近更新 更多