Як дешево отримати лінійку великого файлу в Python?


1010

Мені потрібно отримати кількість рядків великого файлу (сотні тисяч рядків) у python. Що є найбільш ефективним способом пам'яті та часу?

На даний момент я:

def file_len(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

чи можна зробити щось краще?


7
Вам потрібна точна кількість рядків чи буде достатньо наближення?
піко

43
Я раніше додав би i = -1 для циклу, оскільки цей код не працює для порожніх файлів.
Maciek Sawicki

12
@ Легенд: Я думаю, що піко думає, отримайте розмір файлу (з пошуком (0,2) або еквівалентом), розділіть на приблизну довжину рядка. Ви можете прочитати кілька рядків на початку, щоб відгадати середню довжину рядка.
Енн

32
enumerate(f, 1)і рову i + 1?
Ian Mackinnon

4
@IanMackinnon Працює для порожніх файлів, але вам потрібно ініціалізувати i до 0 перед фор -циклом.
scai

Відповіді:


356

Ти не можеш стати кращим за це.

Зрештою, будь-яке рішення доведеться прочитати весь файл, з'ясувати, скільки у \nвас є, і повернути цей результат.

Чи є у вас кращий спосіб зробити це, не читаючи весь файл? Не впевнений ... Найкращим рішенням завжди буде зв’язок вводу / виводу. Найкраще, що ви можете зробити, це переконайтеся, що ви не використовуєте зайву пам'ять, але схоже, що у вас є це.


7
Точно навіть WC читає файл, але в С і, мабуть, досить оптимізований.
flafur Waage

6
Наскільки я розумію, файл файлів Python також виконується через C. docs.python.org/library/stdtypes.html#file-objects
Томалак

9
@Tomalak Це червона оселедець. Незважаючи на те, що python та wc можуть видавати одні й ті ж систематичні виклики, python має накладні диспетчеризації коду, яких у wc немає.
bobpoekert

4
Ви можете наблизити кількість рядків шляхом вибірки. Це може бути в тисячі разів швидше. Дивіться: documentroot.com/2011/02/…
Ерік Аронесті

4
Інші відповіді, схоже, вказують на те, що ця категорична відповідь неправильна, і тому її слід видалити, а не зберігати як прийняту.
Skippy le Grand Gourou

624

Один рядок, напевно, досить швидко:

num_lines = sum(1 for line in open('myfile.txt'))

8
його схожа на суму (послідовність 1), кожен рядок вважається як 1. >>> [1 для рядка в діапазоні (10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> сума (1 для рядка в діапазоні (10)) 10 >>>
Джеймс Сапам

4
num_lines = sum (1 для рядка у відкритому ('myfile.txt'), якщо line.rstrip ()) для фільтрів порожніх рядків
Honghe.Wu

61
Коли ми відкриваємо файл, чи закриється це автоматично, коли ми повторимо всі елементи? Потрібно "закрити ()"? Я думаю, що ми не можемо використовувати "with open ()" у цій короткій заяві, правда?
Mannaggia

16
@Mannaggia ви маєте рацію, було б краще використовувати "з відкритим (ім'я файлу)", щоб переконатися, що файл закривається після завершення, а ще краще - це робити в приміщенні спробувати, крім блоку, куди викидається виняток IOError, якщо файл неможливо відкрити.
BoltzmannBrain

17
Ще одне, що слід зазначити: це ~ 0,04-0,05 секунди повільніше, ніж первісна проблема,
Рядків

202

Я вірю, що файл, який відображається на пам'ять, буде найшвидшим рішенням. Я спробував чотири функції: функцію, розміщену OP ( opcount); проста ітерація рядків у файлі ( simplecount); читальна лінія з поданим на карту пам'яті файлом (mmap) ( mapcount); і рішення для читання буфера, яке пропонував Микола Харечко ( bufcount).

Я виконував кожну функцію п'ять разів і обчислював середній час виконання для 1,2-мільйонного текстового файлу.

Windows XP, Python 2.5, 2 Гб оперативної пам’яті, процесор AMD 2 ГГц

Ось мої результати:

mapcount : 0.465599966049
simplecount : 0.756399965286
bufcount : 0.546800041199
opcount : 0.718600034714

Редагувати : числа для Python 2.6:

mapcount : 0.471799945831
simplecount : 0.634400033951
bufcount : 0.468800067902
opcount : 0.602999973297

Тому стратегія зчитування буфера здається найшвидшою для Windows / Python 2.6

Ось код:

from __future__ import with_statement
import time
import mmap
import random
from collections import defaultdict

def mapcount(filename):
    f = open(filename, "r+")
    buf = mmap.mmap(f.fileno(), 0)
    lines = 0
    readline = buf.readline
    while readline():
        lines += 1
    return lines

def simplecount(filename):
    lines = 0
    for line in open(filename):
        lines += 1
    return lines

def bufcount(filename):
    f = open(filename)                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    return lines

def opcount(fname):
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1


counts = defaultdict(list)

for i in range(5):
    for func in [mapcount, simplecount, bufcount, opcount]:
        start_time = time.time()
        assert func("big_file.txt") == 1209138
        counts[func].append(time.time() - start_time)

for key, vals in counts.items():
    print key.__name__, ":", sum(vals) / float(len(vals))

1
Весь файл, відображений на пам'ять, не завантажується в пам'ять. Ви отримуєте віртуальний простір пам’яті, який ОС заміняється на оперативну пам’ять і виходить з неї. Ось як вони обробляються в Windows: msdn.microsoft.com/en-us/library/ms810613.aspx
Ryan Ginstrom

1
Вибачте, ось більш загальна посилання на файли з картою пам'яті: en.wikipedia.org/wiki/Memory-mapped_file І дякую за голос. :)
Райан Гінстром

1
Незважаючи на те, що це просто віртуальна пам'ять, саме це обмежує цей підхід, і тому він не працюватиме для величезних файлів. Я спробував це з файлом ~ 1,2 Gb з понад 10 млн. Грн. рядки (як отримано за допомогою wc -l) та щойно отримали WindowsError: [Помилка 8] Недостатньо місця для оброблення цієї команди. звичайно, це крайній випадок.
SilentGhost

6
+1 для реальних даних про терміни. Чи знаємо ми, чи розмір буфера 1024 * 1024 є оптимальним, чи є кращий?
Ків

28
Здається, wccount()це найшвидший gist.github.com/0ac760859e614cd03652
jfs

133

Мені довелося розмістити це на подібному питанні, поки мій показник репутації трохи не підскочив (дякую тому, хто мене натрапив!).

Усі ці рішення ігнорують один із способів зробити цей запуск значно швидшим, а саме за допомогою розблокованого (необробленого) інтерфейсу, використання байтарейних масивів та власного буферизації. (Це стосується лише Python 3. У Python 2 необроблений інтерфейс може використовуватися або не використовуватись за замовчуванням, але в Python 3 ти будеш типово встановлений у Unicode.)

Використовуючи модифіковану версію інструменту синхронізації, я вважаю, що наступний код швидший (і дещо пітонічніший), ніж будь-яке із запропонованих рішень:

def rawcount(filename):
    f = open(filename, 'rb')
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.raw.read

    buf = read_f(buf_size)
    while buf:
        lines += buf.count(b'\n')
        buf = read_f(buf_size)

    return lines

Використовуючи окрему функцію генератора, цей запуск швидше:

def _make_gen(reader):
    b = reader(1024 * 1024)
    while b:
        yield b
        b = reader(1024*1024)

def rawgencount(filename):
    f = open(filename, 'rb')
    f_gen = _make_gen(f.raw.read)
    return sum( buf.count(b'\n') for buf in f_gen )

Це можна зробити повністю з вбудованими виразами генераторів, використовуючи itertools, але він виглядає досить дивно:

from itertools import (takewhile,repeat)

def rawincount(filename):
    f = open(filename, 'rb')
    bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
    return sum( buf.count(b'\n') for buf in bufgen )

Ось мої таймінги:

function      average, s  min, s   ratio
rawincount        0.0043  0.0041   1.00
rawgencount       0.0044  0.0042   1.01
rawcount          0.0048  0.0045   1.09
bufcount          0.008   0.0068   1.64
wccount           0.01    0.0097   2.35
itercount         0.014   0.014    3.41
opcount           0.02    0.02     4.83
kylecount         0.021   0.021    5.05
simplecount       0.022   0.022    5.25
mapcount          0.037   0.031    7.46

20
Я працюю з файлами 100Gb +, і ваші рахунки необмеженого користування - єдине можливе рішення, яке я бачив досі. Дякую!
soungalo

1
знаходиться wccountв цій таблиці для подпроцесса оболонки wcінструменту?
Анентропік

1
знайшов це в іншому коментарі, я думаю, це тоді gist.github.com/zed/0ac760859e614cd03652
Anentropic

3
Дякуємо @ michael-bacon, це дійсно приємне рішення. Ви можете зробити rawincountрішення менш дивним на вигляд, використовуючи bufgen = iter(partial(f.raw.read, 1024*1024), b'')замість комбінування takewhileта repeat.
Пітер Х.

1
О, часткова функція, так, це приємна маленька настройка. Крім того, я припускав, що інтерпретатор 1024 * 1024 буде злитий і трактується як константа, але це було на увазі не документацією.
Майкл Бекон

90

Ви можете виконати підпроцес і запустити wc -l filename

import subprocess

def file_len(fname):
    p = subprocess.Popen(['wc', '-l', fname], stdout=subprocess.PIPE, 
                                              stderr=subprocess.PIPE)
    result, err = p.communicate()
    if p.returncode != 0:
        raise IOError(err)
    return int(result.strip().split()[0])

6
яка б це була версія Windows?
SilentGhost

1
Ви можете звернутися до цього питання щодо цього. stackoverflow.com/questions/247234/…
Ólafur Waage

7
Дійсно, у моєму випадку (Mac OS X) для підрахунку кількості рядків "для x у файлі (...)" потрібно 0,13s проти 0,5s, а підрахунок повторних дзвінків на str.find або mmap.find . (Файл, який я використовував для тестування, має 1,3 мільйона рядків.)
bendin

1
Не потрібно залучати оболонку до цього. відредагована відповідь та доданий приклад код;
nosklo

2
Не є крос-платформою.
e-info128

42

Ось програма python для використання багатопроцесорної бібліотеки для розподілу підрахунку рядків по машинам / ядрам. Мій тест покращує підрахунок 20-мільйонного файлу рядків від 26 секунд до 7 секунд за допомогою 8-ядерного сервера Windows 64. Примітка: не використання карти пам'яті робить ситуацію набагато повільнішою.

import multiprocessing, sys, time, os, mmap
import logging, logging.handlers

def init_logger(pid):
    console_format = 'P{0} %(levelname)s %(message)s'.format(pid)
    logger = logging.getLogger()  # New logger at root level
    logger.setLevel( logging.INFO )
    logger.handlers.append( logging.StreamHandler() )
    logger.handlers[0].setFormatter( logging.Formatter( console_format, '%d/%m/%y %H:%M:%S' ) )

def getFileLineCount( queues, pid, processes, file1 ):
    init_logger(pid)
    logging.info( 'start' )

    physical_file = open(file1, "r")
    #  mmap.mmap(fileno, length[, tagname[, access[, offset]]]

    m1 = mmap.mmap( physical_file.fileno(), 0, access=mmap.ACCESS_READ )

    #work out file size to divide up line counting

    fSize = os.stat(file1).st_size
    chunk = (fSize / processes) + 1

    lines = 0

    #get where I start and stop
    _seedStart = chunk * (pid)
    _seekEnd = chunk * (pid+1)
    seekStart = int(_seedStart)
    seekEnd = int(_seekEnd)

    if seekEnd < int(_seekEnd + 1):
        seekEnd += 1

    if _seedStart < int(seekStart + 1):
        seekStart += 1

    if seekEnd > fSize:
        seekEnd = fSize

    #find where to start
    if pid > 0:
        m1.seek( seekStart )
        #read next line
        l1 = m1.readline()  # need to use readline with memory mapped files
        seekStart = m1.tell()

    #tell previous rank my seek start to make their seek end

    if pid > 0:
        queues[pid-1].put( seekStart )
    if pid < processes-1:
        seekEnd = queues[pid].get()

    m1.seek( seekStart )
    l1 = m1.readline()

    while len(l1) > 0:
        lines += 1
        l1 = m1.readline()
        if m1.tell() > seekEnd or len(l1) == 0:
            break

    logging.info( 'done' )
    # add up the results
    if pid == 0:
        for p in range(1,processes):
            lines += queues[0].get()
        queues[0].put(lines) # the total lines counted
    else:
        queues[0].put(lines)

    m1.close()
    physical_file.close()

if __name__ == '__main__':
    init_logger( 'main' )
    if len(sys.argv) > 1:
        file_name = sys.argv[1]
    else:
        logging.fatal( 'parameters required: file-name [processes]' )
        exit()

    t = time.time()
    processes = multiprocessing.cpu_count()
    if len(sys.argv) > 2:
        processes = int(sys.argv[2])
    queues=[] # a queue for each process
    for pid in range(processes):
        queues.append( multiprocessing.Queue() )
    jobs=[]
    prev_pipe = 0
    for pid in range(processes):
        p = multiprocessing.Process( target = getFileLineCount, args=(queues, pid, processes, file_name,) )
        p.start()
        jobs.append(p)

    jobs[0].join() #wait for counting to finish
    lines = queues[0].get()

    logging.info( 'finished {} Lines:{}'.format( time.time() - t, lines ) )

Як це працює з файлами набагато більше, ніж основна пам'ять? наприклад, 20 Гб файл у системі з 4 ГБ оперативної пам’яті та 2 ядрами
Брайан Мінтон

Зараз важко перевірити, але я припускаю, що це дозволить перетворити файл на файл і вийти.
Martlark

5
Це досить акуратний код. Я здивовано виявив, що швидше використовувати декілька процесорів. Я подумав, що вузол буде вузьким місцем. У старих версіях Python для рядка 21 потрібен int (), наприклад, chunk = int ((fSize / процеси)) + 1
Karl Henselin

чи завантажують він весь файл у пам'ять? як щодо більшого пожежі, де розмір більший, ніж баран на комп'ютері?
пелос

Файли відображаються у віртуальній пам'яті, тому розмір файлу та обсяг фактичної пам’яті зазвичай не є обмеженням.
Martlark

17

Однорядковий баш-рішення, подібний до цієї відповіді , використовуючи сучасну subprocess.check_outputфункцію:

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])

Ця відповідь має бути проголосована на вище місце в цій темі для користувачів Linux / Unix. Незважаючи на переваги більшості в кросплатформенному рішенні, це є чудовим способом для Linux / Unix. Для CSV-файлу на 184 мільйони рядків, з якого я повинен відібрати дані, він забезпечує найкращий час виконання. Інші чисті рішення пітона займають в середньому 100+ секунд, тоді як виклик підпроцесу wc -l- 5 секунд.
Shan Dou

shell=Trueце погано для безпеки, краще уникати цього.
Олексій Важнов

Справедливий пункт, відредаговано
1 ''

15

Я б використовував метод файлового об'єкта Python readlinesтаким чином:

with open(input_file) as foo:
    lines = len(foo.readlines())

Це відкриває файл, створює список рядків у файлі, підраховує довжину списку, зберігає його до змінної і знову закриває файл.


6
Хоча це один із перших способів, який спадає на думку, він, мабуть, не дуже ефективний у пам’яті, особливо якщо підрахунок рядків у файлах до 10 Гб (як і я), що є вагомим недоліком.
Стівен Шютт

@TimeSheep Це проблема для файлів з багатьма (скажімо, мільярдами) невеликих рядків або файлів із надзвичайно довгими рядками (скажімо, гігабайт на рядок)?
Роберт

Причина, про яку я запитую, виглядає, що компілятор повинен мати можливість оптимізувати це, не створюючи проміжний список.
Роберт

@dmityugov Документи Per Python xreadlinesзастаріли з 2.3, оскільки він просто повертає ітератор. for line in fileє заявленою заміною. Дивіться: docs.python.org/2/library/stdtypes.html#file.xreadlines
Kumba

12
def file_len(full_path):
  """ Count number of lines in a file."""
  f = open(full_path)
  nr_of_lines = sum(1 for line in f)
  f.close()
  return nr_of_lines

12

Ось те, що я використовую, здається досить чистим:

import subprocess

def count_file_lines(file_path):
    """
    Counts the number of lines in a file using wc utility.
    :param file_path: path to file
    :return: int, no of lines
    """
    num = subprocess.check_output(['wc', '-l', file_path])
    num = num.split(' ')
    return int(num[0])

ОНОВЛЕННЯ: Це незначно швидше, ніж використання чистого пітона, але ціною використання пам'яті. Підпроцес розкладе новий процес з тим самим слідом пам’яті, що і батьківський процес, поки він виконує вашу команду.


1
Як бічна примітка, це, звичайно, не буде працювати в Windows.
Брем

Основні утиліти, очевидно, надають "wc" для Windows stackoverflow.com/questions/247234/… . Ви також можете використовувати Linux VM у вікні Windows, якщо ваш код в кінцевому підсумку працює в linux в prod.
radtek

Або WSL, настійно радимо будь-яку віртуальну машину, якщо подібні речі - це єдине, що ви робите. :-)
Брам

