Как получить количество строк большого файла дешево в Python?

1012

Мне нужно получить количество строк большого файла (сотни тысяч строк) в Python. Как наиболее эффективно использовать память и время?

На данный момент я делаю:

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

Можно ли сделать что-то лучше?

SilentGhost
источник
7
Вам нужно точное количество строк или будет достаточно приближения?
Pico
43
Я бы добавил i = -1 перед циклом for, так как этот код не работает для пустых файлов.
Maciek Sawicki
12
@Legend: держу пари, пико думает, получи размер файла (с поиском (0,2) или эквивалентом), раздели на приблизительную длину строки. Вы можете прочитать несколько строк в начале, чтобы угадать среднюю длину строки.
Энн
32
enumerate(f, 1)а угробить i + 1?
Ян Маккиннон
4
@IanMackinnon Работает для пустых файлов, но вы должны инициализировать i до 0 перед циклом for.
Scai

Ответы:

357

Вы не можете стать лучше, чем это.

В конце концов, любое решение должно будет прочитать весь файл, выяснить, сколько у \nвас есть, и вернуть этот результат.

У вас есть лучший способ сделать это, не читая весь файл? Не уверен ... Лучшее решение всегда будет связано с вводом / выводом, лучшее, что вы можете сделать, - это убедиться, что вы не используете ненужную память, но похоже, что вы это покрыли.

Ювал Адам
источник
7
Точно, даже WC читает файл, но в C, и он, вероятно, довольно оптимизирован.
Олафур Вааге
6
Насколько я понимаю, ввод-вывод файла Python также осуществляется через C. docs.python.org/library/stdtypes.html#file-objects
Томалак
9
@ Томалак Это красная сельдь. Хотя python и wc могут выдавать одни и те же системные вызовы, python имеет накладные расходы на отправку кода операции, которых нет у wc.
bobpoekert
4
Вы можете приблизить количество строк путем выборки. Это может быть в тысячи раз быстрее. Смотрите: documentroot.com/2011/02/…
Эрик Аронести
4
Другие ответы, по-видимому, указывают на то, что этот категорический ответ является неправильным, и поэтому должен быть удален, а не сохранен как принятый.
Skippy le Grand Gourou
625

Одна строка, вероятно, довольно быстро:

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
когда мы открываем файл, будет ли он автоматически закрываться после итерации по всем элементам? Требуется ли закрыть ()? Я думаю, что мы не можем использовать 'с open ()' в этом коротком утверждении, верно?
Маннаджия
16
@Mannaggia, вы правы, было бы лучше использовать 'с открытым (имя файла)', чтобы убедиться, что файл закрывается, когда закончите, и еще лучше делать это в блоке try-Кроме, где исключение и IOError генерируется, если файл не может быть открыт.
BoltzmannBrain
17
Еще одна вещь, на которую стоит обратить внимание: это примерно на 0,04-0,05 секунды медленнее, чем та, которую исходная проблема дала текстовому файлу на 300 тысяч строк
Эндрю
202

Я считаю, что файл с отображением в памяти будет самым быстрым решением. Я попробовал четыре функции: функция, опубликованная OP ( opcount); простая итерация по строкам в файле ( simplecount); readline с полем с отображением в память (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
Райан Гинстром
1
Извините, вот более общая ссылка на файлы с отображением в памяти: en.wikipedia.org/wiki/Memory-mapped_file И спасибо за голосование. :)
Райан Гинстрем
1
Хотя это всего лишь виртуальная память, именно это ограничивает этот подход, и поэтому он не будет работать для больших файлов. Я пробовал это с файлом ~ 1,2 Гб с более чем 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 +, и ваши rawgencounts - единственное возможное решение, которое я видел до сих пор. Спасибо!
soungalo
1
находится wccountв этой таблице для wcинструмента оболочки подпроцесса ?
Anentropic
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/…
Олафур Вааге
7
Действительно, в моем случае (Mac OS X) это требует 0,13 с против 0,5 с для подсчета количества строк, которые производит «для x в файле (...)», по сравнению с 1,0 с подсчетом повторных вызовов str.find или mmap.find , (Файл я использовал , чтобы проверить это имеет 1,3 миллиона строк.)
Бендин
1
Нет необходимости задействовать оболочку на этом. отредактировал ответ и добавил пример кода;
Носкло
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 ) )
Martlark
источник
Как это работает с файлами намного больше, чем основная память? например, файл размером 20 ГБ в системе с 4 ГБ ОЗУ и 2 ядрами
Брайан Минтон,
Сейчас это сложно проверить, но я предполагаю, что файл будет выгружен и выгружен.
Мартларк
5
Это довольно аккуратный код. Я был удивлен, обнаружив, что быстрее использовать несколько процессоров. Я полагал, что IO будет узким местом. В старых версиях Python для строки 21 требуется int (), например chunk = int ((fSize / process)) + 1
Карл Хенселин,
загрузить все файлы в память? а как насчет пожара, размер которого больше, чем у компьютера?
Пелос
Файлы отображаются в виртуальную память, поэтому размер файла и объем фактической памяти обычно не являются ограничением.
Martlark
17

Однострочное решение bash, аналогичное этому ответу , с использованием современной subprocess.check_outputфункции:

def line_count(filename):
    return int(subprocess.check_output(['wc', '-l', filename]).split()[0])
