(Python) Подсчитывание строк в огромном (> 10 ГБ) файле как можно быстрее
У меня сейчас очень простой script, который подсчитывает строки в текстовом файле с помощью enumerate()
:
i = 0
f = open("C:/Users/guest/Desktop/file.log", "r")
for i, line in enumerate(f):
pass
print i + 1
f.close()
Это займет около трех с половиной минут, чтобы просмотреть файл журнала размером 15 ГБ с ~ 30 миллионами строк. Было бы здорово, если бы я мог получить это менее двух минут или меньше, потому что это ежедневные журналы, и мы хотим провести ежемесячный анализ, поэтому код должен обработать 30 журналов ~ 15 ГБ - более полутора часов, возможно, и мы хотели бы свести к минимуму время и нагрузку на память на сервере.
Я бы также согласился на хороший метод приближения/оценки, но он должен быть примерно 4 сиг-фига точной...
Спасибо!
Ответы
Ответ 1
Ответ Ignacio является правильным, но может завершиться неудачно, если у вас есть 32-битный процесс.
Но, может быть, было бы полезно прочитать файл по блоку, а затем подсчитать символы \n
в каждом блоке.
def blocks(files, size=65536):
while True:
b = files.read(size)
if not b: break
yield b
with open("file", "r") as f:
print sum(bl.count("\n") for bl in blocks(f))
выполнит вашу работу.
Обратите внимание, что я не открываю файл как двоичный, поэтому \r\n
будет преобразован в \n
, сделав подсчет более надежным.
Ответ 2
Я знаю его немного несправедливо, но вы можете это сделать
int(subprocess.check_output("wc -l C:\\alarm.bat").split()[0])
Если вы на окнах Coreutils
Ответ 3
mmap файл и подсчитайте новые строки.
Ответ 4
Я бы добавил gl ответ и запустил его/ее код, используя многопроцессорный модуль Python для более быстрого подсчета:
def blocks(f, cut, size=64*1024): # 65536
start, chunk =cut
iter=0
read_size=int(size)
_break =False
while not _break:
if _break: break
if f.tell()+size>start+chunk:
read_size=int(start+chunk- f.tell() )
_break=True
b = f.read(read_size)
iter +=1
if not b: break
yield b
def get_chunk_line_count(data):
fn, chunk_id, cut = data
start, chunk =cut
cnt =0
last_bl=None
with open(fn, "r") as f:
if 0:
f.seek(start)
bl = f.read(chunk)
cnt= bl.count('\n')
else:
f.seek(start)
for i, bl in enumerate(blocks(f,cut)):
cnt += bl.count('\n')
last_bl=bl
if not last_bl.endswith('\n'):
cnt -=1
return cnt
....
pool = multiprocessing.Pool(processes=pool_size,
initializer=start_process,
)
pool_outputs = pool.map(get_chunk_line_count, inputs)
pool.close() # no more tasks
pool.join()
Это улучшит производительность подсчета в 20 раз.
Я завернул его в script и поместил его в Github.
Ответ 5
Быстрое однострочное решение:
sum((1 for i in open(file_path, 'rb')))
Он должен работать с файлами произвольного размера.