Hướng dẫn php read large file - php đọc tệp lớn

• Hàm

// formatBytes is taken from the php.net documentation

memory_get_peak_usage();

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}
9 là tốt cho đến khi các tệp văn bản vượt qua 20 mbyte và tốc độ phân tích cú pháp giảm đi rất nhiều.

• Hàm

// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
0 cho kết quả tốt cho đến 40 mbytes và kết quả chấp nhận được cho đến 100 mbytes, nhưng
// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
1 tải toàn bộ tệp vào bộ nhớ, vì vậy nó không phải là scalabile.
// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
1 loads the entire file into memory
, so it's not scalabile.

• Hàm

// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
2 là thảm họa với các tệp văn bản lớn vì hàm này tạo ra một mảng chứa từng dòng văn bản, do đó mảng này được lưu trong bộ nhớ và bộ nhớ được sử dụng thậm chí còn lớn hơn. Trên thực tế, một tệp 200 MB tôi chỉ có thể quản lý để phân tích cú pháp với
// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
3 được đặt ở mức 2 GB không phù hợp với các tệp GB 1+ mà tôi dự định phân tích.
Actually, a 200 MB file I could only manage to parse with
// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
3 set at 2 GB which was inappropriate for the 1+ GB files I intended to parse.

Khi bạn phải phân tích các tệp lớn hơn 1 GB và thời gian phân tích cú pháp vượt quá 15 giây và bạn muốn tránh tải toàn bộ tệp vào bộ nhớ, bạn phải tìm một cách khác.

Giải pháp của tôi là phân tích dữ liệu trong các khối nhỏ tùy ý. Mã là:parse data in arbitrary small chunks. The code is:

$filesize = get_file_size($file);
$fp = @fopen($file, "r");
$chunk_size = (1<<24); // 16MB arbitrary
$position = 0;

// if handle $fp to file was created, go ahead
if ($fp) {
   while(!feof($fp)){
      // move pointer to $position in file
      fseek($fp, $position);

      // take a slice of $chunk_size bytes
      $chunk = fread($fp,$chunk_size);

      // searching the end of last full text line (or get remaining chunk)
      if ( !($last_lf_pos = strrpos($chunk, "\n")) ) $last_lf_pos = mb_strlen($chunk);

      // $buffer will contain full lines of text
      // starting from $position to $last_lf_pos
      $buffer = mb_substr($chunk,0,$last_lf_pos);
      
      ////////////////////////////////////////////////////
      //// ... DO SOMETHING WITH THIS BUFFER HERE ... ////
      ////////////////////////////////////////////////////

      // Move $position
      $position += $last_lf_pos;

      // if remaining is less than $chunk_size, make $chunk_size equal remaining
      if(($position+$chunk_size) > $filesize) $chunk_size = $filesize-$position;
      $buffer = NULL;
   }
   fclose($fp);
}

Bộ nhớ được sử dụng chỉ là

// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
4 và tốc độ thấp hơn một chút so với mức thu được với
// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
0. Tôi nghĩ rằng nhóm PHP nên sử dụng phương pháp của tôi để tối ưu hóa các chức năng phân tích cú pháp của nó.

*) Tìm chức năng

// from memory.php

function formatBytes($bytes, $precision = 2) {
    $units = array("b", "kb", "mb", "gb", "tb");

    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);

    $bytes /= (1 << (10 * $pow));

    return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());
