Saya baru saja mengetahui bahwa skrip saya memberikan kesalahan fatal:
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 440 bytes) in C:\process_txt.php on line 109
Baris itu adalah ini:
$lines = count(file($path)) - 1;
Jadi saya pikir itu mengalami kesulitan memuat file ke dalam memeory dan menghitung jumlah baris, adakah cara yang lebih efisien untuk melakukan ini tanpa masalah memori?
File teks yang saya butuhkan untuk menghitung jumlah baris dari 2MB hingga 500MB. Mungkin terkadang Gig.
Terima kasih semua atas bantuannya.
\n
) yang diurai pada mesin windows (PHP_EOL == '\r\n'
)fgets($handle, 1);
?substr_count()
, tetapi jika Anda memiliki antrean yang sangat panjang, Anda perlu memanggilwhile()
danfgets()
banyak lagi yang menyebabkan kerugian. Jangan lupa:fgets()
tidak dibaca baris demi baris. Ini hanya membaca jumlah karakter yang Anda tentukan$length
dan jika berisi pemutusan baris ia berhenti apa pun yang$length
telah ditetapkan.while(!feof())
akan menyebabkan Anda membaca baris tambahan, karena indikator EOF tidak disetel sampai Anda mencoba membaca di akhir file.$line = fgets($handle);
bisa sajafgets($handle);
karena$line
tidak pernah digunakan.Menggunakan loop
fgets()
panggilan adalah solusi yang bagus dan paling mudah untuk ditulis, namun:meskipun secara internal file dibaca menggunakan buffer sebesar 8192 byte, kode Anda masih harus memanggil fungsi tersebut untuk setiap baris.
secara teknis mungkin satu baris mungkin lebih besar dari memori yang tersedia jika Anda membaca file biner.
Kode ini membaca file dalam potongan masing-masing 8kB dan kemudian menghitung jumlah baris baru dalam potongan itu.
function getLines($file) { $f = fopen($file, 'rb'); $lines = 0; while (!feof($f)) { $lines += substr_count(fread($f, 8192), "\n"); } fclose($f); return $lines; }
Jika rata-rata panjang setiap baris paling banyak 4kB, Anda sudah mulai menghemat pemanggilan fungsi, dan itu dapat bertambah saat Anda memproses file besar.
Tolok ukur
Saya menjalankan tes dengan file 1GB; berikut hasilnya:
Waktu diukur dalam detik waktu nyata, lihat sini apa arti sebenarnya
sumber
Solusi Objek Berorientasi Sederhana
$file = new \SplFileObject('file.extension'); while($file->valid()) $file->fgets(); var_dump($file->key());
Memperbarui
Cara lain untuk membuatnya adalah dengan metode
PHP_INT_MAX
inSplFileObject::seek
.$file = new \SplFileObject('file.extension', 'r'); $file->seek(PHP_INT_MAX); echo $file->key() + 1;
sumber
wc -l
(karena forking saya kira), terutama pada file kecil.Jika Anda menjalankan ini di host Linux / Unix, solusi termudah adalah menggunakan
exec()
atau serupa dengan menjalankan perintahwc -l $path
. Pastikan Anda telah membersihkannya$path
terlebih dahulu untuk memastikan bahwa itu bukan sesuatu seperti "/ path / to / file; rm -rf /".sumber
Ada cara yang lebih cepat yang saya temukan yang tidak memerlukan perulangan melalui seluruh file
hanya di sistem * nix , mungkin ada cara serupa di windows ...
$file = '/path/to/your.file'; //Get number of lines $totalLines = intval(exec("wc -l '$file'"));
sumber
exec('wc -l '.escapeshellarg($file).' 2>/dev/null')
Jika Anda menggunakan PHP 5.5, Anda dapat menggunakan generator . Ini TIDAK akan berfungsi dalam versi PHP apa pun sebelum 5.5. Dari php.net:
"Generator menyediakan cara mudah untuk mengimplementasikan iterator sederhana tanpa overhead atau kerumitan implementasi kelas yang mengimplementasikan antarmuka Iterator."
// This function implements a generator to load individual lines of a large file function getLines($file) { $f = fopen($file, 'r'); // read each line of the file without loading the whole file to memory while ($line = fgets($f)) { yield $line; } } // Since generators implement simple iterators, I can quickly count the number // of lines using the iterator_count() function. $file = '/path/to/file.txt'; $lineCount = iterator_count(getLines($file)); // the number of lines in the file
sumber
try
/finally
tidak benar-benar diperlukan, PHP secara otomatis akan menutup file untuk Anda. Anda mungkin juga harus menyebutkan bahwa penghitungan sebenarnya dapat dilakukan dengan menggunakaniterator_count(getFiles($file))
:)Ini adalah tambahan untuk solusi Wallace de Souza
Itu juga melewatkan baris kosong saat menghitung:
function getLines($file) { $file = new \SplFileObject($file, 'r'); $file->setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE); $file->seek(PHP_INT_MAX); return $file->key() + 1; }
sumber
Jika Anda menggunakan linux, Anda dapat melakukan:
number_of_lines = intval(trim(shell_exec("wc -l ".$file_name." | awk '{print $1}'")));
Anda hanya perlu menemukan perintah yang tepat jika Anda menggunakan OS lain
Salam
sumber
private static function lineCount($file) { $linecount = 0; $handle = fopen($file, "r"); while(!feof($handle)){ if (fgets($handle) !== false) { $linecount++; } } fclose($handle); return $linecount; }
Saya ingin menambahkan sedikit perbaikan pada fungsi di atas ...
dalam contoh spesifik di mana saya memiliki file yang berisi kata 'pengujian' fungsi mengembalikan 2 sebagai hasilnya. jadi saya perlu menambahkan centang apakah widget dikembalikan salah atau tidak :)
Selamat bersenang-senang :)
sumber
Berdasarkan solusi dominic Rodger, inilah yang saya gunakan (menggunakan wc jika tersedia, jika tidak, mundur ke solusi dominic Rodger).
class FileTool { public static function getNbLines($file) { $linecount = 0; $m = exec('which wc'); if ('' !== $m) { $cmd = 'wc -l < "' . str_replace('"', '\\"', $file) . '"'; $n = exec($cmd); return (int)$n + 1; } $handle = fopen($file, "r"); while (!feof($handle)) { $line = fgets($handle); $linecount++; } fclose($handle); return $linecount; } }
https://github.com/lingtalfi/Bat/blob/master/FileTool.php
sumber
Menghitung jumlah baris dapat dilakukan dengan kode-kode berikut:
<?php $fp= fopen("myfile.txt", "r"); $count=0; while($line = fgetss($fp)) // fgetss() is used to get a line from a file ignoring html tags $count++; echo "Total number of lines are ".$count; fclose($fp); ?>
sumber
Anda punya beberapa pilihan. Yang pertama adalah meningkatkan memori yang tersedia, yang mungkin bukan cara terbaik untuk melakukan hal-hal mengingat Anda menyatakan bahwa file bisa menjadi sangat besar. Cara lain adalah dengan menggunakan widget untuk membaca file baris demi baris dan menambah penghitung, yang seharusnya tidak menyebabkan masalah memori sama sekali karena hanya baris saat ini yang ada di memori pada satu waktu.
sumber
Ada jawaban lain yang menurut saya bisa menjadi tambahan yang bagus untuk daftar ini.
Jika Anda telah
perl
menginstal dan dapat menjalankan sesuatu dari shell di PHP:$lines = exec('perl -pe \'s/\r\n|\n|\r/\n/g\' ' . escapeshellarg('largetextfile.txt') . ' | wc -l');
Ini harus menangani sebagian besar jeda baris baik dari Unix atau file yang dibuat Windows.
DUA kelemahan (setidaknya):
1) Bukan ide bagus untuk memiliki skrip Anda sehingga bergantung pada sistem yang dijalankannya (mungkin tidak aman untuk menganggap Perl dan wc tersedia)
2) Hanya kesalahan kecil dalam melarikan diri dan Anda telah menyerahkan akses ke shell di komputer Anda.
Seperti kebanyakan hal yang saya ketahui (atau menurut saya) tentang pengkodean, saya mendapatkan info ini dari tempat lain:
Artikel John Reeve
sumber
public function quickAndDirtyLineCounter() { echo "<table>"; $folders = ['C:\wamp\www\qa\abcfolder\', ]; foreach ($folders as $folder) { $files = scandir($folder); foreach ($files as $file) { if($file == '.' || $file == '..' || !file_exists($folder.'\\'.$file)){ continue; } $handle = fopen($folder.'/'.$file, "r"); $linecount = 0; while(!feof($handle)){ if(is_bool($handle)){break;} $line = fgets($handle); $linecount++; } fclose($handle); echo "<tr><td>" . $folder . "</td><td>" . $file . "</td><td>" . $linecount . "</td></tr>"; } } echo "</table>"; }
sumber
Saya menggunakan metode ini untuk menghitung berapa banyak baris dalam sebuah file. Apa sisi negatif dari melakukan ayat-ayat ini dengan jawaban yang lain. Saya melihat banyak baris sebagai lawan dari solusi dua baris saya. Saya menduga ada alasan mengapa tidak ada yang melakukan ini.
$lines = count(file('your.file')); echo $lines;
sumber
Solusi lintas platform paling ringkas yang hanya menyangga satu baris dalam satu waktu.
$file = new \SplFileObject(__FILE__); $file->setFlags($file::READ_AHEAD); $lines = iterator_count($file);
Sayangnya, kami harus mengatur
READ_AHEAD
bendera jika tidakiterator_count
memblokir tanpa batas. Jika tidak, ini akan menjadi satu baris.sumber
Untuk hanya menghitung garis gunakan:
$handle = fopen("file","r"); static $b = 0; while($a = fgets($handle)) { $b++; } echo $b;
sumber