পাইথনে কীভাবে একটি বড় ফাইলের লাইন গণনা পাবেন?


1009

পাইথনটিতে আমার একটি বৃহত ফাইলের (কয়েক হাজার লাইনের) লাইন কাউন্ট পেতে হবে। মেমরি- এবং সময় অনুসারে উভয়ই সবচেয়ে কার্যকর উপায় কি?

এই মুহূর্তে আমি করি:

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

এটা কি আরও ভাল করা সম্ভব?


7
আপনার কি সঠিক লাইন গণনা প্রয়োজন বা একটি আনুমানিক যথেষ্ট হবে?
পিকো

43
আমি লুপের আগে i = -1 যুক্ত করব, যেহেতু এই কোডটি খালি ফাইলগুলির জন্য কাজ করে না।
ম্যাকিক সাওকি

12
@ কিংবদন্তি: আমি বাজিতে পিকো ভাবতে চাইছি, ফাইলের আকার (সিক (0,2) বা সমমানের সাথে) আনুমানিক লাইন দৈর্ঘ্যের দ্বারা ভাগ করে নিন। গড় রেখার দৈর্ঘ্য অনুমান করার জন্য আপনি শুরুতে কয়েকটি লাইন পড়তে পারেন।
অ্যান

32
enumerate(f, 1)এবং খাদের i + 1?
ইয়ান ম্যাকিনন

4
@ ইয়ানম্যাকিনন খালি ফাইলগুলির জন্য কাজ করে, তবে আপনাকে লুপের আগে i থেকে 0 করতে হবে ।
স্কাই

উত্তর:


356

আপনি এর চেয়ে ভাল আর কিছু পেতে পারেন না।

সর্বোপরি, যে কোনও সমাধানের জন্য পুরো ফাইলটি পড়তে হবে, \nআপনার কতগুলি আছে তা বের করতে হবে এবং ফলাফলটি ফিরে আসতে হবে।

পুরো ফাইলটি না পড়েই কি আপনার আরও ভাল উপায় আছে? নিশ্চিত নয় ... সর্বোত্তম সমাধানটি সর্বদা আমি / হে-আবদ্ধ হবে, আপনি সবচেয়ে ভাল করতে পারেন তা নিশ্চিত করে নিন যে আপনি অপ্রয়োজনীয় স্মৃতি ব্যবহার করছেন না, তবে দেখে মনে হচ্ছে আপনার এটি আবৃত রয়েছে।


7
ঠিক ঠিক, এমনকি ডব্লিউসিও ফাইলটি পড়ছেন, তবে সিতে এবং এটি সম্ভবত বেশ অনুকূলিত হয়েছে।
ইলফুর ওয়েজ

6
আমি যতদূর বুঝতে পারি পাইথন ফাইল আইওও সি এর মাধ্যমে সম্পন্ন হয়। docs.python.org/library/stdtyype.html#file-objects
টমলক

9
@ তোমালাক এটি একটি লাল রঙের হারিং। পাইথন এবং ডাব্লুসিটি একই সিস্টেমে জারি করতে পারে, পাইথন ওপোডে প্রেরণ করেছে যে ডাব্লিউসি নেই।
ববপোকার্ট

4
স্যাম্পলিংয়ের মাধ্যমে আপনি আনুমানিক একটি লাইন গণনা করতে পারেন। এটি হাজার গুণ দ্রুত হতে পারে। দেখুন: documentroot.com/2011/02/…
এরিক অ্যারোনস্টি

4
অন্যান্য উত্তরগুলি এই শ্রেণিবদ্ধ উত্তরটি ভুল বলে মনে হচ্ছে এবং তাই এটি গ্রহণযোগ্য না হয়ে মুছে ফেলা উচিত।
স্কিপি লে গ্র্যান্ড গৌরূ 25'17

623

একটি লাইন, সম্ভবত বেশ দ্রুত:

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

8
এটির সমান (1 ক্রমানুসারে) প্রতিটি লাইন 1 হিসাবে গণনা করা হচ্ছে >>>> [পরিসীমা (10) এর জন্য 1]] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] >>> যোগফল (পরিসীমা (10) রেখার জন্য 1) 10 >>>
জেমস সপম

4
num_lines = যোগফল (খোলায় রেখার জন্য 1 ('myfile.txt')) খালি লাইনের ফিল্টার করার জন্য যদি line.rstrip ())
হংসে। Wu

