2010-04-08 4 views
7

Tôi có một tệp 200kb, những gì tôi sử dụng trong nhiều trang, nhưng trên mỗi trang tôi chỉ cần 1-2 dòng của tệp đó để tôi có thể đọc những dòng này những gì tôi cần nếu tôi biết số dòng?Làm thế nào để tiết kiệm bộ nhớ khi đọc một tệp trong Php?

Ví dụ: nếu tôi chỉ cần dòng thứ 10, tôi không muốn tải trong bộ nhớ tất cả các dòng, chỉ dòng thứ 10.

Xin lỗi vì tiếng anh xấu của tôi!

Trả lời

3

Trừ khi bạn biết độ lệch của đường, bạn sẽ cần đọc mọi dòng đến điểm đó. Bạn chỉ có thể vứt bỏ các dòng cũ (mà bạn không muốn) bằng cách lặp qua tệp với một cái gì đó như fgets(). (CHỈNH SỬA: Thay vì fgets(), tôi sẽ đề xuất @Gordon 's solution)

Có thể giải pháp tốt hơn là sử dụng cơ sở dữ liệu, vì công cụ cơ sở dữ liệu sẽ thực hiện việc lưu trữ chuỗi và cho phép bạn (rất hiệu quả) nhận được một "dòng" nhất định (Nó sẽ không phải là một dòng nhưng là một bản ghi với một số ID, tuy nhiên nó có cùng một giá trị) mà không cần phải đọc các bản ghi trước đó.

+0

Hãy bình luận về downvote – Yacoby

+0

Cơ sở dữ liệu đó sẽ nhanh hơn là chủ quan. Nếu thông tin mà anh ta đang cố gắng truy cập nằm ở đầu tệp, nó sẽ nhanh hơn rất nhiều. Đọc từ cơ sở dữ liệu vẫn đang đọc từ một tệp. Anh ta sẽ được cải thiện từ chỉ mục cơ sở dữ liệu chỉ khi anh ta đang tìm kiếm thứ gì đó từ đầu tệp của mình. Nó cũng phụ thuộc vào những gì ông đang cố gắng để đạt được chính xác. –

+2

Ông không bao giờ nói rằng cơ sở dữ liệu sẽ nhanh hơn. Chỉ có điều đó sẽ tốt hơn. Mối quan tâm của OP có thể được coi là một vấn đề của bộ nhớ hơn là tốc độ. – webbiedave

0

Chỉ cần lặp qua chúng mà không lưu trữ, ví dụ:

$i = 1; 
$file = fopen('file.txt', 'r'); 
while (!feof($file)) { 
    $line = fgets($file); // this gets whole line from the file; 
    if ($i == 10) { 
     break; // break on tenth line 
    } 
    $i ++; 
} 

Ví dụ trên sẽ giữ bộ nhớ cho dòng cuối cùng của tệp, vì vậy đây là cách hiệu quả nhất để thực hiện.

+1

1. bạn quên $ i ++, 2. tại sao không chỉ kiểm tra xem $ i == 10? – zerkms

+0

Bleh, tôi luôn quên đặt gia số. Đối với các == 10 ... một lần nữa, một habbit xấu của phân tích quá nhiều thứ xung quanh với lặp lại .. thực sự xin lỗi, cố định :) – bisko

+0

stream_get_line() là nhanh hơn fgets() –

0

sử dụng fgets(). 10 lần :-) trong trường hợp này, bạn sẽ không lưu trữ tất cả 10 dòng trong bộ nhớ

1
<?php 
    $lines = array(1, 2, 10); 

    $handle = @fopen("/tmp/inputfile.txt", "r"); 
    if ($handle) { 
     $i = 0; 
     while (!feof($handle)) { 
      $line = stream_get_line($handle, 1000000, "\n"); 

      if (in_array($i, $lines)) { 
       echo $line; 
          $line = ''; // Don't forget to clean the buffer! 
      } 

      if ($i > end($lines)) { 
       break; 
      } 

      $i++; 
     } 
     fclose($handle); 
    } 
?> 
19

Hãy thử SplFileObject

echo memory_get_usage(), PHP_EOL;  // 333200 

$file = new SplFileObject('bible.txt'); // 996kb 
$file->seek(5000);      // jump to line 5000 (zero-based) 
echo $file->current(), PHP_EOL;   // output current line 

echo memory_get_usage(), PHP_EOL;  // 342984 vs 3319864 when using file() 

Đối với xuất ra dòng hiện tại, bạn có thể sử dụng current() hoặc chỉ echo $file. Tôi tìm thấy nó rõ ràng hơn để sử dụng phương pháp mặc dù. Bạn cũng có thể sử dụng fgets(), nhưng điều đó sẽ nhận được dòng tiếp theo.

Tất nhiên, bạn chỉ cần ba dòng ở giữa. Tôi đã thêm các cuộc gọi memory_get_usage chỉ để chứng minh phương pháp này không ăn hầu như không có bộ nhớ.

+0

Tuyệt. Tôi đã không nhận thấy rằng 'tìm kiếm' là dòng thay vì dựa trên byte. – Yacoby

+0

+1 Tôi thích mã này bởi vì nó chỉ làm việc ít hơn cho lập trình viên, và nó rõ ràng hơn những gì đang xảy ra (tìm kiếm một dòng nhất định) hơn 'fgets'. – notJim

+0

@Yacoby có 'SplFileInfo :: fseek()' và 'SplFileInfo :: seek()'. Cái thứ hai là dòng dựa, cái còn lại là byte. 'seek()' là một phương thức từ giao diện 'SeekableIterator'. – Gordon

0

Tại sao bạn chỉ cố gắng tải mười dòng đầu tiên? Bạn có biết rằng tải tất cả những dòng đó thực ra là một vấn đề?

Nếu bạn chưa đo, thì bạn không biết rằng đó là vấn đề. Đừng lãng phí thời gian của bạn để tối ưu hóa cho những vấn đề không phải vấn đề. Rất có thể là bất kỳ thay đổi hiệu suất nào bạn có trong khi không tải toàn bộ tệp 200K sẽ là không thể nhận thấy, trừ khi bạn biết thực tế việc tải tệp đó thực sự là một nút cổ chai.

2

Nội dung của tệp có thay đổi không? Nếu nó tĩnh hoặc tương đối tĩnh, bạn có thể xây dựng danh sách các khoảng trống nơi bạn muốn đọc dữ liệu của mình. Ví dụ, nếu những thay đổi tập tin mỗi năm một lần, nhưng bạn đọc nó hàng trăm lần mỗi ngày, sau đó bạn có thể trước khi tính hiệu số của các dòng bạn muốn và nhảy trực tiếp với họ như thế này:

$offsets = array(); 
while ($line = fread($filehandle)) { .... find line 10 .... } 
$offsets[10] = ftell($filehandle); // store line 10's location 
.... find next line 
$offsets[20] = ftell($filehandle); 

và Sớm. Sau đó, bạn có thể trivially nhảy đến vị trí của dòng như thế này:

$fh = fopen('file.txt', 'rb'); 
fseek($fh, $offsets[20]); // jump to line 20 

Nhưng điều này hoàn toàn có thể là quá mức cần thiết.Hãy thử điểm chuẩn các hoạt động - so sánh phải mất bao lâu để thực hiện "đọc 20 dòng" cũ kỹ so với tính toán trước/nhảy.