1 ''
источник
За этот ответ следует проголосовать до более высокого места в этой теме для пользователей Linux / Unix. Несмотря на большинство предпочтений в кроссплатформенном решении, это превосходный способ для Linux / Unix. Для файла CSV из 184 миллионов строк, из которого мне нужно взять данные, он обеспечивает наилучшее время выполнения. Другие чисто Python-решения занимают в среднем более 100 секунд, тогда как вызов подпроцесса wc -lзанимает ~ 5 секунд.
Шань Доу
shell=Trueэто плохо для безопасности, лучше избегать этого.
Алексей Важнов
Fair point, отредактировано
1 ''
15

Я бы использовал метод файлового объекта Python readlinesследующим образом:

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

Это откроет файл, создаст список строк в файле, посчитает длину списка, сохранит ее в переменной и снова закроет файл.

Дэниел Ли
источник
6
Хотя это один из первых способов, который приходит на ум, он, вероятно, не очень эффективно использует память, особенно если считать строки в файлах до 10 ГБ (как я), что является примечательным недостатком.
Стин Шютт
@TimeSheep Является ли это проблемой для файлов с большим количеством (скажем, миллиардов) маленьких строк или файлов с очень длинными строками (скажем, гигабайт в строке)?
Роберт
Причина, по которой я спрашиваю, заключается в том, что компилятор должен иметь возможность оптимизировать это, не создавая промежуточный список.
Роберт
@dmityugov На Python docs xreadlinesустарел с 2.3, так как он просто возвращает итератор. for line in fileэто заявленная замена. См. Docs.python.org/2/library/stdtypes.html#file.xreadlines
Кумба,
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
PKIT
источник
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])

ОБНОВЛЕНИЕ: Это немного быстрее, чем использование чистого Python, но за счет использования памяти. Подпроцесс запустит новый процесс с тем же объемом памяти, что и родительский процесс, пока он выполняет вашу команду.

radtek
источник
1
Как примечание, это не будет работать на Windows, конечно.
Брэм Ванрой
Основные утилиты, по-видимому, предоставляют «wc» для windows stackoverflow.com/questions/247234/… . Вы также можете использовать виртуальную машину Linux в вашем Windows-окне, если ваш код будет работать в Linux в Prod.
Радтек
Или WSL, настоятельно рекомендуется для любой виртуальной машины, если подобные вещи - единственное, что вы делаете. :-)
Брэм Ванрой
Да, это работает. Я не специалист по Windows, но из новичков я выучил WSL = Windows Subsystem для 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% быстрее, чем что-либо еще.

jeffpkamp
источник
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 вне цикла, если buffer и buffer [-1]! = '\ N'
ryuusenshi
Ошибка: буфер в последнем раунде может быть не чистым.
Джей
что если между буферами одна часть заканчивается на \, а другая часть начинается на 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
ChillarAnand
источник
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() в переменную и обработать их так или иначе.
Се
@ Так что вы правы, но не задается вопрос, сохраняет это или нет. Я думаю, вы понимаете контекст.
TheExorcist
6

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

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

И передал файл 60-миллиметровых строк всем вышеупомянутым методам:

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

Для меня немного удивительно, что fileinput настолько плох и масштабируется гораздо хуже, чем все остальные методы ...

ширина зазора
источник
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.
ДФ.
Что если последняя строка не заканчивается на '\ n'?
tzot
1
Я не знаю, как вы это проверили, дф, но на моей машине это примерно в 2,5 раза медленнее, чем любой другой вариант.
SilentGhost
34
Вы заявляете, что он будет самым быстрым, а затем заявляете, что вы его не тестировали. Не очень научно, а? :)
Олафур Вааге
Смотрите решение и статистику, предоставленную ответом Райана Гинстрома ниже. Также проверьте комментарий JF Sebastian и ссылку на тот же ответ.
SherylHohman
5

Этот код короче и понятнее. Это, наверное, лучший способ:

num_lines = open('yourfile.ext').read().count('\n')
Texom512
источник
6
Вы также должны закрыть файл.
rsm
6
Это загрузит весь файл в память.
Ивелин
не лучше, когда требуется производительность на больших файлах
Мабрахам
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()
odwl
источник
3

count = max(enumerate(open(filename)))[0]

pyanon
источник
Это дает счет -1 истинного значения.
Borealis
Необязательный второй аргумент для enumerate()- это начальное количество в соответствии с docs.python.org/2/library/functions.html#enumerate
MarkHu
3
print open('file.txt', 'r').read().count("\n") + 1
Андрес Торрес
источник
3
def line_count(path):
    count = 0
    with open(path) as lines:
        for count, l in enumerate(lines, start=1):
            pass
    return count
mdwhatcott
источник
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
onetwopunch
источник
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
источник
Не могли бы вы объяснить, что с ним не так, если вы думаете, что это неправильно? Это сработало для меня. Спасибо!
Jciloa
Мне было бы интересно узнать, почему этот ответ также был отклонен. Он перебирает файл по строкам и суммирует их. Мне это нравится, оно короткое и, кстати, что с ним не так?
ассистент
2

Простой метод:

1)

>>> f = len(open("myfile.txt").readlines())
>>> f

430

2)

>>> f = open("myfile.txt").read().count('\n')
>>> f
430
>>>

3)

num_lines = len(list(open('myfile.txt')))
Мохидин бен Мухаммед
источник
3
В этом примере файл не закрыт.
Мацей М
9
ОП хотел что-то эффективное для памяти. Это точно не так.
Энди Карлсон
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?
Moi
0

Если файл может поместиться в памяти, то

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
Картик
источник