61
যেহেতু আমরা কোনও ফাইল খুলি, একবারে সমস্ত উপাদানগুলির পুনরুক্তি করা কি এটি স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যাবে? এটি 'বন্ধ ()' করা প্রয়োজন? আমি মনে করি আমরা এই সংক্ষিপ্ত বিবৃতিতে 'ওপেন () সহ ব্যবহার করতে পারি না, তাই না?
মান্নাগগিয়া

16
@ মান্নগগিয়া আপনি সঠিক, ফাইলটি হয়ে গেলে ফাইলটি বন্ধ হয়ে যায় তা নিশ্চিত হওয়ার জন্য 'ওপেন (ফাইলের নাম)' ব্যবহার করা আরও ভাল হবে, এবং আইওআরআর ব্যতিক্রম যদি নিক্ষেপ করা হয় তবে এটি আরও ভাল চেষ্টা করা ব্লকের মধ্যে করা হয় doing ফাইলটি খোলা যায় না।
বোল্টজমানব্রেন

17
আরেকটি বিষয় লক্ষণীয়: এটি 300,000 লাইনের পাঠ্য ফাইলটিতে মূল সমস্যাটি দেওয়া সমস্যাটির চেয়ে 0.04-0.05 সেকেন্ড ধীরে ধীরে
অ্যান্ড্রু

202

আমি বিশ্বাস করি যে মেমরি ম্যাপ করা ফাইলটি দ্রুততম সমাধান হবে। আমি চারটি ফাংশন চেষ্টা করেছি: ফাংশনটি ওপি পোস্ট করেছে ( opcount); ফাইলের লাইনগুলির উপরে একটি সাধারণ পুনরাবৃত্তি ( simplecount); মেমোরি-ম্যাপযুক্ত ফাইল (এমএমএপি) ( mapcount) সহ রিডলাইন ; এবং মাইকোলা খারেচকো ( bufcount) দ্বারা প্রদত্ত বাফার পড়ার সমাধান ।

আমি প্রতিটি ফাংশন পাঁচবার চালিয়েছি এবং 1.2 মিলিয়ন-লাইনের পাঠ্য ফাইলের জন্য গড় রান-টাইম গণনা করেছি।

উইন্ডোজ এক্সপি, পাইথন 2.5, 2 জিবি র‌্যাম, 2 গিগাহার্টজ এএমডি প্রসেসর

আমার ফলাফলগুলি এখানে:

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

সম্পাদনা করুন : পাইথন ২.6 এর জন্য সংখ্যা:

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

সুতরাং বাফার পঠন কৌশলটি উইন্ডোজ / পাইথন ২.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
রায়ান Ginstrom

1
দুঃখিত, এখানে মেমরি-ম্যাপযুক্ত ফাইলগুলি সম্পর্কে আরও সাধারণ রেফারেন্স দেওয়া হয়েছে: en.wikedia.org/wiki/Memory-maped_file এবং ভোটের জন্য ধন্যবাদ। :)
রায়ান জিনস্ট্রোম

1
যদিও এটি কেবল একটি ভার্চুয়াল মেমরি, এটি সঠিকভাবে যা এই পদ্ধতির সীমাবদ্ধ করে এবং তাই এটি বিশাল ফাইলগুলির জন্য কাজ করবে না। আমি এটি 10 ​​মিলিয়ন ডলারের বেশি দিয়ে 1.2 গিগাবাইট ফাইল দিয়ে চেষ্টা করেছি। লাইনগুলি (ডাব্লুসি-এল দিয়ে প্রাপ্ত হিসাবে) এবং একটি উইন্ডোজআরার পেয়েছে: [ত্রুটি 8] এই কমান্ডটি প্রক্রিয়া করার জন্য পর্যাপ্ত সঞ্চয়স্থান পাওয়া যায় না available অবশ্যই, এটি একটি প্রান্তের কেস।
সাইলেন্টগোস্ট

6
রিয়েল টাইমিং ডেটার জন্য +1। আমরা কি জানি যে 1024 * 1024 এর বাফার আকারটি অনুকূল হয়, বা এর চেয়ে আরও ভাল কিছু আছে?
কিভ

28
দেখে মনে wccount()হচ্ছে এটি দ্রুততম gist.github.com/0ac760859e614cd03652
jfs

133

আমার খ্যাতি স্কোরটি কিছুটা লাফ না দেওয়া পর্যন্ত আমাকে একই পোস্টে পোস্ট করতে হয়েছিল (যারাই আমাকে ধাক্কা দিয়েছে তাকে ধন্যবাদ!)।