Так, це працює. Я не хлопець з Windows, але з goolging я дізнався WSL = Підсистема Windows для Linux =)
radtek

3
python3.7: повернення байтів підпроцесу, тому код виглядає приблизно так: int (subprocess.check_output (['wc', '-l', file_path]). decode ("utf-8"). lstrip (). split (" ") [0])
Олексій

11

Це найшвидше, що я знайшов, використовуючи чистий пітон. Ви можете використовувати будь-який обсяг пам’яті, який хочете, встановивши буфер, хоча 2 ** 16 здається милим місцем на моєму комп’ютері.

from functools import partial

buffer=2**16
with open(myfile) as f:
        print sum(x.count('\n') for x in iter(partial(f.read,buffer), ''))

Тут я знайшов відповідь Чому читання рядків із stdin набагато повільніше в C ++, ніж у Python? і переробили це просто крихітним шматочком. Це дуже добре читати, щоб зрозуміти, як швидко рахувати рядки, хоча wc -lце все-таки на 75% швидше, ніж все інше.


9

Я отримав невелике (4-8%) поліпшення в цій версії, яка повторно використовує постійний буфер, тому він повинен уникати будь-якої пам'яті або GC накладних витрат:

lines = 0
buffer = bytearray(2048)
with open(filename) as f:
  while f.readinto(buffer) > 0:
      lines += buffer.count('\n')

