Python ucuz bir büyük dosya satır sayısını almak için?


1011

Python büyük bir dosya (yüz binlerce satır) bir satır sayısı almak gerekiyor. Hem bellek hem de zaman açısından en etkili yol nedir?

Şu anda yapıyorum:

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

daha iyisini yapmak mümkün mü?


7
Doğru satır sayısına mı ihtiyacınız var yoksa yaklaşık bir tahmin yeterli mi?
pico

43
Bu kod boş dosyalar için çalışmadığından, döngü için önce i = -1 eklerdim.
Maciek Sawicki

12
@Legend: Eminim pico düşünür, dosya boyutunu (seek (0,2) veya eşdeğeri) alır, yaklaşık satır uzunluğuna böler. Ortalama satır uzunluğunu tahmin etmek için başlangıçta birkaç satır okuyabilirsiniz.
Anne

32
enumerate(f, 1)ve hendek i + 1?
Ian Mackinnon

4
@IanMackinnon Boş dosyalar için çalışır, ancak for döngüsünden önce i değerini 0 olarak başlatmanız gerekir .
scai

Yanıtlar:


357

Bundan daha iyisi olamaz.

Sonuçta, herhangi bir çözüm tüm dosyayı okumak, kaç tane \nsahip olduğunuzu bulmak ve bu sonucu döndürmek zorunda kalacak .

Tüm dosyayı okumadan bunu yapmanın daha iyi bir yolu var mı? Emin değilim ... En iyi çözüm her zaman G / Ç'ye bağlı olacaktır, yapabileceğiniz en iyi şey gereksiz belleği kullanmadığınızdan emin olmaktır, ancak görünüşe göre bu kapsamdadır.


7
Tam olarak, WC bile dosyayı okuyor, ancak C'de ve muhtemelen oldukça optimize edilmiş.
furlafur Ücreti

6
Anladığım kadarıyla Python dosyası IO da C aracılığıyla yapılır. docs.python.org/library/stdtypes.html#file-objects
Tomalak

9
@Tomalak Bu kırmızı bir ringa balığı. Python ve wc aynı sistem çağrılarını yayınlarken, python'da wc'nin sahip olmadığı opcode gönderme yükü vardır.
bobpoekert

4
Bir satır sayısını örnekleyerek yaklaşık yapabilirsiniz. Binlerce kat daha hızlı olabilir. Bakınız: documentroot.com/2011/02/…
Erik Aronesty

4
Diğer cevaplar, bu kategorik cevabın yanlış olduğunu göstermektedir ve bu nedenle kabul edildiği gibi değil de silinmelidir.
Skippy le Grand Gourou

625

Bir satır, muhtemelen oldukça hızlı:

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

8
toplamı (1 dizisi) her satır 1 olarak sayılır. >>> [(10) aralığındaki çizgi için 1] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> toplam (10 (10) aralığındaki satır için 1) 10 >>>
James Sapam

4
filtre boş satırlar için line.rstrip () ise num_lines = sum (açıktaki satır için 1 ('myfile.txt')
26'da Honghe.Wu

61
bir dosyayı açtığımızda, tüm öğeleri yinelediğimizde bu otomatik olarak kapatılacak mı? 'Close ()' gerekli mi? Sanırım bu kısa ifadede 'open () ile kullanamayız, değil mi?
Mannaggia

16
@Mannaggia doğruysa, dosyanın açıkken kapatıldığından emin olmak için 'open (dosyaadı)' ile kullanmak daha iyi olur ve daha iyisi, bunu ve dosya açılamıyor.
BoltzmannBrain

17
Dikkat edilmesi gereken başka bir şey: Bu, orijinal sorunun 300 bin satırlık metin dosyasında verdiği sorundan ~ 0.04-0.05 saniye daha yavaş
andrew

202

Bellek eşlemeli bir dosyanın en hızlı çözüm olacağına inanıyorum. Dört işlevi denedim: OP ( opcount) tarafından gönderilen işlev ; dosyadaki ( simplecount) satırlar üzerinden basit bir yineleme ; bellek eşlemeli dosyalanmış okuma çizgisi (mmap) ( mapcount); ve Mykola Kharechko ( bufcount) tarafından sunulan tampon okuma çözeltisi .

Her işlevi beş kez çalıştırdım ve 1,2 milyon satırlık bir metin dosyası için ortalama çalışma süresini hesapladım.

Windows XP, Python 2.5, 2GB RAM, 2 GHz AMD işlemci

İşte sonuçlarım:

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

Düzenleme : Python 2.6 için numaralar:

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

Bu nedenle, tampon okuma stratejisi Windows / Python 2.6 için en hızlı gibi görünüyor

İşte kod:

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
Bellek eşlemeli dosyanın tamamı belleğe yüklenmez. İşletim sisteminin gerektiği gibi RAM'a girip çıktığı bir sanal bellek alanı elde edersiniz. Windows'da nasıl ele alınacakları: msdn.microsoft.com/en-us/library/ms810613.aspx
Ryan Ginstrom

1
Maalesef, bellek eşlemeli dosyalar için daha genel bir referans: en.wikipedia.org/wiki/Memory-mapped_file Ve oyladığınız için teşekkürler. :)
Ryan Ginstrom

