파이썬에서 큰 파일의 줄 수를 싸게 얻는 방법?


1010

파이썬에서 큰 파일 (수만 줄)의 줄 수를 가져와야합니다. 메모리와 시간 단위로 가장 효율적인 방법은 무엇입니까?

현재 내가하는 일 :

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

더 잘 할 수 있습니까?


7
정확한 라인 수가 필요합니까 아니면 근사치만으로 충분합니까?
pico

43
이 코드는 빈 파일에서는 작동하지 않기 때문에 for 루프 앞에 i = -1을 추가합니다.
Maciek Sawicki

12
@Legend : 피코가 생각하고 파일 크기 (seek (0,2) 또는 equiv 사용)를 가져 와서 대략적인 줄 길이로 나눕니다. 처음에 몇 줄을 읽어 평균 줄 길이를 추측 할 수 있습니다.
Anne

32
enumerate(f, 1)그리고 도랑 i + 1?
Ian Mackinnon 2012

4
@IanMackinnon 빈 파일에서 작동하지만 for 루프 전에 i0 으로 초기화 해야합니다.
scai

답변:


356

당신은 그것보다 더 나아질 수 없습니다.

결국 모든 솔루션은 전체 파일을 읽어야합니다. \n 결과를 반환해야합니다.

전체 파일을 읽지 않고 더 좋은 방법이 있습니까? 확실하지 않습니다 ... 최선의 솔루션은 항상 I / O 바인딩 일 것입니다. 최선의 방법은 불필요한 메모리를 사용하지 않는 것입니다.


7
정확히, WC조차도 파일을 읽고 있지만 C에서는 아마 최적화되어 있습니다.
Ólafur Waage

6
내가 이해하는 한 파이썬 파일 IO는 C를 통해 수행됩니다. docs.python.org/library/stdtypes.html#file-objects
Tomalak

9
@Tomalak 그것은 빨간 청어입니다. python과 wc는 동일한 syscall을 발행 할 수 있지만, python에는 wc에는없는 opcode 디스패치 오버 헤드가 있습니다.
밥포에 커트

4
샘플링하여 줄 수를 대략적으로 계산할 수 있습니다. 수천 배 더 빠를 수 있습니다. 참조 : documentroot.com/2011/02/…
Erik Aronesty

4
다른 답변은이 범주 형 답변이 잘못되었음을 나타내므로 허용 된 상태로 유지하기보다는 삭제해야합니다.
Skippy le Grand Gourou

624

한 줄, 아마도 꽤 빠릅니다.

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

8
모든 라인은 sum (1의 순서)과 유사하며 모든 라인은 1로 계산됩니다. >>> [range (10) 범위의 라인에 대해 1] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> sum (range (10) 범위의 행에 대해 1) 10 >>>
James Sapam 5

4
빈 줄을 필터에 대한 line.rstrip ()) 인 경우 num_lines = sum (1 (open) ( 'myfile.txt')의 줄에 대해
Honghe.Wu

61
파일을 열 때 모든 요소를 ​​반복하면 자동으로 닫히나요? 'close ()'가 필요합니까? 이 짧은 문장에서 'with open ()'을 사용할 수 없다고 생각합니다.
Mannaggia

16
@Mannaggia 당신이 맞다면, 'with open (filename)'을 사용하여 파일이 완료되었을 때 파일을 닫는 것이 더 좋으며 try-except 블록 내 에서이 작업을 수행하는 것이 좋습니다. 파일을 열 수 없습니다.
BoltzmannBrain

17
주목해야 할 또 다른 사항 : 이것은 원래 문제가 3 억 줄의 텍스트 파일에서 제공 한 것보다 ~ 0.04 ~ 0.05 초 느리다
andrew

202

메모리 매핑 파일이 가장 빠른 솔루션이라고 생각합니다. 나는 네 가지 기능을 시도했다 : OP ( opcount) 에 의해 게시 된 기능 ; 파일의 라인들에 대한 간단한 반복 ( simplecount); 메모리 매핑 된 파일 (mmap) ( mapcount) 이있는 판독 선 ; Mykola Kharechko에서 제공하는 버퍼 읽기 솔루션 (bufcount )에서 .

각 기능을 5 번 실행하고 120 만 줄 텍스트 파일의 평균 런타임을 계산했습니다.

Windows XP, Python 2.5, 2GB RAM, 2GHz AMD 프로세서

내 결과는 다음과 같습니다.

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
전체 메모리 매핑 된 파일이 메모리에로드되지 않습니다. 가상 메모리 공간이 생겨 OS가 필요에 따라 RAM으로 또는 RAM에서 스왑합니다. 여기가 Windows에서 처리하는 방법은 다음과 같습니다 msdn.microsoft.com/en-us/library/ms810613.aspx
라이언 Ginstrom

1
죄송합니다. 메모리 매핑 된 파일에 대한보다 일반적인 참조는 다음 과 같습니다. en.wikipedia.org/wiki/Memory-mapped_file 투표 해 주셔서 감사합니다. :)
Ryan Ginstrom 2014 년