Ви можете пограти з розміром буфера і, можливо, побачити трохи покращення.


Приємно. Для обліку файлів, які не закінчуються \ n, додайте 1 за межами циклу, якщо буфер і буфер [-1]! = '\ N'
ryuusenshi

Помилка: буфер в останньому раунді може бути нечистим.
Jay

що робити, якщо між буферами одна частина закінчується \, а інша частина починається з n? що там буде пропущений один новий рядок, я б подумав, що змінні зберігатимуть кінець та початок кожного фрагменту, але це може додати більше часу до сценарію = (
pelos

9

Відповідь Кайла

num_lines = sum(1 for line in open('my_file.txt'))

Мабуть, найкраща, альтернатива цьому є

num_lines =  len(open('my_file.txt').read().splitlines())

Ось порівняння продуктивності обох

In [20]: timeit sum(1 for line in open('Charts.ipynb'))
100000 loops, best of 3: 9.79 µs per loop

In [21]: timeit len(open('Charts.ipynb').read().splitlines())
100000 loops, best of 3: 12 µs per loop

9

Рішення з однієї лінії:

import os
os.system("wc -l  filename")  

Мій фрагмент:

>>> os.system('wc -l *.txt')

0 bar.txt
1000 command.txt
3 test_file.txt
1003 total

Хороша ідея, на жаль, це не працює на Windows.
Кім

3
якщо ви хочете бути серфером python, попрощайтеся з windows. Повірте, ви подякуєте мені одного дня.
TheExorcist

6
Я просто вважав примітним, що це буде працювати лише на вікнах. Я вважаю за краще сам працювати над стеком linux / unix, але при написанні програмного забезпечення IMHO слід враховувати побічні ефекти, які може мати програма під час роботи під різними ОС. Оскільки ОП не згадувало про його платформу і, якщо хтось вискакує це рішення через Google і копіює його (не знаючи про обмеження, які може мати система Windows), я хотів додати цю ноту.
Кім

Ви не можете зберегти висновок os.system()змінної та якнайшвидше її обробити.
СЕ

@AnSe ви праві, але питання не задається, економить чи ні. Я думаю, ви розумієте контекст.
TheExorcist

6

Просто для виконання вищевказаних методів я спробував варіант із модулем fileinput:

import fileinput as fi   
def filecount(fname):
        for line in fi.input(fname):
            pass
        return fi.lineno()

І передав файл рядків 60mil до всіх вищезазначених методів:

mapcount : 6.1331050396
simplecount : 4.588793993
opcount : 4.42918205261
filecount : 43.2780818939
bufcount : 0.170812129974

Для мене трохи несподівано, що введення файлів - це погано і масштабується набагато гірше, ніж усі інші методи ...


5

Як на мене, цей варіант буде найшвидшим:

#!/usr/bin/env python

def main():
    f = open('filename')                  
    lines = 0
    buf_size = 1024 * 1024
    read_f = f.read # loop optimization

    buf = read_f(buf_size)
    while buf:
        lines += buf.count('\n')
        buf = read_f(buf_size)

    print lines

if __name__ == '__main__':
    main()

причини: буферизація швидше, ніж читання рядка за рядком, а string.countтакож дуже швидке


1
Але це? Принаймні, на OSX / python2.5 версія OP все ще на 10% швидша, згідно timeit.py.
dF.

Що робити, якщо останній рядок не закінчується на "\ n"?
tzot

1
Я не знаю, як ви його тестували, dF, але на моїй машині це ~ в 2,5 рази повільніше, ніж будь-який інший варіант.
SilentGhost

34
Ви заявляєте, що це буде найшвидше, а потім заявляєте, що ви його не перевіряли. Не дуже науковий так? :)
flafur Waage