1
Sadece sanal bir bellek olmasına rağmen, bu yaklaşımı sınırlayan şey budur ve bu nedenle büyük dosyalar için çalışmaz. Ben 10 milyondan fazla ~ 1.2 Gb dosyası ile denedim. (wc -l ile elde edilen) ve bir WindowsError aldım: [Hata 8] Bu komutu işlemek için yeterli depolama alanı yok. Tabii ki, bu bir uç durum.
SilentGhost

6
Gerçek zamanlama verileri için +1. 1024 * 1024 arabellek boyutunun en iyi olup olmadığını veya daha iyi bir arabellek olup olmadığını biliyor muyuz?
Kiv

28
Görünüşe göre wccount()en hızlı gist.github.com/0ac760859e614cd03652
jfs

133

İtibar puanım biraz atlayana kadar benzer bir soruyu yayınlamam gerekiyordu (kim beni çarptıysa!).

Tüm bu çözümler, arabelleksiz (ham) arabirimi kullanarak, bytearrays kullanarak ve kendi arabelleklemenizi yaparak, bu işlemi önemli ölçüde daha hızlı yapmanın bir yolunu yok sayar. (Bu yalnızca Python 3 için geçerlidir. Python 2'de, ham arabirim varsayılan olarak kullanılabilir veya kullanılmayabilir, ancak Python 3'te varsayılan olarak Unicode'u kullanırsınız.)

Zamanlama aracının değiştirilmiş bir sürümünü kullanarak, aşağıdaki kodun sunulan çözümlerden daha hızlı (ve marjinal olarak daha pythonic) olduğuna inanıyorum:

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

Ayrı bir jeneratör işlevi kullanarak, bu daha hızlı bir görüntü sağlar:

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 )

Bu tamamen itertools kullanarak satır içi jeneratör ifadeleri ile yapılabilir, ancak oldukça garip görünüyor:

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 )

İşte zamanlamalarım:

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 + dosyalarıyla çalışıyorum ve rawgencounts şimdiye kadar gördüğüm tek uygulanabilir çözüm. Teşekkürler!
soungalo

1
olduğu wccountaltişlem kabuk için bu tabloda wcaracı?
Anentropik

1
başka bir yorumda buldum, sanırım o zaman gist.github.com/zed/0ac760859e614cd03652
Anentropic

3
Teşekkürler @ michael-bacon, gerçekten güzel bir çözüm. rawincountKullanarak çözümü daha tuhaf görünmesini sağlayabilirsiniz.bufgen = iter(partial(f.raw.read, 1024*1024), b'') yerine birleştirerek takewhileve repeat.
Peter H.

1
Oh, kısmi işlev, evet, bu hoş bir küçük değişiklik. Ayrıca, 1024 * 1024'ün yorumlayıcı tarafından birleştirileceğini ve sabit olarak ele alınacağını varsaydım, ancak bu dokümantasyonda önseziydi.
Michael Bacon

90

Bir alt işlem yürütebilir ve çalıştırabilirsiniz. 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
bunun windows versiyonu ne olurdu?
SilentGhost