এই সমস্ত সমাধানের পক্ষে এই রানকে আরও দ্রুততর করার একটি উপায় উপেক্ষা করা হয়, যেমন আনফারড (কাঁচা) ইন্টারফেস ব্যবহার করে, বাইটারারি ব্যবহার করে এবং আপনার নিজের বাফারিং করে। (এটি কেবল পাইথন 3 এ প্রযোজ্য Py পাইথন 2 এ, কাঁচা ইন্টারফেসটি ডিফল্টরূপে ব্যবহৃত হতে পারে বা নাও ব্যবহৃত হতে পারে তবে পাইথন 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

একটি পৃথক জেনারেটর ফাংশন ব্যবহার করে, এটি দ্রুত একটি স্মিজ চালায়:

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 )

এটি সম্পূর্ণরূপে জেনারেটর এক্সপ্রেশনগুলির সাথে সম্পূর্ণরূপে ইটারটুলগুলি ব্যবহার করে করা যেতে পারে তবে এটি দেখতে বেশ অদ্ভুত লাগছে:

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
আমি 100 গিগাবাইট + ফাইলের সাথে কাজ করছি এবং আপনার কাঁচা অ্যাকাউন্টগুলি এখন পর্যন্ত দেখা একমাত্র সম্ভাব্য সমাধান। ধন্যবাদ!
সানগালো

1
হয় wccountsubprocess শেল এই টেবিলে wcটুল?
অ্যান্ট্রোপিক

1
এটি অন্য একটি মন্তব্যে পাওয়া গেছে, আমার ধারণা এটি তখন gist.github.com/zed/0ac760859e614cd03652
অ্যান্ট্রোপিক

3
ধন্যবাদ @ মাইকেল-বেকন, এটি একটি দুর্দান্ত সমাধান। আপনি করতে পারেন 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
এর উইন্ডোজ সংস্করণটি কী হবে?
সাইলেন্টগোস্ট

1
আপনি এই সম্পর্কিত এই প্রশ্নটি উল্লেখ করতে পারেন। stackoverflow.com/questions/247234/…
ইলফুর ওয়েজ

