在Perl中检查CSV文件的正确性

时间:2013-11-20 15:53:41

标签: perl parsing csv

我有一个读取CSV文件的进程,我想在开始解析之前确保它是正确的。

我得到一个文件名,检查它是否存在,然后检查其完整性。如果它不存在或没有正确的CSV文件,那么我尝试前一天的文件

有没有办法检查文件是否是正确的CSV文件?我正在使用Text::CSV_XS来解析它。


谷歌搜索了一下我在Text::CSV_XS Git repo上找到了this csv-check example code。它看起来像我可以使用的东西。

3 个答案:

答案 0 :(得分:3)

无论如何都无法读取和解析中的每个记录,无法测试文件的有效性。

我建议的方法是处理您找到的每个文件,在内存中构建您希望在数据库中结束的数据,如果您发现错误,则只需丢弃它并尝试使用下一个文件。

一旦到达文件的末尾并知道它是有效且完整的,那么您只需将准备好的数据保存到数据库,然后继续下一个文件。

这将正常工作,除非您的CSV文件巨大并且太大而无法合理地放入内存中。在这种情况下,你应该只需要两次通过。

答案 1 :(得分:3)

正如其他人所说,您必须解析整个文件以确定它是否有效。你也可以一石二鸟,同时进行数据处理和错误检查。

检测错误

getline()在达到EOF时返回undef,或者无法解析一行。您可以使用它来解析文件,如果有任何解析错误则暂停:

while ( my $row = $csv->getline($io) ) {
    # Process row
}
$csv->eof or do_something();

你也可以

use autodie;

或将Text::CSV_XS->new()中的auto_diag选项设置为die错误:

$csv = Text::CSV_XS->new({ auto_diag => 2 });

您可以通过将解析代码包装在eval块中来处理错误。此方法将在error_diag()之前自动调用die,将错误打印到stderr;这可能不是你想要的。

还原无效文件

如果检测到错误,如何“恢复”对先前行所做的处理?如果您的数据库引擎支持它们,则一种可能性是数据库事务。开始处理文件时,启动事务。如果出现解析错误,只需回滚事务并转到下一个文件;否则,提交交易。

顺便说一句,我还没有看到你的代码插入数据库记录,所以我不确定这是否适用,但是对每一行都有一个单独的insert语句效率不高。相反,请考虑在解析文件时构造复合插入语句;或者,对于非常大的文件,让数据库使用MySQL LOAD DATA INFILE之类的东西进行解析(只是一个例子,因为我不知道你正在使用什么DBMS)。

要使用复合插入,请在内存中构建查询语句,如Borodin suggested。如果到达文件的末尾而没有任何解析错误,请执行语句;否则,扔掉它然后转到下一个文件。

对于非常大的文件,让数据库进行解析可能是最快的,尤其是在插入数据之前进行最少的处理时。例如,MySQL的LOAD DATA INFILE将在检测到数据解释或重复键错误时停止。如果将语句包装在事务中,则可以在出现错误时回滚并尝试加载下一个文件。这种方法的优点是加载有效文件的速度非常快,比必须先用Perl解析它们要快得多。

答案 2 :(得分:2)

这就是我所做的,如果文件正常则sub返回1,如果不正常则返回0:

sub CheckCSVFile {
    my ($fileName) =@_;
    my $csv = Text::CSV_XS->new();
    open my $in_fh, '<:encoding(ISO-8859-1)', $fileName;

    while ( <$in_fh> ) {
        my $status = $csv->parse($_);

        if  ($status != 1){
            return $status;
        }
    }

    $csv->eof;
    close $in_fh;
    return 1;
}

我事先检查文件是否存在,所以不应该出错。如果出现问题我也不想退出。这有点粗糙,但对我有用。