Дивіться рішення та статистику, яку надає відповідь Райана Гінстрома нижче. Також ознайомтеся з коментарем Дж. Ф. Себастьяна і посиланням на ту ж відповідь.
SherylHohman

5

Цей код коротший і чіткіший. Це, мабуть, найкращий спосіб:

num_lines = open('yourfile.ext').read().count('\n')

6
Також слід закрити файл.
rsm

6
Він завантажить весь файл в пам'ять.
Івелін

не найкраще, коли потрібна продуктивність на великих файлах
Mabraham

4

Я змінив корпус буфера так:

def CountLines(filename):
    f = open(filename)
    try:
        lines = 1
        buf_size = 1024 * 1024
        read_f = f.read # loop optimization
        buf = read_f(buf_size)

        # Empty file
        if not buf:
            return 0

        while buf:
            lines += buf.count('\n')
            buf = read_f(buf_size)

        return lines
    finally:
        f.close()

Тепер також рахуються порожні файли та останній рядок (без \ n).


Можливо, також поясніть (або додайте у коментарі до коду), що ви змінили і для чого;). Ви можете дати людям ще трохи всередині вашого коду набагато простіше (а не "розбирати" код у мозку).
Styxxy

Оптимізація циклу, я думаю, дозволяє Python робити локальний пошук змінних у read_f, python.org/doc/essays/list2str
The Red Pea