7
প্রকৃতপক্ষে, আমার ক্ষেত্রে (ম্যাক ওএস এক্স) এটি "ফাইলের এক্স এর জন্য (...)" রেখার সংখ্যা গণনা করার জন্য ০.০ এর বিপরীতে ০.০৩ এর সময় নেয়, স্ট্রিংফাইন্ড বা এমএমএপি.ফাইন্ডে বারবার কল গণনা করা 1.0s এর বিপরীতে produces । (আমি এটি পরীক্ষার জন্য যে ফাইলটি ব্যবহার করেছি
সেটিতে

1
এটিতে শেল জড়িত করার দরকার নেই। সম্পাদিত উত্তর এবং উদাহরণ কোড যুক্ত;
nosklo

2
ক্রস প্ল্যাটফর্ম নয়।
ই তথ্য 128

42

মেশিন / কোরগুলিতে লাইন গণনা বিতরণ করার জন্য মাল্টিপ্রসেসিং লাইব্রেরিটি ব্যবহার করার জন্য পাইথন প্রোগ্রামটি এখানে রয়েছে। আমার পরীক্ষাটি 8 টি মূল উইন্ডোজ 64 সার্ভার ব্যবহার করে 26 মিলিয়ন থেকে 7 সেকেন্ডে 20 মিলিয়ন লাইন ফাইল গণনা উন্নত করে। দ্রষ্টব্য: মেমরি ম্যাপিং ব্যবহার না করা জিনিসগুলিকে অনেক ধীর করে তোলে।

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 জিবি র‌্যাম এবং 2 কোর সহ একটি সিস্টেমে একটি 20 জিবি ফাইল
ব্রায়ান মিন্টন

এখনই পরীক্ষা করা শক্ত, তবে আমি অনুমান করি যে এটি ফাইলটি আউট এবং আউট করবে।
মার্টলার্ক

5
এটি বেশ ঝরঝরে কোড। আমি একাধিক প্রসেসরের ব্যবহার করা দ্রুততর তা জানতে পেরে অবাক হয়েছি। আমি বুঝতে পেরেছিলাম যে আইও হ'ল বাধা। পুরানো পাইথন সংস্করণগুলিতে, লাইন 21-এর মতো প্রয়োজন (যেমন) শঙ্ক = ইনট ((fSize / প্রসেস)) + 1
কার্ল হেন্সলিন

এটি কি সমস্ত ফাইল মেমরিতে লোড করে? আকারে বড় হলে কম্পিউটারে থাকা মেষটি কী হবে?
pelos

ফাইলগুলি ভার্চুয়াল মেমোরিতে ম্যাপ করা হয়, সুতরাং ফাইলের আকার এবং প্রকৃত মেমরির পরিমাণ সাধারণত কোনও বাধা নয়।
মার্টারলাক

17

আধুনিক ক্রিয়াকলাপটি ব্যবহার করে এই উত্তরের অনুরূপ একটি এক-লাইন বাশ সমাধান subprocess.check_output:

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

এই উত্তরটি লিনাক্স / ইউনিক্স ব্যবহারকারীদের জন্য এই থ্রেডের উচ্চতর স্থানে ভোট দেওয়া উচিত। ক্রস-প্ল্যাটফর্ম সমাধানে সংখ্যাগরিষ্ঠ পছন্দ সত্ত্বেও, এটি লিনাক্স / ইউনিক্সের একটি দুর্দান্ত উপায়। 184-মিলিয়ন-লাইনের সিএসভি ফাইলের জন্য আমার কাছে থেকে ডেটা নমুনা করতে হবে, এটি সেরা রানটাইম সরবরাহ করে। অন্যান্য খাঁটি অজগর সমাধানগুলিতে গড়ে 100+ সেকেন্ড wc -lসময় লাগে যখন সাব-প্রসেস কলের সময় লাগে 5 seconds সেকেন্ড।
শান ডু

shell=Trueসুরক্ষার জন্য খারাপ, এটি এড়ানো ভাল।
আলেক্সি ওয়াজনভ

ফেয়ার পয়েন্ট, সম্পাদিত
1 ''

15

আমি পাইথনের ফাইল অবজেক্ট পদ্ধতিটি ব্যবহার করব readlines:

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

এটি ফাইলটি খোলে, ফাইলটিতে লাইনগুলির একটি তালিকা তৈরি করে, তালিকার দৈর্ঘ্য গণনা করে, এটি একটি পরিবর্তনশীলে সংরক্ষণ করে এবং ফাইলটি আবার বন্ধ করে দেয়।


6
যদিও এটি প্রথম দিকের মধ্যে মনে আসে, এটি সম্ভবত খুব স্মৃতিশক্তি দক্ষ নয়, বিশেষত যদি 10 গিগাবাইট পর্যন্ত ফাইলগুলিতে লাইন গণনা করা হয় (যেমন আমি করি) তবে এটি একটি উল্লেখযোগ্য অসুবিধা।
স্টেইন শ্যাট

@ টাইমশীপ এটি কি অনেকগুলি ছোট ফাইল (বলে, কোটি কোটি) লাইনযুক্ত ফাইলগুলির জন্য , বা অত্যন্ত লম্বা লাইনযুক্ত ফাইলগুলির (যা বলুন, প্রতি লাইনে গিগা বাইট ) ফাইলগুলির জন্য সমস্যা ?
রবার্ট

যে কারণটি আমি জিজ্ঞাসা করছি তা মনে হচ্ছে যে সংকলকটি মধ্যবর্তী তালিকা তৈরি না করে এটিকে অপ্টিমাইজ করতে সক্ষম হবে।
রবার্ট

@ dmityugov প্রতি পাইথন ডক্স, xreadlines২.৩ থেকে অবহেলা করা হয়েছে, কারণ এটি কেবল একজন পুনরাবৃত্তিকে ফেরত দেয়। for line in fileবিবৃত প্রতিস্থাপন হয়। দেখুন: docs.python.org/2/library/stdtyype.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

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

আপডেট: খাঁটি অজগর ব্যবহারের তুলনায় এটি সামান্য গতিযুক্ত তবে মেমরির ব্যবহারের ব্যয়ে। সাব-প্রসেসটি আপনার কমান্ড কার্যকর করার সময় পিতামাতার প্রক্রিয়ার মতো একই মেমরি পদক্ষেপ সহ একটি নতুন প্রক্রিয়া তৈরি করবে for


1
পার্শ্ব নোট হিসাবে, এটি অবশ্যই উইন্ডোজটিতে কাজ করবে না।
ব্রাম ভ্যানরোয়

মূল ব্যবহারগুলি দৃশ্যত উইন্ডোজের জন্য "ডাব্লুসি" সরবরাহ করে স্ট্যাকওভারফ্লো / প্রশ্ন / 247234/… । আপনি যদি উইন্ডোজ বাক্সে একটি লিনাক্স ভিএম ব্যবহার করতে পারেন তবে যদি আপনার কোডটি লিনাক্সে প্রোডে চলে।
Radtek

বা ডাব্লুএসএল, যে কোনও ভিএমের উপর অত্যন্ত পরামর্শ দেওয়া যদি এই ধরণের জিনিসগুলি কেবল আপনিই করেন। :-)
ব্রাম ভ্যানরোয়

