2014-04-16 74 views
4

我目前新Perl和我在一个偶然的问题:大厦索引文件在Perl

我的任务是创建一个简单的方法来访问线Perl中的大文件时,最快的方式可能。 我创建了一个由500万行组成的文件,在每一行上都有该行的编号。 我已经创建了我的主程序,它需要能够打印给定行的任何内容。 要做到这一点,我使用两种方法,我发现在互联网上:

use Config qw(%Config); 

my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j'; 
my $file = "testfile.err"; 
open(FILE, "< $file")   or die "Can't open $file for reading: $!\n"; 
open(INDEX, "+>$file.idx") 
     or die "Can't open $file.idx for read/write: $!\n"; 
build_index(*FILE, *INDEX); 
my $line = line_with_index(*FILE, *INDEX, 129); 
print "$line"; 

sub build_index { 
    my $data_file = shift; 
    my $index_file = shift; 
    my $offset  = 0; 

    while (<$data_file>) { 
     print $index_file pack($off_t, $offset); 
     $offset = tell($data_file); 
    } 
} 

sub line_with_index { 
    my $data_file = shift; 
    my $index_file = shift; 
    my $line_number = shift; 

    my $size;    # size of an index entry 
    my $i_offset;   # offset into the index of the entry 
    my $entry;    # index entry 
    my $d_offset;   # offset into the data file 

    $size = length(pack($off_t, 0)); 
    $i_offset = $size * ($line_number-1); 
    seek($index_file, $i_offset, 0) or return; 
    read($index_file, $entry, $size); 
    $d_offset = unpack($off_t, $entry); 
    seek($data_file, $d_offset, 0); 
    return scalar(<$data_file>); 
} 

这些方法有时工作,我得到一个值一次十个尝试在不同的设定值,但大部分的我得到“在test2.pl第10行的字符串中使用了未初始化的值$ line”(在文件中查找第566行时)或未使用正确的数值。而且,索引似乎在前200行左右工作得很好,但之后我得到了错误。我真的不知道我在做什么错..

我知道你可以使用一个基本的循环,将解析每一行,但我真的需要一种方式访问​​,在任何给定的时间,一行文件,而不用重新解析它。

编辑:Reading a particular line by line number in a very large file 我把它换成了“N”模板包带:我用在这里找到一点小费试图

my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j'; 

这使得程序更好地工作,直到线128,而不是获得128,我得到一个空白字符串。对于129,我得到3,这并不意味着太多..

Edit2:基本上我需要的是一种机制,使我能够读取下一个2行例如已经被读取的文件,同时保持在当前行读取“头部”(而不是2行后)。

感谢您的帮助!

+0

Re“用于test2.pl第46行的字符串中的未初始化值$ line”该程序只有7行!你实际得到了什么输出? – ikegami

+1

我没有问题与一个文件有2GB的数据运行您的脚本。对超过4GB的文件使用包“N”将是一个问题。使用包装“J”(大写)来解决这个问题。 – imran

+1

@imran,这是错误的。 '$ Config {lseeksize}> $ Config {ivsize}? 'F':他已经使用的'j''好多了。 1)'j'更自适,因为它自带有一个带符号的数字。 2)你的建议在32位机器上完全没有帮助(尽管我不确定'F'会不会) – ikegami

回答

2

既然你正在写的二进制数据索引文件,你需要设置文件句柄为二进制模式,特别是如果你在Windows中:

open(INDEX, "+>$file.idx") 
    or die "Can't open $file.idx for read/write: $!\n"; 
binmode(INDEX); 

现在,当你在Windows中执行这样的事情:

print $index_file pack("j", $offset); 

Perl会将打包字符串中的任何0x0a转换为0x0d0a's。将文件句柄设置为binmode将确保换行符不会转换为回车换行符。

+0

我明天会在右边的电脑上查看,看起来好像是一个很好的照片!会让你更新。 –

+0

工程就像一个魅力,非常感谢!对于一个特定文件,未初始化的警告消息仍然存在一个小问题,但它不会弄乱结果。 –