3

Як що до цього

def file_len(fname):
  counts = itertools.count()
  with open(fname) as f: 
    for _ in f: counts.next()
  return counts.next()



3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count

3

Якщо ви хочете отримати дешевий підрахунок рядків у Python в Linux, я рекомендую такий спосіб:

import os
print os.popen("wc -l file_path").readline().split()[0]

file_path може бути як абстрактним шляхом до файлу, так і відносним шляхом. Сподіваюся, це може допомогти.


2

Як щодо цього?

import fileinput
import sys

counter=0
for line in fileinput.input([sys.argv[1]]):
    counter+=1

fileinput.close()
print counter

2

Як щодо цього однолінійного:

file_length = len(open('myfile.txt','r').read().split('\n'))

За допомогою цього методу потрібно 0,003 сек, щоб розмістити його у файлі 3900 рядків

def c():
  import time
  s = time.time()
  file_length = len(open('myfile.txt','r').read().split('\n'))
  print time.time() - s

2
def count_text_file_lines(path):
    with open(path, 'rt') as file:
        line_count = sum(1 for _line in file)
    return line_count

Чи можете ви поясніть, що з цим не так, якщо ви вважаєте, що це неправильно? Це працювало для мене. Дякую!
jciloa

Мені було б цікаво, чому ця відповідь була спростована також. Він повторює файл по рядках і підсумовує їх. Мені це подобається, він короткий і до речі, що з цим погано?
цессор


1

Результатом відкриття файлу є ітератор, який можна перетворити на послідовність, що має довжину:

with open(filename) as f:
   return len(list(f))

це більш стисло, ніж ваш явний цикл, і уникає enumerate.


10
а це означає, що файл в 100 Мб потрібно буде прочитати в пам'яті.
SilentGhost

так, хороший момент, хоча мені цікаво різнитися у швидкості (на відміну від пам’яті). Можливо, можливо створити ітератор, який це робить, але я думаю, це було б рівнозначно вашому рішенню.
Ендрю Яффе

6
-1, це не просто пам’ять, а необхідність побудови списку в пам'яті.
orip

0

Ви можете використовувати os.pathмодуль наступним чином:

import os
import subprocess
Number_lines = int( (subprocess.Popen( 'wc -l {0}'.format( Filename ), shell=True, stdout=subprocess.PIPE).stdout).readlines()[0].split()[0] )

, де Filenameабсолютний шлях до файлу.


1
Що стосується цієї відповіді os.path?
травень

0

Якщо файл може вміститись у пам'яті, то

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.