Saya menggunakan loop for untuk membaca file, tetapi saya hanya ingin membaca baris tertentu, katakanlah baris # 26 dan # 30. Apakah ada fitur bawaan untuk mencapai ini?
enumerate(x)menggunakan x.next, jadi tidak perlu seluruh file dalam memori.
Alok Singhal
3
Daging sapi kecil saya dengan ini adalah bahwa A) Anda ingin menggunakan dengan bukan pasangan buka / tutup dan dengan demikian menjaga tubuh tetap pendek, B) Tetapi tubuh tidak terlalu pendek. Kedengarannya seperti pertukaran antara kecepatan / ruang dan menjadi Pythonic. Saya tidak yakin solusi apa yang terbaik.
Hamish Grubijan
5
dengan dibesar-besarkan, python bergaul dengan baik selama lebih dari 13 tahun tanpanya
Dan D.
38
@Dan D. Listrik berlebihan, umat manusia hidup baik-baik saja selama lebih dari 200 ribu tahun tanpanya. ;-) 'with' membuatnya lebih aman, lebih mudah dibaca, dan satu baris lebih pendek.
Romain Vincent
9
mengapa digunakan untuk loop, saya tidak berpikir Anda mengerti artinya big file.
Ubah 4ke nomor baris yang Anda inginkan, dan Anda aktif. Perhatikan bahwa 4 akan membawa baris kelima karena penghitungannya berbasis nol.
Jika file tersebut mungkin sangat besar, dan menyebabkan masalah saat dibaca ke dalam memori, mungkin ide yang baik untuk mengambil saran @ Alok dan menggunakan enumerate () .
Untuk menyimpulkan:
Gunakan fileobject.readlines()atau for line in fileobjectsebagai solusi cepat untuk file kecil.
Gunakan linecacheuntuk solusi yang lebih elegan, yang akan cukup cepat untuk membaca banyak file, mungkin berulang kali.
Ambil saran @ Alok dan gunakanenumerate() untuk file yang bisa sangat besar, dan tidak akan masuk ke dalam memori. Perhatikan bahwa menggunakan metode ini mungkin lambat karena file dibaca berurutan.
Bagus. Saya baru saja melihat sumber linecachemodul, dan sepertinya membaca seluruh file di memori. Jadi, jika akses acak lebih penting daripada optimasi ukuran, linecacheadalah metode terbaik.
Alok Singhal
7
dengan linecache.getlin ('some_file', 4) Saya mendapatkan baris ke-4, bukan ke-5.
Juan
fakta menyenangkan: jika Anda menggunakan satu set dan bukan daftar dalam contoh kedua, Anda mendapatkan O (1) waktu berjalan. Mencari dalam daftar adalah O (n). Set internal direpresentasikan sebagai hash, dan itulah sebabnya Anda mendapatkan O (1) waktu berjalan. bukan masalah besar dalam contoh ini, tetapi Jika menggunakan daftar angka yang besar, dan peduli efisiensi, set adalah cara yang harus dilakukan.
rady
linecachesekarang tampaknya hanya berfungsi untuk file sumber python
Paul H
Anda juga dapat menggunakan linecache.getlines('/etc/passwd')[0:4]untuk membaca di baris pertama, kedua, ketiga dan keempat.
zyy
30
Pendekatan yang cepat dan ringkas dapat:
def picklines(thefile, whatlines):return[x for i, x in enumerate(thefile)if i in whatlines]
ini menerima objek seperti file terbuka thefile(menyerahkan kepada pemanggil apakah itu harus dibuka dari file disk, atau melalui misalnya soket, atau aliran file-suka lainnya) dan satu set indeks garis berbasis nol whatlines, dan mengembalikan sebuah daftar, dengan jejak memori rendah dan kecepatan wajar. Jika jumlah baris yang dikembalikan besar, Anda mungkin lebih suka generator:
def yieldlines(thefile, whatlines):return(x for i, x in enumerate(thefile)if i in whatlines)
yang pada dasarnya hanya baik untuk perulangan - perhatikan bahwa satu - satunya perbedaan berasal dari menggunakan kurung bulat daripada tanda kurung di return pernyataan, membuat daftar pemahaman dan ekspresi generator masing-masing.
Catatan lebih lanjut bahwa meskipun disebutkan "baris" dan "file" fungsi-fungsi ini banyak, banyak lebih umum - mereka akan bekerja pada setiap iterable, baik itu file terbuka atau lainnya, kembali daftar (atau generator) item berdasarkan nomor-item progresif mereka. Jadi, saya sarankan menggunakan nama-nama umum yang lebih tepat ;-).
@ephemient, saya tidak setuju - genexp membaca dengan lancar dan sempurna.
Alex Martelli
Solusi yang bagus dan elegan, terima kasih! Memang, bahkan file besar harus didukung, dengan ekspresi generator. Tidak bisa lebih elegan dari ini, bukan? :)
Samuel Lampa
Solusi yang bagus, bagaimana ini dibandingkan dengan yang diusulkan oleh @AdamMatan? Solusi Adam bisa lebih cepat karena mengeksploitasi informasi tambahan (nomor baris meningkat secara monoton) yang dapat menyebabkan pemberhentian awal. Saya memiliki file 10GB yang tidak dapat saya muat ke dalam memori.
Mannaggia
2
@Mannaggia Ini tidak cukup ditekankan dalam jawaban ini, tetapi whatlinesharus a set, karena if i in whatlinesakan mengeksekusi lebih cepat dengan set daripada daftar (diurutkan). Saya tidak memperhatikannya terlebih dahulu dan malah menemukan solusi jelek saya sendiri dengan daftar terurut (di mana saya tidak perlu memindai daftar setiap kali, sementara if i in whatlinesmelakukan hal itu), tetapi perbedaan kinerja dapat diabaikan (dengan data saya) dan ini solusi jauh lebih elegan.
Ini membaca seluruh file ke dalam memori. Anda mungkin juga memanggil file.read (). Split ('\ n') kemudian gunakan pencarian indeks array untuk mendapatkan garis yang menarik ...
Rapi. Tapi bagaimana Anda close()file saat membukanya dengan cara ini?
Milo Wielondek
1
@ 0sh, apakah kita perlu menutup?
Ooker
1
Iya. kita perlu menutup setelah ini. Ketika kita membuka file menggunakan "dengan" ... itu menutup sendiri.
reetesh11
10
Demi kelengkapan, berikut adalah satu opsi lagi.
Mari kita mulai dengan definisi dari python docs :
slice Suatu objek yang biasanya berisi sebagian dari urutan. Sepotong dibuat menggunakan notasi subskrip, [] dengan titik dua di antara angka ketika beberapa diberikan, seperti dalam variabel_name [1: 3: 5]. Notasi braket (subskrip) menggunakan objek slice secara internal (atau dalam versi yang lebih lama, __ widgetlice __ () dan __setslice __ ()).
Meskipun notasi irisan tidak langsung berlaku untuk iterator secara umum, itertoolspaket berisi fungsi penggantian:
from itertools import islice
# print the 100th linewith open('the_file')as lines:for line in islice(lines,99,100):print line
# print each third line until 100with open('the_file')as lines:for line in islice(lines,0,100,3):print line
Keuntungan tambahan dari fungsi ini adalah ia tidak membaca iterator sampai akhir. Jadi Anda dapat melakukan hal-hal yang lebih kompleks:
with open('the_file')as lines:# print the first 100 linesfor line in islice(lines,100):print line
# then skip the next 5for line in islice(lines,5):pass# print the restfor line in lines:print line
Dan untuk menjawab pertanyaan awal:
# how to read lines #26 and #30In[365]: list(islice(xrange(1,100),25,30,4))Out[365]:[26,30]
Sejauh ini pendekatan terbaik saat bekerja dengan file besar. Program saya berubah dari mengkonsumsi 8GB + menjadi hampir tidak ada. Tradeoffnya adalah penggunaan CPU yang berubah dari ~ 15% menjadi ~ 40% tetapi pemrosesan aktual file adalah 70% lebih cepat. Saya akan mengambil tradeoff sepanjang hari. Terimakasih! 🎉🎉🎉
GollyJer
1
Ini tampaknya yang paling pythonic bagi saya. Terima kasih!
ipetrik
10
Membaca file sangat cepat. Membaca file 100MB membutuhkan waktu kurang dari 0,1 detik (lihat artikel saya Membaca dan Menulis File dengan Python ). Karenanya Anda harus membacanya sepenuhnya dan kemudian bekerja dengan satu baris.
Apa yang paling banyak dilakukan di sini bukanlah salah, tetapi gaya yang buruk. Membuka file harus selalu dilakukanwith karena memastikan bahwa file ditutup kembali.
Jadi Anda harus melakukannya seperti ini:
with open("path/to/file.txt")as f:
lines = f.readlines()print(lines[26])# or whatever you want to do with this lineprint(lines[30])# or whatever you want to do with this line
File besar
Jika Anda memiliki file yang besar dan konsumsi memori menjadi masalah, Anda dapat memprosesnya baris demi baris:
with open("path/to/file.txt")as f:for i, line in enumerate(f):pass# process line i
IMO itu adalah gaya yang sangat buruk untuk membaca seluruh file dengan panjang yang tidak diketahui, hanya untuk mendapatkan 30 baris pertama .. bagaimana dengan konsumsi memori .. dan bagaimana dengan aliran tanpa akhir?
kembali42
@ return42 Ini sangat tergantung pada aplikasi. Bagi banyak orang, sama sekali tidak masalah untuk menganggap bahwa file teks memiliki ukuran yang jauh lebih rendah daripada memori yang tersedia. Jika Anda berpotensi memiliki file besar, saya telah mengedit jawaban saya.
Martin Thoma
terima kasih untuk tambahan Anda, yang sama dengan jawaban alok . Dan maaf tidak, saya rasa ini tidak tergantung pada aplikasinya. IMO selalu lebih baik tidak membaca lebih banyak baris dari yang Anda butuhkan.
kembali42
7
Beberapa di antaranya indah, tetapi bisa dilakukan lebih sederhana:
start =0# some starting index
end =5000# some ending index
filename ='test.txt'# some file we want to usewith open(filename)as fh:
data = fin.readlines()[start:end]print(data)
Itu akan menggunakan daftar slicing, memuat seluruh file, tetapi sebagian besar sistem akan meminimalkan penggunaan memori dengan tepat, lebih cepat dari sebagian besar metode yang diberikan di atas, dan bekerja pada file data 10G + saya. Semoga berhasil!
Anda dapat melakukan pencarian () yang menempatkan kepala baca Anda ke byte yang ditentukan dalam file. Ini tidak akan membantu Anda kecuali jika Anda tahu persis berapa banyak byte (karakter) yang ditulis dalam file sebelum baris yang ingin Anda baca. Mungkin file Anda benar-benar diformat (setiap baris adalah X jumlah byte?) Atau, Anda dapat menghitung sendiri jumlah karakter (ingat untuk memasukkan karakter yang tidak terlihat seperti jeda baris) jika Anda benar-benar menginginkan peningkatan kecepatan.
Jika tidak, Anda harus membaca setiap baris sebelum baris yang Anda inginkan, sesuai salah satu dari banyak solusi yang sudah diusulkan di sini.
def getitems(iterable, items):
items = list(items)# get a list from any iterable and make our own copy# since we modify itif items:
items.sort()for n, v in enumerate(iterable):if n == items[0]:yield v
items.pop(0)ifnot items:breakprint list(getitems(open("/usr/share/dict/words"),[25,29]))# ['Abelson\n', 'Abernathy\n']# note that index 25 is the 26th item
Roger, cowok favoritku! Ini bisa mendapat manfaat dari pernyataan dengan.
Hamish Grubijan
2
Saya lebih suka pendekatan ini karena lebih umum, yaitu Anda dapat menggunakannya pada file, pada hasil f.readlines(), pada StringIOobjek, apa pun:
def read_specific_lines(file, lines_to_read):"""file is any iterable; lines_to_read is an iterable containing int values"""
lines = set(lines_to_read)
last = max(lines)for n, line in enumerate(file):if n +1in lines:yield line
if n +1> last:return>>>with open(r'c:\temp\words.txt')as f:[s for s in read_specific_lines(f,[1,2,3,1000])]['A\n','a\n','aa\n','accordant\n']
def indexLines(filename, lines=[2,4,6,8,10,12,3,5,7,1]):
fp = open(filename,"r")
src = fp.readlines()
data =[(index, line)for index, line in enumerate(src)if index in lines]
fp.close()return data
# Usage below
filename ="C:\\Your\\Path\\And\\Filename.txt"for line in indexLines(filename):# using default list, specify your own list of lines otherwiseprint"Line: %s\nData: %s\n"%(line[0], line[1])
Objek file memiliki metode .readlines () yang akan memberi Anda daftar konten file, satu baris per item daftar. Setelah itu, Anda bisa menggunakan teknik mengiris daftar normal.
ini bukan jawaban yang valid. setelah panggilan pertama ke readlines()iterator akan habis dan panggilan kedua akan mengembalikan daftar kosong atau membuat kesalahan (tidak ingat yang mana)
Paul H
1
Anda dapat melakukan ini dengan sangat sederhana dengan sintaksis yang telah disebutkan oleh seseorang, tetapi ini adalah cara termudah untuk melakukannya:
Untuk mencetak baris tertentu dalam file teks. Buat daftar "lines2print" dan kemudian cetak ketika enumerasi "di" daftar lines2print. Untuk menghilangkan '\ n' tambahan gunakan line.strip () atau line.strip ('\ n'). Saya hanya suka "daftar pemahaman" dan coba gunakan ketika saya bisa. Saya suka metode "with" untuk membaca file teks untuk mencegah membiarkan file terbuka karena alasan apa pun.
lines2print =[26,30]# can be a big list and order doesn't matter.with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in lines2print]
atau jika daftar kecil ketik saja daftar sebagai daftar ke dalam pemahaman.
with open("filepath",'r')as fp:[print(x.strip())for ei,x in enumerate(fp)if ei in[26,30]]
Untuk mencetak garis yang diinginkan. Untuk mencetak garis di atas / di bawah garis yang diperlukan.
def dline(file,no,add_sub=0):
tf=open(file)for sno,line in enumerate(tf):if sno==no-1+add_sub:print(line)
tf.close()
jalankan ----> dline ("D: \ dummy.txt", 6) yaitu dline ("path file", line_number, jika Anda ingin baris atas dari garis yang dicari berikan 1 untuk lebih rendah -1 ini adalah nilai default opsional akan diambil 0)
Jika Anda ingin membaca baris tertentu, seperti baris yang dimulai setelah beberapa baris ambang maka Anda dapat menggunakan kode berikut,
file = open("files.txt","r")
lines = file.readlines() ## convert to list of lines
datas = lines[11:] ## raed the specific lines
Memberikan hasil yang salah, karena Anda tidak dapat menggunakan readlines dan readline seperti itu (masing-masing mengubah posisi baca saat ini).
Maaf karena mengabaikan kesalahan BESAR dalam kode pertama saya. Kesalahan telah diperbaiki dan kode saat ini harus berfungsi seperti yang diharapkan. Terima kasih telah menunjukkan kesalahan saya, Roger Pate.
Jawaban:
Jika file yang dibaca besar, dan Anda tidak ingin membaca seluruh file dalam memori sekaligus:
Perhatikan bahwa
i == n-1
untukn
baris ke - th.Dalam Python 2.6 atau yang lebih baru:
sumber
enumerate(x)
menggunakanx.next
, jadi tidak perlu seluruh file dalam memori.big file
.Jawaban cepat:
atau:
Ada solusi yang lebih elegan untuk mengekstraksi banyak baris: linecache (milik "python: cara melompat ke baris tertentu dalam file teks besar?" , Pertanyaan stackoverflow.com sebelumnya).
Mengutip dokumentasi python yang ditautkan di atas:
Ubah
4
ke nomor baris yang Anda inginkan, dan Anda aktif. Perhatikan bahwa 4 akan membawa baris kelima karena penghitungannya berbasis nol.Jika file tersebut mungkin sangat besar, dan menyebabkan masalah saat dibaca ke dalam memori, mungkin ide yang baik untuk mengambil saran @ Alok dan menggunakan enumerate () .
Untuk menyimpulkan:
fileobject.readlines()
ataufor line in fileobject
sebagai solusi cepat untuk file kecil.linecache
untuk solusi yang lebih elegan, yang akan cukup cepat untuk membaca banyak file, mungkin berulang kali.enumerate()
untuk file yang bisa sangat besar, dan tidak akan masuk ke dalam memori. Perhatikan bahwa menggunakan metode ini mungkin lambat karena file dibaca berurutan.sumber
linecache
modul, dan sepertinya membaca seluruh file di memori. Jadi, jika akses acak lebih penting daripada optimasi ukuran,linecache
adalah metode terbaik.linecache
sekarang tampaknya hanya berfungsi untuk file sumber pythonlinecache.getlines('/etc/passwd')[0:4]
untuk membaca di baris pertama, kedua, ketiga dan keempat.Pendekatan yang cepat dan ringkas dapat:
ini menerima objek seperti file terbuka
thefile
(menyerahkan kepada pemanggil apakah itu harus dibuka dari file disk, atau melalui misalnya soket, atau aliran file-suka lainnya) dan satu set indeks garis berbasis nolwhatlines
, dan mengembalikan sebuah daftar, dengan jejak memori rendah dan kecepatan wajar. Jika jumlah baris yang dikembalikan besar, Anda mungkin lebih suka generator:yang pada dasarnya hanya baik untuk perulangan - perhatikan bahwa satu - satunya perbedaan berasal dari menggunakan kurung bulat daripada tanda kurung di
return
pernyataan, membuat daftar pemahaman dan ekspresi generator masing-masing.Catatan lebih lanjut bahwa meskipun disebutkan "baris" dan "file" fungsi-fungsi ini banyak, banyak lebih umum - mereka akan bekerja pada setiap iterable, baik itu file terbuka atau lainnya, kembali daftar (atau generator) item berdasarkan nomor-item progresif mereka. Jadi, saya sarankan menggunakan nama-nama umum yang lebih tepat ;-).
sumber
whatlines
harus aset
, karenaif i in whatlines
akan mengeksekusi lebih cepat dengan set daripada daftar (diurutkan). Saya tidak memperhatikannya terlebih dahulu dan malah menemukan solusi jelek saya sendiri dengan daftar terurut (di mana saya tidak perlu memindai daftar setiap kali, sementaraif i in whatlines
melakukan hal itu), tetapi perbedaan kinerja dapat diabaikan (dengan data saya) dan ini solusi jauh lebih elegan.Demi menawarkan solusi lain:
Saya harap ini cepat dan mudah :)
sumber
jika Anda ingin saluran 7
sumber
close()
file saat membukanya dengan cara ini?Demi kelengkapan, berikut adalah satu opsi lagi.
Mari kita mulai dengan definisi dari python docs :
Meskipun notasi irisan tidak langsung berlaku untuk iterator secara umum,
itertools
paket berisi fungsi penggantian:Keuntungan tambahan dari fungsi ini adalah ia tidak membaca iterator sampai akhir. Jadi Anda dapat melakukan hal-hal yang lebih kompleks:
Dan untuk menjawab pertanyaan awal:
sumber
Membaca file sangat cepat. Membaca file 100MB membutuhkan waktu kurang dari 0,1 detik (lihat artikel saya Membaca dan Menulis File dengan Python ). Karenanya Anda harus membacanya sepenuhnya dan kemudian bekerja dengan satu baris.
Apa yang paling banyak dilakukan di sini bukanlah salah, tetapi gaya yang buruk. Membuka file harus selalu dilakukan
with
karena memastikan bahwa file ditutup kembali.Jadi Anda harus melakukannya seperti ini:
File besar
Jika Anda memiliki file yang besar dan konsumsi memori menjadi masalah, Anda dapat memprosesnya baris demi baris:
sumber
Beberapa di antaranya indah, tetapi bisa dilakukan lebih sederhana:
Itu akan menggunakan daftar slicing, memuat seluruh file, tetapi sebagian besar sistem akan meminimalkan penggunaan memori dengan tepat, lebih cepat dari sebagian besar metode yang diberikan di atas, dan bekerja pada file data 10G + saya. Semoga berhasil!
sumber
Anda dapat melakukan pencarian () yang menempatkan kepala baca Anda ke byte yang ditentukan dalam file. Ini tidak akan membantu Anda kecuali jika Anda tahu persis berapa banyak byte (karakter) yang ditulis dalam file sebelum baris yang ingin Anda baca. Mungkin file Anda benar-benar diformat (setiap baris adalah X jumlah byte?) Atau, Anda dapat menghitung sendiri jumlah karakter (ingat untuk memasukkan karakter yang tidak terlihat seperti jeda baris) jika Anda benar-benar menginginkan peningkatan kecepatan.
Jika tidak, Anda harus membaca setiap baris sebelum baris yang Anda inginkan, sesuai salah satu dari banyak solusi yang sudah diusulkan di sini.
sumber
Jika file teks besar Anda
file
terstruktur dengan baik (artinya setiap baris memiliki panjang yang samal
), Anda dapat menggunakan untukn
-th linePenafian Ini hanya berfungsi untuk file dengan panjang yang sama!
sumber
Bagaimana dengan ini:
sumber
Jika Anda tidak keberatan mengimpor maka fileinput melakukan apa yang Anda butuhkan (ini adalah Anda dapat membaca nomor baris dari baris saat ini)
sumber
sumber
Saya lebih suka pendekatan ini karena lebih umum, yaitu Anda dapat menggunakannya pada file, pada hasil
f.readlines()
, padaStringIO
objek, apa pun:sumber
Inilah 2 sen kecil saya, untuk apa nilainya;)
sumber
Perubahan yang lebih baik dan kecil untuk jawaban Alok Singhal
sumber
Objek file memiliki metode .readlines () yang akan memberi Anda daftar konten file, satu baris per item daftar. Setelah itu, Anda bisa menggunakan teknik mengiris daftar normal.
http://docs.python.org/library/stdtypes.html#file.readlines
sumber
@OP, Anda bisa menggunakan enumerate
sumber
Menggunakan pernyataan with, ini membuka file, mencetak baris 26 dan 30, lalu menutup file. Sederhana!
sumber
readlines()
iterator akan habis dan panggilan kedua akan mengembalikan daftar kosong atau membuat kesalahan (tidak ingat yang mana)Anda dapat melakukan ini dengan sangat sederhana dengan sintaksis yang telah disebutkan oleh seseorang, tetapi ini adalah cara termudah untuk melakukannya:
sumber
Untuk mencetak baris # 3,
Penulis asli: Frank Hofmann
sumber
Cukup cepat dan to the point.
Untuk mencetak baris tertentu dalam file teks. Buat daftar "lines2print" dan kemudian cetak ketika enumerasi "di" daftar lines2print. Untuk menghilangkan '\ n' tambahan gunakan line.strip () atau line.strip ('\ n'). Saya hanya suka "daftar pemahaman" dan coba gunakan ketika saya bisa. Saya suka metode "with" untuk membaca file teks untuk mencegah membiarkan file terbuka karena alasan apa pun.
atau jika daftar kecil ketik saja daftar sebagai daftar ke dalam pemahaman.
sumber
Untuk mencetak garis yang diinginkan. Untuk mencetak garis di atas / di bawah garis yang diperlukan.
jalankan ----> dline ("D: \ dummy.txt", 6) yaitu dline ("path file", line_number, jika Anda ingin baris atas dari garis yang dicari berikan 1 untuk lebih rendah -1 ini adalah nilai default opsional akan diambil 0)
sumber
Jika Anda ingin membaca baris tertentu, seperti baris yang dimulai setelah beberapa baris ambang maka Anda dapat menggunakan kode berikut,
file = open("files.txt","r") lines = file.readlines() ## convert to list of lines datas = lines[11:] ## raed the specific lines
sumber
sumber
Saya pikir ini akan berhasil
sumber