6 ở đây.

    Nó không thường xuyên mà chúng tôi, với tư cách là các nhà phát triển PHP, cần phải lo lắng về quản lý bộ nhớ. Động cơ PHP thực hiện công việc xuất sắc là làm sạch sau chúng tôi và mô hình máy chủ web của bối cảnh thực hiện ngắn hạn có nghĩa là ngay cả mã dốc nhất cũng không có hiệu ứng lâu dài.

    Có những lúc chúng ta có thể cần phải bước ra ngoài ranh giới thoải mái này - như khi chúng ta đang cố gắng chạy trình soạn thảo cho một dự án lớn trên các VP nhỏ nhất mà chúng ta có thể tạo hoặc khi chúng ta cần đọc các tệp lớn trên một máy chủ nhỏ không kém .

    Nó có vấn đề sau này mà chúng tôi sẽ xem xét trong hướng dẫn này.

    Mã cho hướng dẫn này có thể được tìm thấy trên GitHub.

    Hướng dẫn php read large file - php đọc tệp lớn

    Đo lường thành công

    Cách duy nhất để chắc chắn rằng chúng tôi sẽ thực hiện bất kỳ cải tiến nào đối với mã của chúng tôi là đo lường tình huống xấu và sau đó so sánh phép đo đó với một điều khác sau khi chúng tôi áp dụng sửa chữa của chúng tôi. Nói cách khác, trừ khi chúng ta biết một giải pháp của người Viking giúp chúng ta bao nhiêu (nếu có), chúng ta có thể biết liệu đó có thực sự là một giải pháp hay không.

    Có hai số liệu chúng ta có thể quan tâm. Đầu tiên là sử dụng CPU. Quá trình chúng ta muốn làm việc nhanh như thế nào? Thứ hai là sử dụng bộ nhớ. Tập lệnh mất bao nhiêu bộ nhớ để thực thi? Đây thường là tỷ lệ nghịch đảo - có nghĩa là chúng ta có thể giảm tải việc sử dụng bộ nhớ với chi phí sử dụng CPU và ngược lại.

    Trong một mô hình thực thi không đồng bộ (như với các ứng dụng PHP đa quy trình hoặc đa luồng), cả việc sử dụng CPU và bộ nhớ đều là những cân nhắc quan trọng. Trong kiến ​​trúc PHP truyền thống, chúng thường trở thành một vấn đề khi một trong hai đạt đến giới hạn của máy chủ.

    Nó không thực tế để đo sử dụng CPU bên trong PHP. Nếu đó là khu vực bạn muốn tập trung vào, hãy xem xét sử dụng một cái gì đó như

    // from memory.php
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    print formatBytes(memory_get_peak_usage());
    
    7, trên Ubuntu hoặc MacOS. Đối với Windows, hãy xem xét sử dụng hệ thống con Linux, vì vậy bạn có thể sử dụng
    // from memory.php
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    print formatBytes(memory_get_peak_usage());
    
    7 trong Ubuntu.

    Đối với các mục đích của hướng dẫn này, chúng tôi sẽ đo lường mức sử dụng bộ nhớ. Chúng tôi sẽ xem xét số lượng bộ nhớ được sử dụng trong các kịch bản truyền thống của truyền thống. Chúng tôi sẽ thực hiện một vài chiến lược tối ưu hóa và đo lường những chiến lược đó. Cuối cùng, tôi muốn bạn có thể đưa ra một lựa chọn có học thức.

    Các phương pháp chúng tôi sẽ sử dụng để xem bao nhiêu bộ nhớ được sử dụng là:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    

    Chúng tôi sẽ sử dụng các chức năng này ở cuối tập lệnh của chúng tôi, vì vậy chúng tôi có thể xem tập lệnh nào sử dụng bộ nhớ nhiều nhất cùng một lúc.

    Các lựa chọn của chúng tôi là gì?

    Có nhiều cách tiếp cận chúng tôi có thể thực hiện để đọc các tệp một cách hiệu quả. Nhưng cũng có hai kịch bản có khả năng trong đó chúng ta có thể sử dụng chúng. Chúng tôi có thể muốn đọc và xử lý dữ liệu tất cả cùng một lúc, xuất dữ liệu được xử lý hoặc thực hiện các hành động khác dựa trên những gì chúng tôi đọc. Chúng tôi cũng có thể muốn chuyển đổi một luồng dữ liệu mà không bao giờ thực sự cần truy cập vào dữ liệu.

    Hãy để tưởng tượng, trong kịch bản đầu tiên, chúng tôi muốn có thể đọc một tệp và tạo các công việc xử lý xếp hàng riêng biệt cứ sau 10.000 dòng. Chúng tôi cần phải giữ ít nhất 10.000 dòng trong bộ nhớ và chuyển chúng cho người quản lý công việc xếp hàng (bất kỳ hình thức nào có thể lấy).

    Đối với kịch bản thứ hai, hãy để chúng tôi tưởng tượng chúng tôi muốn nén nội dung của phản hồi API đặc biệt lớn. Chúng tôi không quan tâm đến những gì nó nói, nhưng chúng tôi cần chắc chắn rằng nó đã sao lưu ở dạng nén.

    Trong cả hai kịch bản, chúng ta cần đọc các tệp lớn. Đầu tiên, chúng ta cần biết dữ liệu là gì. Trong lần thứ hai, chúng tôi không quan tâm đến dữ liệu là gì. Hãy cùng khám phá các tùy chọn này

    Có nhiều chức năng để làm việc với các tập tin. Hãy để kết hợp một số ít thành một đầu đọc tệp ngây thơ:

    // from memory.php
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    print formatBytes(memory_get_peak_usage());
    
    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    

    Chúng tôi đọc một tệp văn bản chứa các tác phẩm hoàn chỉnh của Shakespeare. Tệp văn bản là khoảng 5,5 MB và việc sử dụng bộ nhớ cực đại là 12,8MB. Bây giờ, hãy để sử dụng một trình tạo để đọc từng dòng:5.5MB, and the peak memory usage is 12.8MB. Now, let’s use a generator to read each line:

    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    

    Tệp văn bản có cùng kích thước, nhưng việc sử dụng bộ nhớ cực đại là 393kb. Điều này không có ý nghĩa gì cho đến khi chúng tôi làm điều gì đó với dữ liệu mà chúng tôi đang đọc. Có lẽ chúng ta có thể chia tài liệu thành các khối bất cứ khi nào chúng ta thấy hai dòng trống. Một cái gì đó như thế này:393KB. This doesn’t mean anything until we do something with the data we’re reading. Perhaps we can split the document into chunks whenever we see two blank lines. Something like this:

    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    

    Có đoán được chúng tôi đang sử dụng bao nhiêu bộ nhớ không? Bạn có làm bạn ngạc nhiên khi biết rằng, mặc dù chúng tôi chia tài liệu văn bản thành 1.216 khối, chúng tôi vẫn chỉ sử dụng bộ nhớ 459kb? Với tính chất của các máy phát điện, bộ nhớ nhất mà chúng tôi sẽ sử dụng là thứ chúng tôi cần lưu trữ đoạn văn bản lớn nhất trong một lần lặp. Trong trường hợp này, khối lớn nhất là 101.985 ký tự.1,216 chunks, we still only use 459KB of memory? Given the nature of generators, the most memory we’ll use is that which we need to store the largest text chunk in an iteration. In this case, the largest chunk is 101,985 characters.

    Tôi đã viết về hiệu suất tăng cường sử dụng máy phát điện và thư viện Iterator Nikita Popov, vì vậy hãy kiểm tra xem bạn có muốn xem thêm không!

    Máy phát điện có các mục đích sử dụng khác, nhưng cái này rất tốt cho việc đọc các tệp lớn. Nếu chúng ta cần làm việc trên dữ liệu, máy phát điện có lẽ là cách tốt nhất.

    Đường ống giữa các tập tin

    Trong các tình huống mà chúng tôi không cần phải hoạt động trên dữ liệu, chúng tôi có thể truyền dữ liệu tệp từ tệp này sang tệp khác. Điều này thường được gọi là đường ống (có lẽ là vì chúng tôi không thấy những gì bên trong một đường ống ngoại trừ ở mỗi đầu, miễn là nó mờ đục, tất nhiên!). Chúng ta có thể đạt được điều này bằng cách sử dụng các phương thức luồng. Trước tiên, chúng ta hãy viết một tập lệnh để chuyển từ tệp này sang tệp khác, để chúng ta có thể đo mức sử dụng bộ nhớ:piping (presumably because we don’t see what’s inside a pipe except at each end … as long as it’s opaque, of course!). We can achieve this by using stream methods. Let’s first write a script to transfer from one file to another, so that we can measure the memory usage:

    // from piping-files-1.php
    
    file_put_contents(
        "piping-files-1.txt", file_get_contents("shakespeare.txt")
    );
    
    require "memory.php";
    

    Không có gì đáng ngạc nhiên, tập lệnh này sử dụng nhiều bộ nhớ hơn một chút để chạy so với tệp văn bản mà nó sao chép. Điều đó bởi vì nó phải đọc (và giữ) nội dung tệp trong bộ nhớ cho đến khi nó được ghi vào tệp mới. Đối với các tập tin nhỏ, điều đó có thể ổn. Khi chúng ta bắt đầu sử dụng các tệp lớn hơn, không có quá nhiều

    Hãy để thử phát trực tuyến (hoặc đường ống) từ tệp này sang tệp khác:

    // from piping-files-2.php
    
    $handle1 = fopen("shakespeare.txt", "r");
    $handle2 = fopen("piping-files-2.txt", "w");
    
    stream_copy_to_stream($handle1, $handle2);
    
    fclose($handle1);
    fclose($handle2);
    
    require "memory.php";
    

    Mã này hơi lạ. Chúng tôi mở tay cầm cho cả hai tệp, chế độ đọc đầu tiên và chế độ thứ hai trong chế độ ghi. Sau đó, chúng tôi sao chép từ thứ nhất vào thứ hai. Chúng tôi kết thúc bằng cách đóng cả hai tệp một lần nữa. Nó có thể làm bạn ngạc nhiên khi biết rằng bộ nhớ được sử dụng là 393kb.393KB.

    Điều đó có vẻ quen thuộc. Có phải là những gì mã máy phát điện được sử dụng để lưu trữ khi đọc từng dòng? Điều đó bởi vì đối số thứ hai cho

    // from memory.php
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    print formatBytes(memory_get_peak_usage());
    
    9 chỉ định số lượng byte của mỗi dòng để đọc (và mặc định là
    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    0 hoặc cho đến khi nó đạt đến một dòng mới).

    Đối số thứ ba với

    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    1 chính xác là cùng một loại tham số (với chính xác cùng một mặc định).
    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    1 đang đọc từ một luồng, một dòng tại một thời điểm và viết nó cho luồng khác. Nó bỏ qua phần mà trình tạo mang lại một giá trị, vì chúng tôi không cần phải làm việc với giá trị đó.

    Đường ống văn bản này không hữu ích cho chúng tôi, vì vậy hãy để Lôi nghĩ về các ví dụ khác có thể. Giả sử chúng tôi muốn xuất ra một hình ảnh từ CDN của chúng tôi, như một loại tuyến ứng dụng được chuyển hướng. Chúng tôi có thể minh họa nó bằng mã giống như sau:

    // from piping-files-3.php
    
    file_put_contents(
        "piping-files-3.jpeg", file_get_contents(
            "https://github.com/assertchris/uploads/raw/master/rick.jpg"
        )
    );
    
    // ...or write this straight to stdout, if we don't need the memory info
    
    require "memory.php";
    

    Hãy tưởng tượng một lộ trình ứng dụng đã đưa chúng ta đến mã này. Nhưng thay vì phục vụ một tệp từ hệ thống tệp cục bộ, chúng tôi muốn lấy nó từ CDN. Chúng tôi có thể thay thế

    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    3 cho một cái gì đó thanh lịch hơn (như guzzle), nhưng dưới mui xe, nó rất giống nhau.

    Việc sử dụng bộ nhớ (cho hình ảnh này) là khoảng 581kb. Bây giờ, làm thế nào về việc chúng ta cố gắng phát trực tuyến điều này thay thế?581KB. Now, how about we try to stream this instead?

    // from piping-files-4.php
    
    $handle1 = fopen(
        "https://github.com/assertchris/uploads/raw/master/rick.jpg", "r"
    );
    
    $handle2 = fopen(
        "piping-files-4.jpeg", "w"
    );
    
    // ...or write this straight to stdout, if we don't need the memory info
    
    stream_copy_to_stream($handle1, $handle2);
    
    fclose($handle1);
    fclose($handle2);
    
    require "memory.php";
    

    Việc sử dụng bộ nhớ ít hơn một chút (ở mức 400kb), nhưng kết quả là như nhau. Nếu chúng tôi không cần thông tin bộ nhớ, chúng tôi cũng có thể in ra đầu ra tiêu chuẩn. Trên thực tế, PHP cung cấp một cách đơn giản để làm điều này:400KB), but the result is the same. If we didn’t need the memory information, we could just as well print to standard output. In fact, PHP provides a simple way to do this:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    0

    Các luồng khác

    Có một vài luồng khác mà chúng tôi có thể ống và/hoặc viết cho và/hoặc đọc từ:

    • // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      4 (chỉ đọc)
    • // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      5 (chỉ viết, như php: // stdout)
    • // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      6 (chỉ đọc) cho phép chúng tôi truy cập vào cơ quan yêu cầu thô
    • // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      7 (chỉ viết) cho phép chúng tôi viết vào bộ đệm đầu ra
    • // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      8 và
      // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      9 (đọc-write) là những nơi chúng ta có thể lưu trữ dữ liệu tạm thời. Sự khác biệt là
      // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      9 sẽ lưu trữ dữ liệu trong hệ thống tệp một khi nó trở nên đủ lớn, trong khi
      // from reading-files-line-by-line-1.php
      
      function readTheFile($path) {
          $lines = [];
          $handle = fopen($path, "r");
      
          while(!feof($handle)) {
              $lines[] = trim(fgets($handle));
          }
      
          fclose($handle);
          return $lines;
      }
      
      readTheFile("shakespeare.txt");
      
      require "memory.php";
      
      8 sẽ tiếp tục lưu trữ trong bộ nhớ cho đến khi hết.

    Bộ lọc

    Có một thủ thuật khác mà chúng tôi có thể sử dụng với các luồng gọi là bộ lọc. Họ là một loại ở giữa các bước, cung cấp một chút kiểm soát đối với dữ liệu luồng mà không phải tiếp xúc với chúng tôi. Hãy tưởng tượng chúng tôi muốn nén

    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    2 của chúng tôi. Chúng tôi có thể sử dụng tiện ích mở rộng ZIP:filters. They’re a kind of in-between step, providing a tiny bit of control over the stream data without exposing it to us. Imagine we wanted to compress our
    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    2. We might use the Zip extension:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    1

    Đây là một chút mã gọn gàng, nhưng nó đồng hồ vào khoảng 10,75MB. Chúng ta có thể làm tốt hơn, với các bộ lọc:10.75MB. We can do better, with filters:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    2

    Ở đây, chúng ta có thể thấy bộ lọc

    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    3, đọc và nén nội dung của tài nguyên. Sau đó, chúng ta có thể gửi dữ liệu nén này vào một tệp khác. Điều này chỉ sử dụng 896kb.896KB.

    Tôi biết đây không phải là định dạng giống nhau, hoặc có những mặt trái để thực hiện kho lưu trữ zip. Mặc dù vậy, bạn phải tự hỏi: Nếu bạn có thể chọn định dạng khác nhau và tiết kiệm 12 lần bộ nhớ, có phải bạn không?

    Để giải nén dữ liệu, chúng ta có thể chạy lại tệp bị lệch thông qua một bộ lọc ZLIB khác:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    3

    Các luồng đã được đề cập rộng rãi trong việc hiểu các luồng trong PHP và sử dụng các luồng PHP một cách hiệu quả. Nếu bạn thích một quan điểm khác, hãy kiểm tra những điều đó!

    Tùy chỉnh luồng

    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    4 và
    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    3 có bộ tùy chọn mặc định của riêng họ, nhưng chúng hoàn toàn có thể tùy chỉnh. Để xác định chúng, chúng ta cần tạo bối cảnh luồng mới:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    4

    Trong ví dụ này, chúng tôi đang cố gắng thực hiện yêu cầu

    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    6 cho API. Điểm cuối API là an toàn, nhưng chúng ta vẫn cần sử dụng thuộc tính bối cảnh
    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    7 (như được sử dụng cho
    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    7 và
    // from reading-files-line-by-line-2.php
    
    function readTheFile($path) {
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            yield trim(fgets($handle));
        }
    
        fclose($handle);
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    9). Chúng tôi đặt một vài tiêu đề và mở một tay cầm tệp cho API. Chúng ta có thể mở tay cầm như chỉ đọc vì bối cảnh sẽ quan tâm đến việc viết.

    Có rất nhiều thứ chúng tôi có thể tùy chỉnh, vì vậy, tốt nhất là kiểm tra tài liệu nếu bạn muốn biết thêm.

    Tạo các giao thức và bộ lọc tùy chỉnh

    Trước khi chúng tôi kết thúc mọi thứ, hãy để nói về việc tạo ra các giao thức tùy chỉnh. Nếu bạn nhìn vào tài liệu, bạn có thể tìm thấy một lớp ví dụ để thực hiện:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    5

    Chúng tôi sẽ không thực hiện một trong những điều này, vì tôi nghĩ rằng nó xứng đáng với hướng dẫn của riêng mình. Có rất nhiều công việc cần phải làm. Nhưng một khi công việc đó hoàn thành, chúng tôi có thể đăng ký trình bao bọc luồng của mình khá dễ dàng:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    6

    Tương tự, nó cũng có thể tạo các bộ lọc luồng tùy chỉnh. Tài liệu có một lớp lọc ví dụ:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    7

    Điều này có thể được đăng ký dễ dàng như vậy:

    // formatBytes is taken from the php.net documentation
    
    memory_get_peak_usage();
    
    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");
    
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
    
        $bytes /= (1 << (10 * $pow));
    
        return round($bytes, $precision) . " " . $units[$pow];
    }
    
    8

    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    
    0 cần khớp với thuộc tính
    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    
    1 của lớp Bộ lọc mới. Nó cũng có thể sử dụng các bộ lọc tùy chỉnh trong chuỗi
    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    
    2. Nó dễ dàng hơn nhiều để xác định các bộ lọc hơn là xác định các giao thức. Một lý do cho điều này là các giao thức cần xử lý các hoạt động thư mục, trong khi các bộ lọc chỉ cần xử lý từng khối dữ liệu.

    Nếu bạn có tính năng, tôi khuyến khích bạn thử nghiệm tạo các giao thức và bộ lọc tùy chỉnh. Nếu bạn có thể áp dụng các bộ lọc cho các hoạt động

    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    1, các ứng dụng của bạn sẽ sử dụng bên cạnh không có bộ nhớ ngay cả khi làm việc với các tệp lớn khó hiểu. Hãy tưởng tượng viết bộ lọc
    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    
    4 hoặc và
    // from reading-files-line-by-line-3.php
    
    $iterator = readTheFile("shakespeare.txt");
    
    $buffer = "";
    
    foreach ($iterator as $iteration) {
        preg_match("/\n{3}/", $buffer, $matches);
    
        if (count($matches)) {
            print ".";
            $buffer = "";
        } else {
            $buffer .= $iteration . PHP_EOL;
        }
    }
    
    require "memory.php";
    
    5.

    Bản tóm tắt

    Mặc dù đây không phải là một vấn đề mà chúng tôi thường gặp phải, nhưng nó rất dễ gây rối khi làm việc với các tệp lớn. Trong các ứng dụng không đồng bộ, nó rất dễ dàng để đưa toàn bộ máy chủ xuống khi chúng tôi không cẩn thận về việc sử dụng bộ nhớ.

    Hướng dẫn này hy vọng đã giới thiệu cho bạn một vài ý tưởng mới (hoặc làm mới bộ nhớ của bạn về chúng), để bạn có thể suy nghĩ thêm về cách đọc và viết các tệp lớn một cách hiệu quả. Khi chúng ta bắt đầu làm quen với các luồng và trình tạo và ngừng sử dụng các hàm như

    // from reading-files-line-by-line-1.php
    
    function readTheFile($path) {
        $lines = [];
        $handle = fopen($path, "r");
    
        while(!feof($handle)) {
            $lines[] = trim(fgets($handle));
        }
    
        fclose($handle);
        return $lines;
    }
    
    readTheFile("shakespeare.txt");
    
    require "memory.php";
    
    3: toàn bộ danh mục lỗi biến mất khỏi các ứng dụng của chúng tôi. Đó có vẻ như là một điều tốt để nhắm đến!