Saya sedang menulis penampil file log untuk aplikasi web dan untuk itu saya ingin memberi paginasi melalui baris file log. Item dalam file tersebut berdasarkan garis dengan item terbaru di bagian bawah.
Jadi saya memerlukan tail()
metode yang dapat membaca n
baris dari bawah dan mendukung offset. Apa yang saya hasilkan terlihat seperti ini:
def tail(f, n, offset=0):
"""Reads a n lines from f with an offset of offset lines."""
avg_line_length = 74
to_read = n + offset
while 1:
try:
f.seek(-(avg_line_length * to_read), 2)
except IOError:
# woops. apparently file is smaller than what we want
# to step back, go to the beginning instead
f.seek(0)
pos = f.tell()
lines = f.read().splitlines()
if len(lines) >= to_read or pos == 0:
return lines[-to_read:offset and -offset or None]
avg_line_length *= 1.3
Apakah ini pendekatan yang masuk akal? Apa cara yang disarankan untuk mengekor file log dengan offset?
seek(0,2)
lalutell()
), dan menggunakan nilai itu untuk mencari relatif ke awal.open
perintah yang digunakan untuk menghasilkanf
file objek harus ditentukan, karena tergantung jikaf=open(..., 'rb')
atauf=open(..., 'rt')
yangf
harus diproses secara berbedaJawaban:
Ini mungkin lebih cepat dari milikmu. Tidak membuat asumsi tentang panjang garis. Mundur melalui file satu blok pada satu waktu sampai ditemukan jumlah karakter '\ n' yang tepat.
Saya tidak suka asumsi rumit tentang panjang garis ketika - sebagai masalah praktis - Anda tidak akan pernah tahu hal-hal seperti itu.
Secara umum, ini akan menemukan 20 baris terakhir pada lintasan pertama atau kedua melalui loop. Jika 74 karakter Anda benar-benar akurat, Anda membuat ukuran blok 2048 dan Anda akan segera mengekor 20 garis.
Juga, saya tidak membakar banyak kalori otak mencoba untuk menyelaraskan dengan blok OS fisik. Menggunakan paket I / O tingkat tinggi ini, saya ragu Anda akan melihat konsekuensi kinerja dari mencoba menyelaraskan pada batas blok OS. Jika Anda menggunakan I / O tingkat rendah, maka Anda mungkin melihat speedup.
MEMPERBARUI
untuk Python 3.2 dan ke atas, ikuti proses pada byte sebagai Dalam file teks (yang dibuka tanpa "b" dalam string mode), hanya mencari relatif terhadap awal file yang diizinkan (pengecualian sedang mencari hingga akhir file dengan seek (0, 2)) .:
misalnya:
f = open('C:/.../../apache_logs.txt', 'rb')
sumber
io.UnsupportedOperation: can't do nonzero end-relative seeks
saya dapat mengubah offset ke 0, tapi itu mengalahkan tujuan fungsi.Mengasumsikan sistem unix-like pada Python 2 yang dapat Anda lakukan:
Untuk python 3, Anda dapat melakukannya:
sumber
offset_total = str(n+offset)
dan ganti baris inistdin,stdout = os.popen2("tail -n "+offset_total+" "+f)
untuk menghindariTypeErrors (cannot concatenate int+str)
Inilah jawaban saya. Python murni. Menggunakan timeit sepertinya cukup cepat. Tailing 100 baris file log yang memiliki 100.000 baris:
Ini kodenya:
sumber
if len(lines_found) > lines:
benar - benar perlu? Bukankahloop
kondisinya akan menangkapnya juga?os.SEEK_END
digunakan hanya untuk kejelasan? Sejauh yang saya temukan, nilainya konstan (= 2). Saya bertanya-tanya tentang meninggalkannya untuk dapat meninggalkanimport os
. Terima kasih atas solusi hebatnya!os.SEEK_END
dengan yang setara dengan integer. Itu terutama di sana untuk dibaca.while len(lines_found) < lines
kewhile len(lines_found) <= lines
dalam salinan saya. Terima kasih!Jika membaca seluruh file dapat diterima maka gunakan deque.
Sebelum 2.6, deques tidak memiliki opsi maksimal, tetapi cukup mudah untuk diterapkan.
Jika itu adalah persyaratan untuk membaca file dari akhir, maka gunakan pencarian gallop (alias eksponensial).
sumber
pos *= 2
tampaknya sepenuhnya arbitrer. Apa maknanya?Jawaban S.Lott di atas hampir berhasil untuk saya tetapi akhirnya memberi saya sebagian garis. Ternyata itu merusak data pada batas blok karena data memegang blok baca dalam urutan terbalik. Ketika '.join (data) dipanggil, blok-bloknya berada dalam urutan yang salah. Ini memperbaikinya.
sumber
Kode yang akhirnya saya gunakan. Saya pikir ini yang terbaik sejauh ini:
sumber
Solusi sederhana dan cepat dengan mmap:
sumber
.rfind
metode untuk memindai mundur untuk baris baru, daripada melakukan byte pada suatu waktu memeriksa di tingkat Python; di CPython, mengganti kode tingkat Python dengan Panggilan bawaan C biasanya menang dengan banyak). Untuk input yang lebih kecil,deque
dengan amaxlen
lebih sederhana dan mungkin sama cepatnya.Versi yang kompatibel dengan python3 yang bahkan lebih bersih yang tidak memasukkan tetapi menambahkan & membalikkan:
gunakan seperti ini:
sumber
Perbarui solusi @ papercrane ke python3. Buka file dengan
open(filename, 'rb')
dan:sumber
Posting jawaban atas perintah komentator atas jawaban saya untuk pertanyaan serupa di mana teknik yang sama digunakan untuk mengubah baris terakhir file, tidak hanya mendapatkannya.
Untuk file dengan ukuran signifikan,
mmap
adalah cara terbaik untuk melakukan ini. Untuk meningkatkanmmap
jawaban yang ada , versi ini portabel antara Windows dan Linux, dan harus berjalan lebih cepat (meskipun tidak akan berfungsi tanpa beberapa modifikasi pada 32 bit Python dengan file dalam rentang GB, lihat jawaban lain untuk petunjuk tentang penanganan ini , dan untuk memodifikasi agar berfungsi pada Python 2 ).Ini mengasumsikan jumlah garis berekor cukup kecil sehingga Anda dapat dengan aman membaca semuanya dalam memori sekaligus; Anda juga bisa menjadikan ini fungsi generator dan secara manual membaca satu baris sekaligus dengan mengganti baris terakhir dengan:
Terakhir, ini dibaca dalam mode biner (perlu digunakan
mmap
) sehingga memberikanstr
garis (Py2) danbytes
garis (Py3); jika Anda inginunicode
(Py2) ataustr
(Py3), pendekatan iteratif dapat diubah untuk memecahkan kode untuk Anda dan / atau memperbaiki baris baru:Catatan: Saya mengetik semuanya ini di mesin tempat saya tidak memiliki akses untuk menguji Python. Tolong beri tahu saya jika saya salah mengetik; ini cukup mirip dengan jawaban saya yang lain sehingga saya pikir itu harus bekerja, tetapi tweak (misalnya menangani
offset
) dapat menyebabkan kesalahan halus. Tolong beri tahu saya di komentar jika ada kesalahan.sumber
Saya menemukan Popen di atas untuk menjadi solusi terbaik. Cepat dan kotor dan berfungsi Untuk python 2.6 pada mesin Unix saya menggunakan yang berikut ini
soutput akan berisi n baris terakhir dari kode. untuk beralih melalui soutput baris demi baris lakukan:
sumber
berdasarkan jawaban terpilih S.Lott (25 Sep '08 di 21:43), tetapi tetap untuk file kecil.
Semoga ini bermanfaat.
sumber
Ada beberapa implementasi tail on pypi yang dapat Anda instal menggunakan pip:
Tergantung pada situasi Anda, mungkin ada keuntungan menggunakan salah satu alat yang ada ini.
sumber
tailhead
,tailer
tetapi mereka tidak berhasil. Juga mencobamtFileUtil
. Itu pada awalnya melempar kesalahan karenaprint
pernyataan tidak memiliki tanda kurung (Saya di Python 3.6). Saya menambahkan itureverse.py
dan pesan kesalahan hilang tetapi ketika skrip saya memanggil modul (mtFileUtil.tail(open(logfile_path), 5)
), itu tidak mencetak apa pun.Sederhana:
sumber
Untuk efisiensi dengan file yang sangat besar (umum dalam situasi logfile di mana Anda mungkin ingin menggunakan tail), Anda umumnya ingin menghindari membaca seluruh file (bahkan jika Anda melakukannya tanpa membaca seluruh file ke dalam memori sekaligus) Namun, Anda lakukan perlu entah bagaimana bekerja diimbangi dalam garis daripada karakter. Salah satu kemungkinan adalah membaca mundur dengan seek () char by char, tetapi ini sangat lambat. Sebaliknya, lebih baik diproses dalam blok yang lebih besar.
Saya memiliki fungsi utilitas yang saya tulis beberapa waktu lalu untuk membaca file mundur yang dapat digunakan di sini.
[Sunting] Menambahkan versi yang lebih spesifik (tidak perlu mundur dua kali)
sumber
Anda dapat pergi ke akhir file Anda dengan f.seek (0, 2) dan kemudian membacakan baris satu per satu dengan penggantian readline berikut ():
sumber
Berdasarkan jawaban Eyecue (10 Jun '10 pada 21:28): kelas ini menambahkan metode head () dan tail () ke file objek.
Pemakaian:
sumber
Beberapa solusi ini memiliki masalah jika file tidak diakhiri dengan \ n atau memastikan baris pertama yang lengkap dibaca.
sumber
Berikut ini adalah implementasi yang cukup sederhana:
sumber
f.seek
? Kenapa tidak sebelumwith open
? Juga, mengapaexcept
Anda melakukanf.readlines()
??Ada modul yang sangat berguna yang dapat melakukan ini:
sumber
Solusi Lain
jika file txt Anda terlihat seperti ini: mouse snake cat lizard serigala dog
Anda bisa membalikkan file ini hanya dengan menggunakan pengindeksan array dalam python '' '
hasil: kucing kadal serigala anjing
sumber
Cara paling sederhana adalah dengan menggunakan
deque
:sumber
Saya harus membaca nilai tertentu dari baris terakhir file, dan menemukan utas ini. Daripada menciptakan kembali roda dengan Python, saya malah membuat skrip shell kecil, disimpan sebagai / usr / local / bin / get_last_netp:
Dan dalam program Python:
sumber
Bukan contoh pertama menggunakan deque, tetapi yang lebih sederhana. Ini umum: ini bekerja pada objek yang dapat diulang, bukan hanya file.
sumber
sumber
sumber
sumber
sumber
Pembaruan untuk jawaban yang diberikan oleh A.Coady
Bekerja dengan python 3 .
Ini menggunakan Pencarian Eksponensial dan hanya akan menyangga
N
baris dari belakang dan sangat efisien.sumber
Setelah dipikir-pikir, ini mungkin secepat apa pun di sini.
Jauh lebih sederhana. Dan itu tampaknya merobek dengan kecepatan yang baik.
sumber