1
Bununla ilgili bu SO sorusuna başvurabilirsiniz. stackoverflow.com/questions/247234/…
furlafur Ücret

7
Gerçekten de, benim durumumda (Mac OS X) bu, dosyadaki (...) "x için satır sayısını saymak için 0,53'e karşı 0,13 saniyeyi alır, 1,0'a karşı str.find veya mmap.find çağrılarını tekrarlar . (Bu test için kullanılan dosya 1300000 hatları vardır.)
Bendin

1
Kabuğu buna dahil etmeye gerek yok. düzenlenmiş cevap ve eklenen örnek kod;
nosklo

2
Çapraz platform değildir.
e-info128

42

Satır sayımını makineler / çekirdekler arasında dağıtmak için çoklu işlem kütüphanesini kullanmak için bir python programı. Testim, 8 çekirdekli bir Windows 64 sunucusu kullanarak 26 milyondan 7 saniyeye kadar 20 milyon satırlık bir dosya saymayı geliştiriyor. Not: bellek eşleme kullanılmaması işleri daha yavaş hale getirir.

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

Bu, ana bellekten çok daha büyük dosyalarla nasıl çalışır? örneğin 4GB RAM ve 2 çekirdekli bir sistemde 20GB'lık bir dosya
Brian Minton

Şimdi test etmek zor, ama dosyayı içeri ve dışarı sayfa olacağını tahmin ediyorum.
Martlark

5
Bu oldukça düzgün bir kod. Birden fazla işlemci kullanmanın daha hızlı olduğunu görünce şaşırdım. ES'nin darboğaz olacağını düşündüm. Eski Python sürümlerinde, satır 21 ihtiyaçlar = int ((FSIZE / süreçler)) + 1 öbek gibi () int
Karl Henselin

tüm dosyayı belleğe yüklüyor mu? boyutunun bilgisayardaki koçtan daha büyük olduğu daha büyük bir yangına ne dersiniz?
pelos

Dosyalar sanal belleğe eşlenir, bu nedenle dosyanın boyutu ve gerçek bellek miktarı genellikle bir kısıtlama değildir.
Martlark

17

Modern işlevi kullanarak bu cevaba benzer tek satırlık bir bash çözümü subprocess.check_output:

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

Bu yanıt Linux / Unix kullanıcıları için bu konu başlığında daha yüksek bir noktaya kadar oylanmalıdır. Platformlar arası bir çözümde tercihlerin çoğuna rağmen, bu Linux / Unix'te mükemmel bir yoldur. Veriyi örneklemek zorunda olduğum 184 milyon satırlık bir csv dosyası için en iyi çalışma zamanını sağlar. Diğer saf python çözümleri ortalama 100+ saniye sürerken, alt işlem çağrısı wc -lyaklaşık 5 saniye sürer.
Shan Dou

shell=Truegüvenlik açısından kötü, bundan kaçınmak daha iyidir.
Alexey Vazhnov

Düzenlenen fuar noktası
1 ''

15

Python'un dosya nesnesi yöntemini readlinesaşağıdaki gibi kullanırdım:

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

Bu dosyayı açar, dosyada bir satır listesi oluşturur, listenin uzunluğunu sayar, bunu bir değişkene kaydeder ve dosyayı tekrar kapatır.


6
Bu akla gelen ilk yollardan biri olsa da, özellikle de 10 GB'a kadar olan dosyalarda (saydıklarım gibi) satırları sayıyorsa, bu da dikkate değer bir dezavantaj olan, muhtemelen çok bellek verimli değildir.
Steen Schütt

@TimeSheep Bu, çok sayıda (milyarlarca) küçük satır içeren dosyalar veya son derece uzun satırlara (satır başına Gigabyte) sahip dosyalar için bir sorun mu?
Robert

Sormamın nedeni, derleyicinin bir ara liste oluşturmadan bunu optimize edebilmesi gibi görünüyor.
Robert

@dmityugov Python belgelerine göre, xreadlinessadece bir yineleyici döndürdüğü için 2.3'ten beri kullanımdan kaldırıldı. for line in filebelirtilen değiştirmedir. Bkz. 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

