2011-12-18 10 views
7

Có cách nào nhanh và hiệu quả để đọc các dòng tệp lớn cụ thể mà không tải nó vào bộ nhớ không?Đọc một dòng cụ thể từ tệp lớn trong Perl

Tôi đã viết một kịch bản perl, chạy nhiều dĩa và tôi muốn họ đọc các dòng cụ thể từ một tệp.

Tại thời điểm Im sử dụng một lệnh bên ngoài:

sub getFileLine { 
    my ($filePath, $lineWanted) = @_; 
    $SIG{PIPE} = '_IGNORE_'; 
    open(my $fh, '-|:utf8', "tail -q -n +$lineWanted \"$filePath\" | head -n 1"); 
    my $line = <$fh>; 
    close $fh; 
    chomp($line); 
    return $line; 
} 

nhanh của nó và nó hoạt động - nhưng có lẽ đó là một "Perl-ish" cách hơn, nhanh và bộ nhớ hiệu quả như thế này? Như bạn đã biết, việc tạo một quy trình rẽ nhánh trong Perl sẽ sao chép bộ nhớ chính - vì vậy nếu quá trình chính đang sử dụng 10MB, ngã ba sẽ sử dụng ít nhất là nhiều.

Mục tiêu của tôi là giữ quy trình ngã ba (vì vậy quá trình chính cho đến khi chạy dĩa cũng) sử dụng bộ nhớ càng thấp càng tốt. Đó là lý do tại sao tôi không muốn tải toàn bộ tập tin vào bộ nhớ.

+2

btw, đó là 'IGNORE', không phải' _IGNORE_'. – ikegami

Trả lời

16

Trước khi bạn tiếp tục, điều quan trọng là phải hiểu cách hoạt động của fork. Khi bạn fork một quá trình, HĐH sử dụng các ngữ nghĩa copy-on-write để chia sẻ phần lớn bộ nhớ của quy trình cha và con; chỉ số lượng bộ nhớ khác nhau giữa cha mẹ và con cần được phân bổ riêng.

Đối với đọc một dòng duy nhất của một tập tin trong Perl, đây là một cách đơn giản:

open my $fh, '<', $filePath or die "$filePath: $!"; 
my $line; 
while(<$fh>) { 
    if($. == $lineWanted) { 
     $line = $_; 
     last; 
    } 
} 

này sử dụng $. biến đặc biệt mà giữ số dòng của filehandle hiện hành.

4

Hãy xem Tie::File mô-đun chính.

+0

Tôi nghĩ 'Tie :: File' là bộ nhớ không hiệu quả. Không phải OP yêu cầu sử dụng bộ nhớ thấp? – Zaid

+0

@ Zaid nó thực sự hợp lý bộ nhớ hiệu quả; nó không lưu toàn bộ nội dung của tập tin trong bộ nhớ, chỉ có một danh sách * offset * của mỗi dòng. Nó không phải là miễn phí (thậm chí chỉ là vô hướng để giữ mỗi bù đắp mất một số không gian trên mỗi dòng), nhưng nó thường là tốt, đủ để xử lý các tập tin đa trăm megabyte một cách dễ dàng. – hobbs

+0

@hobbs: Yup. Tôi đã xem xét các tài liệu kể từ đó (bình luận là khá cũ bây giờ), và nó làm cho nó khá rõ ràng rằng nó không phải là một con heo bộ nhớ. – Zaid

0

Bạn không cần phải ngã ba. Như bạn có thể tưởng tượng, việc đọc một dòng cụ thể từ một tệp là một hoạt động đủ phổ biến mà một trong các mô-đun 20k trên CPAN đã làm điều đó rồi.

File::ReadBackwards là bộ nhớ hiệu quả và nhanh chóng.