Apakah ada alternatif untuk kode di bawah ini:
startFromLine = 141978 # or whatever line I need to jump to
urlsfile = open(filename, "rb", 0)
linesCounter = 1
for line in urlsfile:
if linesCounter > startFromLine:
DoSomethingWithThisLine(line)
linesCounter += 1
Jika saya memproses file teks besar (~15MB)
dengan baris yang tidak diketahui tetapi panjangnya berbeda, dan perlu melompat ke baris tertentu, nomor mana yang saya ketahui sebelumnya? Saya merasa tidak enak dengan memprosesnya satu per satu ketika saya tahu saya dapat mengabaikan setidaknya paruh pertama file. Mencari solusi yang lebih elegan jika ada.
python
text-files
pengguna63503
sumber
sumber
Jawaban:
linecache :
sumber
Anda tidak dapat melompat ke depan tanpa membaca file setidaknya sekali, karena Anda tidak tahu di mana letak baris baru. Anda bisa melakukan sesuatu seperti:
sumber
Anda tidak benar-benar memiliki banyak opsi jika garisnya memiliki panjang yang berbeda ... sayangnya Anda perlu memproses karakter akhir baris untuk mengetahui kapan Anda maju ke baris berikutnya.
Anda dapat, bagaimanapun, secara dramatis mempercepat ini DAN mengurangi penggunaan memori dengan mengubah parameter terakhir menjadi "terbuka" menjadi sesuatu yang bukan 0.
0 berarti operasi pembacaan file tidak disangga, yang sangat lambat dan intensif disk. 1 berarti file tersebut memiliki buffering baris, yang akan menjadi peningkatan. Apa pun di atas 1 (katakanlah 8k .. yaitu: 8096, atau lebih tinggi) membaca potongan file ke dalam memori. Anda masih mengaksesnya
for line in open(etc):
, tetapi python hanya berjalan sedikit demi sedikit, membuang setiap potongan yang di-buffer setelah diproses.sumber
Saya mungkin dimanjakan oleh ram yang melimpah, tapi 15 M tidaklah besar. Membaca ke dalam memori dengan
readlines()
adalah apa yang biasanya saya lakukan dengan file sebesar ini. Mengakses baris setelah itu sepele.sumber
Saya heran tidak ada yang menyebutkan islice
atau jika Anda menginginkan seluruh file lainnya
atau jika Anda ingin setiap baris lain dari file tersebut
sumber
Karena tidak ada cara untuk menentukan panjang semua garis tanpa membacanya, Anda tidak punya pilihan selain mengulang semua garis sebelum garis mulai. Yang bisa Anda lakukan hanyalah membuatnya terlihat bagus. Jika file sangat besar maka Anda mungkin ingin menggunakan pendekatan berbasis generator:
Catatan: indeks berbasis nol dalam pendekatan ini.
sumber
Jika Anda tidak ingin membaca seluruh file di memori .. Anda mungkin perlu membuat beberapa format selain teks biasa.
tentu saja itu semua tergantung pada apa yang Anda coba lakukan, dan seberapa sering Anda akan melompati file.
Misalnya, jika Anda akan berpindah ke baris berkali-kali dalam file yang sama, dan Anda tahu bahwa file tidak berubah saat bekerja dengannya, Anda dapat melakukan ini:
Pertama, lewati seluruh file, dan catat " seek-location "dari beberapa nomor-baris-kunci (seperti, pernah 1000 baris),
Kemudian jika Anda menginginkan baris 12005, lompat ke posisi 12000 (yang telah Anda rekam) kemudian baca 5 baris dan Anda akan mengenal Anda berada di baris 12005 dan seterusnya
sumber
Jika Anda mengetahui sebelumnya posisi di file (bukan nomor baris), Anda dapat menggunakan file.seek () untuk menuju ke posisi itu.
Edit : Anda dapat menggunakan fungsi linecache.getline (nama file, lineno) , yang akan mengembalikan konten baris lineno, tetapi hanya setelah membaca seluruh file ke dalam memori. Baik jika Anda mengakses baris secara acak dari dalam file (seperti yang mungkin ingin dilakukan python untuk mencetak traceback) tetapi tidak bagus untuk file 15MB.
sumber
Apa yang menghasilkan file yang ingin Anda proses? Jika itu adalah sesuatu di bawah kendali Anda, Anda dapat membuat indeks (baris mana di posisi mana.) Pada saat file ditambahkan. File indeks dapat berukuran baris tetap (spasi berisi atau 0 angka berlapis) dan pasti akan lebih kecil. Dan dengan demikian bisa dibaca dan diproses secara cepat.
sumber
Saya memiliki masalah yang sama (perlu mengambil dari baris khusus file besar).
Tentunya, saya dapat setiap saat menjalankan semua catatan dalam file dan menghentikannya ketika penghitung akan sama dengan baris target, tetapi itu tidak bekerja secara efektif dalam kasus ketika Anda ingin mendapatkan jumlah jamak dari baris tertentu. Itu menyebabkan masalah utama diselesaikan - bagaimana menangani langsung ke tempat file yang diperlukan.
Saya menemukan keputusan berikutnya: Pertama saya menyelesaikan kamus dengan posisi awal setiap baris (kuncinya adalah nomor baris, dan nilai - panjang kumulatif baris sebelumnya).
akhirnya, fungsi tujuan:
t.seek (line_number) - perintah yang menjalankan pemangkasan file hingga awal baris. Jadi, jika Anda selanjutnya melakukan readline - Anda mendapatkan garis target Anda.
Dengan menggunakan pendekatan seperti itu, saya telah menghemat sebagian besar waktu.
sumber
Anda dapat menggunakan mmap untuk menemukan offset garis. MMap tampaknya menjadi cara tercepat untuk memproses file
contoh:
kemudian gunakan f.seek (offset) untuk berpindah ke baris yang Anda butuhkan
sumber
Apakah baris itu sendiri berisi informasi indeks? Jika konten setiap baris adalah seperti "
<line index>:Data
", makaseek()
pendekatan tersebut dapat digunakan untuk melakukan pencarian biner melalui file tersebut, bahkan jika jumlahnyaData
adalah variabel. Anda akan mencari titik tengah file, membaca baris, memeriksa apakah indeksnya lebih tinggi atau lebih rendah dari yang Anda inginkan, dll.Jika tidak, hal terbaik yang dapat Anda lakukan adalah adil
readlines()
. Jika Anda tidak ingin membaca semua 15MB, Anda dapat menggunakansizehint
argumen untuk setidaknya mengganti banyakreadline()
dengan jumlah panggilan ke yang lebih kecilreadlines()
.sumber
Jika Anda berurusan dengan file teks & berbasis sistem linux , Anda dapat menggunakan perintah linux.
Bagi saya, ini bekerja dengan baik!
sumber
Berikut adalah contoh menggunakan 'readlines (sizehint)' untuk membaca potongan baris pada satu waktu. DNS menunjukkan solusi itu. Saya menulis contoh ini karena contoh lain di sini berorientasi pada garis tunggal.
sumber
Tidak ada jawaban yang memuaskan, jadi berikut ini cuplikan kecil untuk membantu.
Contoh penggunaan:
Ini melibatkan melakukan banyak pencarian file, tetapi berguna untuk kasus di mana Anda tidak dapat memasukkan seluruh file ke dalam memori. Itu melakukan satu pembacaan awal untuk mendapatkan lokasi baris (jadi itu membaca seluruh file, tetapi tidak menyimpan semuanya di memori), dan kemudian setiap akses file mencari fakta.
Saya menawarkan potongan di atas di bawah lisensi MIT atau Apache atas kebijaksanaan pengguna.
sumber
Dapat menggunakan fungsi ini untuk mengembalikan baris n:
sumber