1
가상 메모리 일지라도 정확하게이 방법을 제한하는 것이므로 대용량 파일에서는 작동하지 않습니다. 나는 ~ 1.2 Gb 파일로 10 mln 이상 사용해 보았습니다. (wc -l로 얻은) 행에 WindowsError가 발생했습니다. [오류 8]이 명령을 처리하는 데 사용 가능한 스토리지가 충분하지 않습니다. 물론 이것은 엣지 케이스입니다.
SilentGhost

6
실제 타이밍 데이터의 경우 +1 1024 * 1024의 버퍼 크기가 최적인지 또는 더 좋은지 알고 있습니까?
Kiv

28
wccount()가장 빠른 것 같습니다 gist.github.com/0ac760859e614cd03652
jfs

133

나는 나의 명성 점수가 약간 올라갈 때까지 비슷한 질문에 이것을 게시해야했다.

이러한 모든 솔루션은 버퍼링되지 않은 (raw) 인터페이스를 사용하고, 바이트 배열을 사용하고, 자체 버퍼링을 수행하여이 실행을 상당히 빠르게하는 한 가지 방법을 무시합니다. (이것은 Python 3에만 적용됩니다. Python 2에서는 기본 인터페이스가 기본적으로 사용되거나 사용되지 않을 수 있지만 Python 3에서는 기본적으로 유니 코드로 설정됩니다.)

수정 된 버전의 타이밍 도구를 사용하면 다음 코드가 제공되는 솔루션보다 빠릅니다 (그리고 조금 더 많은 파이썬).

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

별도의 생성기 기능을 사용하면 smidge가 더 빠르게 실행됩니다.

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.
피터 H.

1
아, 부분적인 기능입니다. 아주 좋은 조정입니다. 또한 1024 * 1024가 인터프리터에 의해 병합되어 상수로 취급되지만 문서화가 아니라고 가정했습니다.
Michael Bacon

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
그것에 대해이 SO 질문을 참조 할 수 있습니다. stackoverflow.com/questions/247234/…
Ólafur Waage

7
실제로, 내 경우 (Mac OS X) str.find 또는 mmap.find에 대한 반복 호출 수를 계산하는 "file in x (...)"에 대한 x 행 수를 계산하는 데 0.13 초 대 0.5 초가 걸립니다. . (이 파일을 테스트하는 데 사용한 파일은 130 만 줄입니다.)
bendin

1
그것에 껍질을 포함 할 필요가 없습니다. 답변을 수정하고 예제 코드를 추가했습니다.
nosklo

2
크로스 플랫폼이 아닙니다.
e-info128

42

다음은 멀티 프로세싱 라이브러리를 사용하여 머신 / 코어에 라인 수를 분배하는 파이썬 프로그램입니다. 내 테스트는 8 코어 Windows 64 서버를 사용하여 2 천만 줄 파일을 26 초에서 7 초로 세는 것을 향상시킵니다. 참고 : 메모리 매핑을 사용하지 않으면 작업 속도가 훨씬 느려집니다.

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 ) )