হ্যাঁ যে কাজ করে। আমি উইন্ডোজ লোক নই, গোলিং থেকে আমি লিনাক্সের জন্য ডাব্লুএসএল = উইন্ডোজ সাবসিস্টেম শিখেছি =)
র‌্যাডটেক

3
পাইথন ৩..7: সাবপ্রসেস রিটার্ন বাইটস, সুতরাং কোডটি এর মতো দেখায়: int (subprocess.check_output (['wc', '-l', file_path])। ডিকোড ("utf-8")। lstrip ()। বিভাজন (" ") [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), ''))

আমি উত্তরটি এখানে পেয়েছি কেন স্টিডিনের লাইনগুলি পাইথনের তুলনায় সি ++ তে খুব ধীর হয়? এবং এটি সামান্য একটি সামান্য বিট। লাইনগুলি কীভাবে দ্রুত গণনা করা যায় তা বোঝার জন্য এটি খুব ভাল পড়া, যদিও wc -lঅন্য যে কোনও কিছুর চেয়ে এখনও প্রায় 75% দ্রুত।


9

আমি এই সংস্করণটির সাথে একটি ছোট (4-8%) উন্নতি পেয়েছি যা একটি ধ্রুবক বাফারটিকে পুনরায় ব্যবহার করে যাতে এটি কোনও স্মৃতি বা জিসি ওভারহেড এড়ানো উচিত:

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

আপনি বাফার আকারের সাথে চারপাশে খেলতে পারেন এবং সম্ভবত কিছুটা উন্নতি দেখতে পাবেন।


খুশী হলাম। Files n এ শেষ হয় না এমন ফাইলগুলির জন্য অ্যাকাউন্ট করতে, বাফার এবং বাফার হলে লুপের বাইরে 1 যুক্ত করুন [-1]! = '\ N'
ryuusenshi

একটি বাগ: শেষ রাউন্ডের বাফারটি পরিষ্কার নাও হতে পারে।
জে