İşte kullandığım, oldukça temiz görünüyor:

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

GÜNCELLEME: Bu, saf python kullanmaktan biraz daha hızlıdır, ancak bellek kullanımı pahalıdır. Alt işlem, komutunuzu yürütürken üst işlemle aynı bellek kapladığı yeni bir işlemi keser.


1
Bir yan not olarak, bu elbette Windows üzerinde çalışmaz.
Bram Vanroy

çekirdek araçlar görünüşe göre windows için "wc" sağlar stackoverflow.com/questions/247234/… . Kodunuz linux in prod içinde çalışacaksa, windows kutunuzda bir linux VM de kullanabilirsiniz.
radtek

Veya WSL, böyle bir şey yaptığınız tek şey ise herhangi bir VM üzerinden şiddetle tavsiye edilir. :-)
Bram Vanroy

Evet, işe yarıyor. Ben bir windows adam değilim ama goolging WSL = Linux için Windows Alt Sistemi =)
radtek

3
python3.7: alt süreç dönüş baytları, bu yüzden kod şöyle görünür: int (subprocess.check_output (['wc', '-l', dosya_yolu]). decode ("utf-8"). lstrip (). split (" ") [0])
Alexey Alexeenka

11

Bu saf python kullanarak bulduğum en hızlı şey. Arabelleği ayarlayarak istediğiniz bellek miktarını kullanabilirsiniz, ancak 2 ** 16 bilgisayarımda tatlı bir nokta gibi görünüyor.

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

Cevabı burada buldum Neden stdin'den satırları okumak C ++ 'da Python'dan çok daha yavaş? ve küçük bir değişiklik yaptım. Çizgileri hızlı bir şekilde nasıl sayacağınızı anlamak için çok iyi bir okuma wc -l, yine de her şeyden yaklaşık% 75 daha hızlı.


9

Herhangi bir bellek veya GC yükünü önlemek gerekir sabit bir tampon yeniden kullanır bu sürümü ile küçük (% 4-8) bir gelişme var:

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

Arabellek boyutu ile oynayabilir ve belki biraz iyileşme görebilirsiniz.


Güzel. \ N bitmez dosyalar için hesaba için, tampon eğer döngünün 1 dışını ve tampon [-1] = '\ n'!
ryuusenshi

Bir hata: son turdaki arabellek temiz olmayabilir.
Jay

tamponlar arasında bir kısım \ ile bitiyor ve diğer kısım n ile başlıyorsa ne olur? orada yeni bir satır kaçıracak, ben her yığının sonu ve başlangıcını saklamak için değişkenler için sudgest olurdu, ama bu senaryoya daha fazla zaman ekleyebilir = (
pelos

9

Kyle'nin cevabı

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

muhtemelen en iyisi, bunun için bir alternatif

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

İşte her ikisinin performans karşılaştırması

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

Tek hat çözümü:

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

Snippet'im:

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

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

İyi fikir, ne yazık ki bu Windows üzerinde çalışmıyor.
Kim

3
Python sörfçü olmak istiyorsanız, pencerelere güle güle deyin. İnanın bana bir gün bana teşekkür edeceksiniz.
TheExorcist

6
Bunun sadece pencerelerde çalışacağını dikkate aldım. Kendimi bir linux / unix yığını üzerinde çalışmayı tercih ediyorum, ancak yazılım IMHO'yu yazarken, bir programın farklı işletim sistemleri altında çalıştırıldığında sahip olabileceği yan etkileri göz önünde bulundurmalısınız. OP platformundan bahsetmediği ve herhangi birinin google üzerinden bu çözümü açması ve kopyalaması durumunda (bir Windows sisteminin sahip olabileceği sınırlamalardan habersiz) notu eklemek istedim.
Kim

os.system()Değişkenin çıktısını kaydedemez ve hiçbir şekilde işleme koyamazsınız.
Bir Se

@Eğer haklısın, ancak soru kaydedilip kaydedilmediği sorulmuyor.Kanırım bağlamı anlıyorsun.
TheExorcist

6

Sadece yukarıdaki yöntemleri tamamlamak için fileinput modülü ile bir varyant denedim:

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

Ve yukarıda belirtilen yöntemlerin tümüne bir 60mil satır dosyasını geçti:

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

Dosya girişinin o kadar kötü ve ölçeklendirilmesinin diğer tüm yöntemlerden çok daha kötü olması benim için biraz sürpriz ...


5

Bana göre bu varyant en hızlı olacak:

#!/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()

nedenleri: satır satır okumaktan daha hızlı arabelleğe alma ve string.countaynı zamanda çok hızlı


1
Ama öyle mi? En azından OSX / python2.5'te OP'nin sürümü timeit.py'ye göre hala% 10 daha hızlı.
dF.

Son satır '\ n' ile bitmezse ne olur?
tzot

1
Nasıl test ettiğinizi bilmiyorum, dF, ancak makinemde diğer seçeneklerden ~ 2.5 kat daha yavaş.
SilentGhost

34
En hızlı olacağını ve test etmediğini belirtiyorsun. Çok bilimsel değil ha? :)
furlafur Ücreti

