2014-04-16 9 views
4

에있는 파일에 대한 건물의 인덱스 나는 펄에 현재 새로운 해요, 내가 문제가 우연히했습니다

내 작업, 펄에서 큰 파일의 라인에 액세스 할 수있는 간단한 방법을 만드는 것입니다 가능한 가장 빠른 방법. 5 백만 줄로 구성된 파일을 각 줄마다 줄 번호와 함께 만들었습니다. 그런 다음 주어진 줄의 내용을 인쇄 할 수 있어야하는 주요 프로그램을 만들었습니다. , 나는 두 가지 방법 내가 인터넷에서 찾은 사용하고이 작업을 수행하려면

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 개 정도의 행에서 제대로 작동하지만 이후에 오류가 발생합니다. 난 정말 내가 뭘 잘못하고 있는지 모르겠다.

나는 당신이 각 줄을 구문 분석 할 수있는 기본 루프를 사용할 수 있지만 모든 주어진 시간에 한 줄의 파일을 다시 전체적으로 다시 구문 분석하지 않아도됩니다.

편집 :와 팩에 대한 "N"템플릿을 대체 한 Reading a particular line by line number in a very large file : 내가 여기 약간의 팁을 사용하려고했습니다

그것은 라인 (128)까지, 프로세스 작업을 더하게
my $off_t = $Config{lseeksize} > $Config{ivsize} ? 'F' : 'j'; 

, 여기서 128을 얻지 않고 빈 문자열을 얻습니다. 129에 대해서는 3을 얻습니다. 많은 것을 의미하지는 않습니다.

편집 2 : 기본적으로 내가 읽고있는 파일에 대해 다음 2 줄을 읽을 수있는 메커니즘이 필요합니다. 현재 행의 "head"읽기 (2 행 이후가 아님)

도움 주셔서 감사합니다. 당신이 Windows에서 이런 일을 수행 할 때,

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

지금 : 인덱스 파일에 바이너리 데이터를 쓰기 때문에

+0

Re "test2.pl 줄에서 문자열 $ in uninitialized $ line 사용 46"이 프로그램은 7 줄만 있습니다! 실제로 어떤 결과물을 얻습니까? – ikegami

+1

2GB의 데이터가있는 파일로 스크립트를 실행하는 데 문제가 없습니다. 4GB 이상의 파일과 함께 "N"을 사용하면 문제가됩니다. 그 주위를 피하기 위해 "J"(대문자) 팩을 사용하십시오. – imran

+1

@imran, 그건 틀렸어. '$ Config {lseeksize}> $ Config {ivsize}? 'F': 이미 사용하고있는 'j'가 훨씬 낫다. 1) 이후 'j'는 서명 된 숫자를 취하는 이후의 탐색보다 적합합니다. 2) 당신이 제안하는 것은 32 비트 컴퓨터에서 전혀 도움이되지 않을 것입니다. (물론 'F'도 확실하지 않습니다.) – ikegami

답변

2

, 당신은 Windows의 경우 특히, 바이너리 모드로 파일 핸들을 설정해야 :

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

Perl은 압축 된 문자열의 0x0a를 0x0d0a로 변환합니다. 파일 핸들을 binmode로 설정하면 라인 피드가 캐리지 리턴 라인 피드로 변환되지 않습니다.

+0

내일 올바른 컴퓨터에서 확인해 보겠습니다. 계속 업데이트 될 것입니다. –

+0

매력처럼 작동합니다. 정말 고마워요! 한 특정 파일에 대한 초기화되지 않은 경고 메시지에 약간의 문제가 있지만 결과를 엉망으로 만들지는 않습니다. –