【发布时间】:2012-12-04 17:08:34
【问题描述】:
我正在创建一个子例程:
(1) 解析 CSV 文件;
(2) 并检查该文件中的所有行是否具有预期的列数。如果列数无效,它会发出嘶哑的声音。
当行数从数千到数百万不等时,您认为最有效的方法是什么?
现在,我正在尝试这些实现。
(1) 基本文件解析器
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 0;
while ( my $row = <$in_fh> ) {
my @values = split (q{,}, $row);
++$row_no;
if ( scalar @values < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
close $in_fh
or croak "Cannot close '$file': $OS_ERROR";
(2) 使用 Text::CSV_XS(bind_columns 和 csv->getline)
my $csv = Text::CSV_XS->new () or
croak "Cannot use CSV: " . Text::CSV_XS->error_diag();
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 1;
my @cols = @{$csv->getline($in_fh)};
my $row = {};
$csv->bind_columns (\@{$row}{@cols});
while ($csv->getline ($in_fh)) {
++$row_no;
if ( scalar keys %$row < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
$csv->eof or $csv->error_diag();
close $in_fh or
croak "Cannot close '$file': $OS_ERROR";
(3) 使用 Text::CSV_XS (csv->parse)
my $csv = Text::CSV_XS->new() or
croak "Cannot use CSV: " . Text::CSV_XS->error_diag();
open my $in_fh, '<', $file or
croak "Cannot open '$file': $OS_ERROR";
my $row_no = 0;
while ( <$in_fh> ) {
$csv->parse($_);
++$row_no;
if ( scalar $csv->fields < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
$csv->eof or $csv->error_diag();
close $in_fh or
croak "Cannot close '$file': $OS_ERROR";
(4) 使用 Parse::CSV
use Parse::CSV;
my $simple = Parse::CSV->new(
file => $file
);
my $row_no = 0;
while ( my $array_ref = $simple->fetch ) {
++$row_no;
if ( scalar @$array_ref < $min_cols_no ) {
croak "Invalid file format. File '$file' does not have '$min_cols_no' columns in line '$row_no'.";
}
}
我使用 Benchmark 模块对它们进行了基准测试。
use Benchmark qw(timeit timestr timediff :hireswallclock);
这些是我得到的数字(以秒为单位):
1000 行文件:
实施 1:0.0016
实施 2:0.0025
实施 3:0.0050
实施 4:0.0097
10,000 行文件:
实现 1:0.0204
实施 2:0.0244
实施 3:0.0523
实施 4:0.1050
1,500,000 行文件:
实现 1:1.8697
实施 2:3.1913
实施 3:7.8475
实施 4:15.6274
鉴于这些数字,我认为简单解析器是最快的,但从我从不同来源阅读的内容来看,Text::CSV_XS 应该是最快的。
有人会告诉我这个吗?我使用模块的方式有问题吗?非常感谢您的帮助!
【问题讨论】:
-
为什么速度对您如此重要?你确定这是你的代码的慢点吗?你的程序速度有问题吗?你确定你没有过早优化吗?例如,如果您的程序将 90% 的时间用于写入数据库,而将 10% 的时间用于读取 CSV 文件,那么寻找最快的 CSV 解析器并不是花费时间的最佳方式。
-
'"That's the thing about strings", he said, "you can include commas, periods, and all other kinds of stuff in quotes!"' -
@AndyLester,速度非常重要,因为这是我们现有的几乎所有系统的当前工作流程的附加功能或步骤,如果可能,我们不想增加任何额外的时间。在这种情况下,我真的很想向专家学习,无论我的做法是否正确。我也同意你的看法。优化对数据库的写入确实更有意义,因为大多数时候,瓶颈都发生在那里。仅供参考,我们使用 freebcp 进行插入。再次感谢安迪!
-
@JackManey,我用谷歌搜索了这些陈述的部分内容,但找不到来源。你是在哪里拿到的?也谢谢!
-
@Carlisle:我知道您“如果可能的话,不想增加任何额外的时间”。没有人会。但实际上,这是“任何额外时间”意味着什么的问题。如果您有一些东西在任何更改之前的 37 分钟内运行,并且当您使用 Text::CSV::Whatever 时在 37:02 运行,那么是否有一些东西可以让它在 37:01 运行呢?花费昂贵的程序员时间来解决这个问题值得吗?或者可能使用需要您编写难以理解的代码的模块?当然,如果没有测量,您将无法回答任何问题。