Python-да үлкен файлды оқудың жалған әдісі?

Менде үлкен 4 ГБ файл бар, мен оны оқып көрген кезде компьютерім қатып қалады. Сондықтан оны бөліктерде оқып, әрбір бөлікті өңдегеннен кейін өңделетін бөлімді басқа файлға сақтап, келесі бөлімді оқып шығыңыз.

Бұл үзінділерді алудың қандай да бір тәсілі бар ма?

Мен жалқау әдіс алғым келеді.

196
06 февр. Pratik Deoghare сұрады 06 ақп. 2009-02-06 12:11 '09 at 12:11 2009-02-06 12:11
@ 11 жауап

Жалқау функция жазу үшін жай yield пайдаланыңыз:

 def read_in_chunks(file_object, chunk_size=1024): """Lazy function (generator) to read a file piece by piece. Default chunk size: 1k.""" while True: data = file_object.read(chunk_size) if not data: break yield data f = open('really_big_file.dat') for piece in read_in_chunks(f): process_data(piece) 

Тағы бір нұсқа - iter және қосалқы функцияны пайдалану:

 f = open('really_big_file.dat') def read1k(): return f.read(1024) for piece in iter(read1k, ''): process_data(piece) 

Егер файл - жол болса, онда файлдық объект қазірдің өзінде жалған жол генераторы болып табылады:

 for line in open('really_big_file.dat'): process_data(line) 
293
06 февр. Жауап nosklo берілді 06 ақп. 2009-02-06 12:20 '09 в 12:20 2009-02-06 12:20

Егер сіздің компьютеріңіз, OS және Python 64-бит болса , файлдың мазмұнын жадында көрсету үшін индекстер мен тілдер арқылы қол жеткізу үшін mmap модулін қолдануға болады. Құжаттағы мысал:

 import mmap with open("hello.txt", "r+") as f: # memory-map the file, size 0 means whole file map = mmap.mmap(f.fileno(), 0) # read content via standard file methods print map.readline() # prints "Hello Python!" # read content via slice notation print map[:5] # prints "Hello" # update content using slice notation; # note that new content must have same size map[6:] = " world!\n" # ... and read again using standard file methods map.seek(0) print map.readline() # prints "Hello world!" # close the map map.close() 
border=0

Егер сіздің компьютеріңіз, OS немесе Python 32-бит болса , онда үлкен файлдар мекенжай кеңістігінің үлкен бөлігін резервтей алады және бағдарлама жадына ашылады.

24
06 февр. Жауап 06-ші ақпанға дейін белгісіз. 2009-02-06 12:41 '09 at 12:41 2009-02-06 12:41

file.readlines () қайтарылған жолдарда оқылатын жолдардың санын жуатын қосымша өлшемді дәлелді қабылдайды.

 bigfile = open('bigfilename','r') tmp_lines = bigfile.readlines(BUF_SIZE) while tmp_lines: process([line for line in tmp_lines]) tmp_lines = bigfile.readlines(BUF_SIZE) 
23
21 янв. жауап 21-қаңтарда Anshul берген 2010-01-21 21:27 '10 at 21:27 2010-01-21 21:27

Бұл лауазымға Neopythonic-те қараңыз : «Python арқылы миллиондаған 32-биттік бүтін сандарды 2 Мб жедел жіктеу »

17
06 февр. Паоло Тедескодың жауабы - 06 ақп. 2009-02-06 12:28 '09 оның 12:28 2009-02-06 12:28

Көптеген жақсы жауаптар бар, бірақ соңғы уақытта маған ұқсас мәселе туындады, және маған қажет шешімді осында көрсетуге болмайды, сондықтан осы ағынға толықтыруды шештім.

Уақыттың 80% -ы, файлдарды жолдармен оқып шығуым керек. Содан кейін, бұл ұсынылғандай, файлды ленивый файл генераторы ретінде пайдаланғыңыз келеді:

 with open('big.csv') as f: for line in f: process(line) 

Дегенмен, жақында мен өте үлкен (дерлік) жалғыз csv сызығымен кездестім, онда сызық бөлгіші іс жүзінде '\n' , бірақ '|' .

  • Желі бойынша оқу жолы опция болмады, бірақ мен оны сызық бойынша өңдеуге тура келді.
  • '|' Түрлендіру өңдеуден бұрын '\n' де сұрақтың сыртында болмауы мүмкін, себебі осы CSV өрістерінің кейбіреулері '\n' (пайдаланушы мәтінін еркін енгізу) қамтылған.
  • Csv кітапханасын пайдалану да алынып тасталды, өйткені кем дегенде бұрынғы нұсқалардағы бастапқы кодтар кіріс жолын оқуға қиындық туғызады .