যদি বাফারগুলির মধ্যে একটি অংশ \ দিয়ে শেষ হয় এবং অন্য অংশটি এন দিয়ে শুরু হয়? এটি সেখানে একটি নতুন লাইন মিস করবে, আমি প্রতিটি খণ্ডের শেষ এবং শুরুটি সংরক্ষণ করতে ভেরিয়েবলগুলিতে সোডাস্ট করব, তবে এটি স্ক্রিপ্টে আরও সময় যোগ করতে পারে = (
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

ভাল ধারণা, দুর্ভাগ্যক্রমে যদিও এটি উইন্ডোজটিতে কাজ করে না।
কিম

3
আপনি যদি অজগরকে আরও ভাল করে তুলতে চান, উইন্ডোজগুলিকে বিদায় জানান B আমাকে ছেড়ে দিন, আপনি একদিন আমাকে ধন্যবাদ দেবেন।
Thexorist

6
আমি কেবল এটি লক্ষণীয় হিসাবে বিবেচনা করেছি যে এটি কেবল উইন্ডোতে কাজ করবে। আমি নিজেই একটি লিনাক্স / ইউনিক্স স্ট্যাকের উপর কাজ করা পছন্দ করি তবে আইএমএইচও সফ্টওয়্যার লেখার সময় বিভিন্ন ওএসের অধীনে চলাকালীন কোনও প্রোগ্রামের পার্শ্ব প্রতিক্রিয়াগুলি বিবেচনা করা উচিত। যেহেতু ওপি তার প্ল্যাটফর্মটির উল্লেখ না করে এবং যদি কেউ এই সমাধানটি গুগলের মাধ্যমে পপ করে এবং এটি অনুলিপি করে (কোনও উইন্ডোজ সিস্টেমের সীমাবদ্ধতা সম্পর্কে অবগত নয়), আমি নোটটি যুক্ত করতে চেয়েছিলাম।
কিম

আপনি os.system()ভেরিয়েবলের আউটপুট সংরক্ষণ করতে এবং এটি কোনওভাবে পোস্ট-প্রসেস করতে পারবেন না।
আন সে

@ আপনি সঠিক হন তবে প্রশ্ন সংরক্ষণ করা হয় না তা সংরক্ষণ করা হয় কি না জিজ্ঞাসা করা হয়নি I আমি অনুমান করি আপনি প্রসঙ্গটি বুঝতে পেরেছেন।
এক্সোরিস্ট

6

কেবলমাত্র উপরের পদ্ধতিগুলি সম্পূর্ণ করতে আমি ফাইল ইনপুট মডিউলটির সাথে একটি বৈকল্পিক চেষ্টা করেছি:

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

আমার কাছে কিছুটা অবাক লাগল যে ফাইলিনপুটটি হ'ল যে খারাপ এবং স্কেলগুলি অন্য সমস্ত পদ্ধতির চেয়ে খারাপ ...


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
তবে কি তাই? কমপক্ষে ওএসএক্স / পাইথন ২.৫-তে অপারেটিং সিস্টেমের সংস্করণ টাইমাইট.পি অনুসারে এখনও প্রায় 10% দ্রুত।
ডিএফ।

শেষ লাইনটি '\ n' এ শেষ না হলে কী হবে?
tzot

1
আপনি কীভাবে এটি পরীক্ষা করেছেন, আমি জানি না, ডিএফ, তবে আমার মেশিনে এটি অন্য কোনও বিকল্পের চেয়ে 2.5 গুন বেশি ধীর।
সাইলেন্টগোস্ট

34
আপনি উল্লেখ করেছেন যে এটি সবচেয়ে দ্রুত হবে এবং তারপরে জানিয়ে দিন যে আপনি এটি পরীক্ষা করেননি। খুব বৈজ্ঞানিক তাই না? :)
ইলফুর ওয়েজ

নীচে রায়ান জিনস্ট্রোমের উত্তর দ্বারা প্রদত্ত সমাধান এবং পরিসংখ্যান দেখুন। এছাড়াও জেএফ সেবাস্তিয়ানের মন্তব্য এবং একই উত্তরের লিঙ্ক দেখুন।
শারিলহোহমান

5

এই কোডটি সংক্ষিপ্ত এবং ক্লিয়ার। এটি সম্ভবত সবচেয়ে ভাল উপায়:

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

6
আপনার ফাইলটিও বন্ধ করা উচিত।
আরএসএম

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

লুপ অপ্টিমাইজেশন আমি মনে করি পাইথন স্থানীয়ভাবে স্থানীয় পরিবর্তনগুলি সন্ধানের জন্য read_f, python.org/doc/essays/list2str এ করতে পারে
দ্য রেড মটর

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

যদি কেউ লিনাক্সের পাইথনে সস্তাভাবে লাইন গণনা পেতে চায় তবে আমি এই পদ্ধতির প্রস্তাব দিই:

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

ফাইল_পথ বিমূর্ত ফাইল পথ বা আপেক্ষিক পথ উভয়ই হতে পারে। আশা করি এটি সাহায্য করতে পারে।


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

এই উত্তরটি কেন হ্রাস পেয়েছে সে সম্পর্কে আমি আগ্রহী। এটি লাইন দ্বারা ফাইলটি পুনরাবৃত্তি করে এবং তাদের যোগফল দেয়। আমি এটি পছন্দ করি, এটি সংক্ষিপ্ত এবং বিন্দুতে, এতে কী দোষ আছে?
সিউজার

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 এমবি ফাইল মেমোরিতে পড়তে হবে।
সাইলেন্টগোস্ট

হ্যাঁ, ভাল কথা, যদিও আমি গতির (স্মৃতির বিপরীতে) পার্থক্য সম্পর্কে অবাক হই। এটি করে এমন একটি পুনরুক্তি তৈরি করা সম্ভবত সম্ভব, তবে আমি মনে করি এটি আপনার সমাধানের সমান হবে।
অ্যান্ড্রু জাফি

6
-1, এটি কেবল মেমরি নয়, স্মৃতিতে তালিকাটি তৈরি করতে হবে।
21:14

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.