주 메모리보다 훨씬 큰 파일에서 어떻게 작동합니까? 예를 들어 4기가바이트 RAM, 2 개 코어 시스템에서 20GB의 파일
브라이언 민튼

지금 테스트하기는 어렵지만 파일을 페이징 및 페이징한다고 가정합니다.
Martlark

5
이것은 매우 깔끔한 코드입니다. 여러 프로세서를 사용하는 것이 더 빠르다는 사실에 놀랐습니다. IO가 병목 현상이 될 것이라고 생각했습니다. 오래된 파이썬 버전에서는 라인 (21 개)의 요구는 = INT ((FSIZE / 프로세스)) + 1 덩어리처럼 (를) int로
칼 Henselin

모든 파일을 메모리에로드합니까? 컴퓨터의 램보다 크기가 큰 더 큰 불은 어떻습니까?
pelos December

파일은 가상 메모리에 매핑되므로 파일 크기와 실제 메모리 양에는 제한이 없습니다.
Martlark

17

현대적인 기능을 사용 하여이 답변 과 비슷한 한 줄 bash 솔루션 subprocess.check_output:

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

이 답변은 Linux / Unix 사용자를 위해이 스레드에서 더 높은 자리에 투표해야합니다. 크로스 플랫폼 솔루션의 기본 설정에도 불구하고 이는 Linux / Unix에서 최상의 방법입니다. 184 만 줄의 CSV 파일의 경우 데이터를 샘플링해야하며 최상의 런타임을 제공합니다. 다른 순수한 파이썬 솔루션은 평균 100 초 이상 wc -l걸리며 하위 프로세스 호출 은 ~ 5 초가 걸립니다.
Shan Dou

shell=True보안이 나쁘면 피하는 것이 좋습니다.
Alexey Vazhnov

공정한 포인트, 편집
1 ''

15

readlines다음과 같이 Python의 파일 객체 메소드 를 사용합니다.

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

파일을 열고 파일에 행 목록을 작성하고 목록의 길이를 세고 변수에 저장 한 후 파일을 다시 닫습니다.


6
이것이 가장 먼저 떠오르는 방법 중 하나이지만, 특히 파일에서 최대 10GB까지 줄을 세는 경우 (그렇게하는 것처럼) 메모리 효율성이 떨어질 수 있습니다. 이는 주목할만한 단점입니다.
Steen Schütt

@TimeSheep 작은 줄 이 많은 파일 (예 : 수십억) 또는 매우 긴 줄이있는 파일 (예 : 줄당 기가 바이트)에 문제가 있습니까?
robert

내가 묻는 이유는 컴파일러가 중간 목록을 만들지 않고 이것을 최적화 할 수 있어야하기 때문입니다.
robert

@dmityugov 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에서는 작동하지 않습니다.
Bram Vanroy 19

핵심 utils는 분명히 Windows stackoverflow.com/questions/247234/…에 "wc"를 제공합니다 . 코드가 Linux에서 prod로 실행되는 경우 Windows 상자에서 Linux VM을 사용할 수도 있습니다.
radtek

또는 WSL은 이와 같은 작업이 유일한 일이라면 모든 VM에 대해 강력히 권고합니다. :-)
Bram Vanroy 19

그래 그게 효과가있어 나는 창가는 아니지만 goolging에서 WSL = Linux의 Windows 하위 시스템 =)을 배웠습니다.
radtek

3
python3.7 : 서브 프로세스 리턴 바이트이므로 코드는 다음과 같습니다. int (subprocess.check_output ([ 'wc', '-l', file_path]). decode ( "utf-8"). lstrip (). split ( " ") [0])
Alexey Alexeenka

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), ''))

여기 답을 찾을 파이썬보다 C ++로 훨씬 느린 stdin에서 라인을 읽고 왜? 그것을 조금 조정했습니다. 행 수를 빠르게 계산하는 방법을 이해하는 데 도움이되지만 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으로 끝나지 않는 파일을 설명하려면 buffer and buffer [-1]! = '\ n'인 경우 루프 외부에 1을 추가하십시오.
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에서 작동하지 않습니다.
Kim