Мен келесі үзіндімен келдім:

 def rows(f, chunksize=1024, sep='|'): """ Read a file where the row separator is '|' lazily. Usage: >>> with open('big.csv') as f: >>> for r in rows(f): >>> process(row) """ incomplete_row = None while True: chunk = f.read(chunksize) if not chunk: # End of file if incomplete_row is not None: yield incomplete_row break # Split the chunk as long as possible while True: i = chunk.find(sep) if i == -1: break # If there is an incomplete row waiting to be yielded, # prepend it and set it back to None if incomplete_row is not None: yield incomplete_row + chunk[:i] incomplete_row = None else: yield chunk[:i] chunk = chunk[i+1:] # If the chunk contained no separator, it needs to be appended to # the current incomplete row. if incomplete_row is not None: incomplete_row += chunk else: incomplete_row = chunk 

Мен оны үлкен файлдарға және әртүрлі блоктық өлшемдерге сәтті түрде сынап көрдім (тіпті алгоритм өлшемге байланысты емес екенін тексеру үшін 1 байтты бөлуге тырыстым).

9
11 июня '15 в 11:23 2015-06-11 11:23 жауап 11- ші маусымның 11-і сағат 11 :23-да болады
 f = ... # file-like object, ie supporting read(size) function and # returning empty string '' when there is nothing to read def chunked(file, chunk_size): return iter(lambda: file.read(chunk_size), '') for data in chunked(f, 65536): # process the data 

UPDATE: тәсілі ең жақсы түсіндіріледі solopackaging.ru.site/questions/32675 / ...

8
31 марта '12 в 4:50 2012-03-31 04:50 жауапты мирослав 31 наурызда сағат 4: 50-те келтіреді 2012-03-31 04:50

Менің ойымша, бұл туралы жаза аламыз:

 def read_file(path, block_size=1024): with open(path, 'rb') as f: while True: piece = f.read(block_size) if piece: yield piece else: return for piece in read_file(path): process_piece(piece) 
2
06 нояб. Бұл сұраққа жауап TonyCoolZhu 06 қараша. 2013-11-06 05:15 '13 at 5:15 pm 2013-11-06 05:15

Мен төмен беделімнің арқасында түсініктеме беруге рұқсат бермеймін, бірақ SilentGhosts шешімі файлдар файлдарымен оңай болуы керек file.readlines ([sizehint])

python файл әдісі

өңдеу: SilentGhost дұрыс, бірақ жақсы болуы керек:

 s = "" for i in xrange(100): s += file.next() 
1
06 февр. жауап 06 қар. 2009-02-06 13:37 '09 сағат 13:37 2009-02-06 13:37

Мен осындай жағдайдамын. Блоктың өлшемін байттарда білесің бе, анық емес; Мен әдетте бұл туралы білмеймін, бірақ талап етілетін жазбалардың (сызбалардың) саны белгілі:

 def get_line(): with open('4gb_file') as file: for i in file: yield i lines_required = 100 gen = get_line() chunk = [i for i, j in zip(gen, range(lines_required))] 

Жаңарту : алғыс nosklo. Мен осылай ойладым. Ол дерлік жұмыс істейді, тек қана бөліктер арасындағы сызықты жоғалтады.

 chunk = [next(gen) for i in range(lines_required)] 

Кез-келген жолды жоғалтпай-ақ қиянат жасаңыз, бірақ бұл өте жақсы көрінбейді.

1
06 февр. жауап SilentGhost 06 ақпанда берілді. 2009-02-06 13:12 '09 at 13:12 2009-02-06 13:12

Желіні сызықпен өңдеу үшін бұл талғампаз шешім:

  def stream_lines(file_name): file = open(file_name) while True: line = file.readline() if not line: file.close() break yield line 

Бос жолдар әлі жоқ.

0
02 мая '12 в 2:12 2012-05-02 02:12 жауап crizCraig 02 мамыр '12 сағат 2:12 2012-05-02 02:12 беріледі

Келесі кодты пайдалануға болады.

 file_obj = open('big_file') 

open () файлдық нысанды қайтарады

содан кейін өлшемді алу үшін os.stat пайдаланыңыз

 file_size = os.stat('big_file').st_size for i in range( file_size/1024): print file_obj.read(1024) 
-1
18 июня '15 в 16:20 2015-06-18 16:20 жауап 18 маусымда сағат 15: 16- да беріледі. 2015-06-18 16:20