Aşağıdaki Ryan Ginstrom cevap tarafından sağlanan çözümü ve istatistikleri görün. Ayrıca JF Sebastian'ın yorumuna ve aynı cevaptaki bağlantıya göz atın.
SherylHohman

5

Bu kod daha kısa ve açıktır. Muhtemelen en iyi yol:

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

6
Ayrıca dosyayı kapatmalısınız.
rsm

6
Tüm dosyayı belleğe yükleyecektir.
Ivelin

büyük dosyalarda performans gerektiğinde iyi değil
mabraham

4

Arabellek kasasını şu şekilde değiştirdim:

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

Şimdi boş dosyalar ve son satır (\ n olmadan) sayılır.


Belki de neyi değiştirdiğinizi ve ne için; Kodunuzdaki insanlara biraz daha kolay verebilir (beyindeki kodu "ayrıştırmak" yerine).
Styxxy

Bence döngü optimizasyonu Python read_f yerel bir değişken arama yapmanızı sağlar, python.org/doc/essays/list2str
Kırmızı Bezelye

3

Peki buna ne dersin

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

Biri Linux'ta Python'da ucuza satır sayısını almak istiyorsa, bu yöntemi öneririm:

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

file_path hem soyut dosya yolu hem de göreli yol olabilir. Umarım bu yardımcı olabilir.


2

Buna ne dersin?

import fileinput
import sys

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

fileinput.close()
print counter

2

Peki bu tek astarlı:

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

3900 satır dosyasında zamanlamak için bu yöntemi kullanarak 0.003 saniye sürer

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

Yanlış olduğunu düşünüyorsanız, neyin yanlış olduğunu açıklar mısınız? Benim için çalıştı. Teşekkürler!
jciloa

Bu cevabın neden reddedildiğini de merak ediyorum. Dosya üzerinde satırlar halinde yinelenir ve özetlenir. Sevdim, kısa ve noktaya gelince, sorun ne?
cessor

2

Basit yöntem:

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
Bu örnekte dosya kapatılmamıştır.
Maciej M

9
OP bellek verimli bir şey istedi. Bu kesinlikle değil.
Andy Carlson

1

bir dosyayı açmanın sonucu, uzunluğu olan bir diziye dönüştürülebilen bir yineleyicidir:

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

bu, açık döngünüzden daha özlüdür ve enumerate.


10
yani 100 Mb'lik bir dosyanın hafızaya okunması gerekir.
SilentGhost

evet, iyi bir nokta, hız (merak yerine) fark merak rağmen. Muhtemelen bunu yapan bir yineleyici oluşturmak mümkündür, ancak bunun çözümünüze eşdeğer olacağını düşünüyorum.
Andrew Jaffe

6
-1, bu sadece bellek değil, listeyi bellekte oluşturmak zorunda.
09:14

0

Sen kullanabilirsiniz os.pathşu şekilde modülü:

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

, Filenamedosyanın mutlak yolu nerede .


1
Bu sorunun ne ile ilgisi var os.path?
moi

0

Dosya belleğe sığabiliyorsa,

with open(fname) as f:
    count = len(f.read().split(b'\n')) - 1
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.