3
파이썬의 서퍼가되고 싶다면 창문에 작별 인사를 해주세요.
TheExorcist

6
방금 Windows에서만 작동한다는 점에 주목했습니다. 나는 리눅스 / 유닉스 스택을 직접 작업하는 것을 선호하지만, 소프트웨어 IMHO를 작성할 때 다른 OS에서 실행될 때 프로그램이 가질 수있는 부작용을 고려해야합니다. OP는 자신의 플랫폼을 언급하지 않았고 누구나 Google을 통해이 솔루션에 팝업하여 복사 (Windows 시스템의 제한 사항을 알지 못함)하는 경우 메모를 추가하고 싶었습니다.
Kim

출력 os.system()을 변수에 저장 하고 어쨌든 후 처리 할 수 없습니다 .
An Se

@AnSe는 정확하지만 질문이 저장되는지 여부를 묻지 않습니다. 문맥을 이해하고 있다고 생각합니다.
The Exorcist

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

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 이상에서는 timeit.py에 따르면 OP 버전은 여전히 ​​약 10 % 빠릅니다.
dF.

마지막 줄이 '\ n'으로 끝나지 않으면 어떻게됩니까?
tzot

1
나는 당신이 그것을 어떻게 테스트했는지 모릅니다, dF, 내 컴퓨터에서는 다른 옵션보다 ~ 2.5 배 느립니다.
SilentGhost

34
당신은 그것이 가장 빠를 것이라고 말한 다음 테스트하지 않았다고 진술합니다. 과학적이지 않습니까? :)
Ólafur Waage

아래 Ryan Ginstrom 답변에서 제공하는 솔루션 및 통계를 참조하십시오. 또한 JF Sebastian의 의견과 동일한 답변에 대한 링크를 확인하십시오.
SherylHohman

5

이 코드는 더 짧고 명확합니다. 아마도 가장 좋은 방법 일 것입니다.

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

6
또한 파일을 닫아야합니다.
rsm

6
전체 파일을 메모리에로드합니다.
Ivelin

대용량 파일에서 성능이 필요한 경우에 적합하지 않음
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 제외)도 계산됩니다.


어쩌면 변경 한 내용과;에 대해 설명하거나 코드에 주석을 추가 할 수도 있습니다. 두뇌에있는 코드를 "파싱 (parsing)"하는 대신 사람들이 코드에서 훨씬 더 쉽게 내부를 제공 할 수 있습니다.
Styxxy

내가 생각하는 루프 최적화는 파이썬이 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

Linux의 Python에서 줄 수를 저렴하게 얻으려면이 방법을 권장합니다.

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'))

이 방법을 사용하여 3900 라인 파일에서 0.003 초 소요

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

이 답변이 왜 다운되었는지에 관심이 있습니다. 파일을 한 줄씩 반복하여 요약합니다. 나는 그것을 좋아한다. 그것은 짧고 요점은 무엇이 문제인가?
cessor

2

간단한 방법 :

1)

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

430

2)

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

삼)

num_lines = len(list(open('myfile.txt')))

3
이 예제에서 파일은 닫히지 않습니다.
Maciej M

9
OP는 메모리 효율적인 무언가를 원했습니다. 이것은 확실히 아닙니다.
Andy Carlson

1

파일을 연 결과는 반복자이며, 길이가있는 시퀀스로 변환 될 수 있습니다.

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

이것은 명시 적 루프보다 간결하며를 피합니다 enumerate.


10
이것은 100 Mb 파일을 메모리로 읽어야한다는 것을 의미합니다.
SilentGhost

그렇습니다, 좋은 점입니다. 비록 속도 (메모리와는 반대)에 대해 궁금합니다. 아마도이 작업을 수행하는 반복자를 만들 수는 있지만 솔루션과 동일하다고 생각합니다.
Andrew Jaffe

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.