স্মৃতিতে লোড না করে আমি কীভাবে পাইথন-এ বড় টেক্সট ফাইলগুলি এক এক করে লাইনে পড়তে পারি?


239

আমাকে লাইন লাইন একটি বড় ফাইল পড়তে হবে। বলুন যে ফাইলটিতে 5 গিগাবাইটের বেশি রয়েছে এবং আমার প্রতিটি লাইন পড়তে হবে, তবে স্পষ্টতই আমি ব্যবহার করতে চাই না readlines()কারণ এটি স্মৃতিতে একটি খুব বড় তালিকা তৈরি করবে।

এই ক্ষেত্রে নীচের কোডটি কীভাবে কাজ করবে? xreadlinesনিজেই কি একের পর এক স্মৃতিতে পড়ছে? জেনারেটর এক্সপ্রেশন প্রয়োজন?

f = (line for line in open("log.txt").xreadlines())  # how much is loaded in memory?

f.next()  

এছাড়াও, লিনাক্স tailকমান্ডের মতো, বিপরীত ক্রমে এটি পড়তে আমি কী করতে পারি ?

আমি পেয়েছি:

http://code.google.com/p/pytailer/

এবং

" অজগর মাথা, লেজ এবং পিছনে একটি পাঠ্য ফাইলের লাইনে পড়া "

দুজনেই খুব ভাল কাজ করেছেন!


এবং লেজ থেকে এটি পড়তে আমি কী করতে পারি? সর্বশেষ লাইনে শুরু করে এক লাইনে লাইন।
ব্রুনো রোচা - রোচব্রুনো

এটি পৃথক প্রশ্ন হওয়া উচিত
2

1
ডুপ্লিকেট stackoverflow.com/questions/5896079/...
cmcginty

উত্তর:


310

আমি এই উত্তরটি সরবরাহ করেছি কারণ কীথের, সংক্রামিত অবস্থায়, ফাইলটি স্পষ্টভাবে বন্ধ করা হয়নি

with open("log.txt") as infile:
    for line in infile:
        do_something_with(line)

30
এখনও প্রশ্নটি হচ্ছে, "ইনফাইলে লাইনের জন্য" কি আমার 5 গিগাবাইট লাইন স্মৃতিতে লোড করবে? এবং, আমি পুচ্ছ থেকে কীভাবে পড়তে পারি?
ব্রুনো রোচা - রোচব্রুনো

66
@ ক্র্যাচব্রুনো, এটি একবারে কেবল একটি লাইন পড়ে। পরের লাইনটি পড়লে, পূর্ববর্তীটি আবর্জনা সংগ্রহ করা হবে যদি না আপনি অন্য কোথাও এর কোনও রেফারেন্স সঞ্চয় না করে থাকেন
জন লা রুই

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

4
ধন্যবাদ! আমি লেজ সমাধান পাওয়া stackoverflow.com/questions/5896079/...
rochacbruno - ব্রুনো Rocha,

1
@ বাবেজাকুনাল, আপনি কি বোঝাতে চাইছেন যে যদি কোনও লাইন একবারে স্মৃতিতে লোড করার জন্য খুব দীর্ঘ হয়? এটি একটি পাঠ্য ফাইলের জন্য অস্বাভাবিক । forলুপগুলি যা লাইনগুলিতে পুনরাবৃত্তি করে তা ব্যবহার করার পরিবর্তে , আপনি chunk = infile.read(chunksize)তাদের বিষয়বস্তু নির্বিশেষে সীমিত আকারের অংশগুলি পড়তে ব্যবহার করতে পারেন । নিজেকে নতুন লাইনের জন্য খণ্ডগুলির মধ্যে অনুসন্ধান করতে হবে।
জন লা রুই

60

আপনাকে যা করতে হবে তা হ'ল ফাইল অবজেক্টটিকে পুনরুক্তি হিসাবে ব্যবহার করা।

for line in open("log.txt"):
    do_something_with(line)

এর চেয়েও ভাল সাম্প্রতিক পাইথন সংস্করণগুলিতে প্রসঙ্গ পরিচালককে ব্যবহার করা।

with open("log.txt") as fileobject:
    for line in fileobject:
        do_something_with(line)

এটি স্বয়ংক্রিয়ভাবে ফাইলটিও বন্ধ করে দেবে।


2
পুরো স্মৃতিতে লোড হচ্ছে না?
ব্রুনো রোচা - রোচাব্রুনো

17

একটি পুরানো স্কুল পদ্ধতির:

fh = open(file_name, 'rt')
line = fh.readline()
while line:
    # do stuff with line
    line = fh.readline()
fh.close()

2
সামান্য মন্তব্য: ব্যতিক্রম সুরক্ষার জন্য আপনার ক্ষেত্রে "উইথ" স্টেটমেন্ট ব্যবহার করার পরামর্শ দেওয়া হয়, "খোলা (ফাইলের নাম, 'আরটি') দিয়ে
এফ

16
@ প্রোখের: হ্যাঁ, তবে আমি এই "পুরাতন স্কুল" বলি।
পিটিবিএনএল

15

পরিবর্তে একটি পুনরাবৃত্তি ব্যবহার করে আপনি ভাল। প্রাসঙ্গিক: http://docs.python.org/library/fileinput.html

দস্তাবেজগুলি থেকে:

import fileinput
for line in fileinput.input("filename"):
    process(line)

এটি একবারে পুরো ফাইলটি মেমোরিতে অনুলিপি করা এড়াবে।


যদিও দস্তাবেজগুলি স্নিপেটকে "সাধারণ ব্যবহার" হিসাবে দেখায়, লুপটি শেষ হওয়ার পরে এটি ব্যবহার close()করে ফিরে আসা FileInputশ্রেণীর অবজেক্টের পদ্ধতিটিকে কল করে না - সুতরাং আমি এটি এভাবে ব্যবহার করা এড়াতে চাই। পাইথন ৩.২-এ তারা শেষ পর্যন্ত fileinputপ্রাসঙ্গিক পরিচালক প্রোটোকলের সাথে সামঞ্জস্যপূর্ণ করেছে যা এই সমস্যাটিকে সম্বোধন করে (তবে কোডটি এখনও দেখানো পথে বেশিরভাগভাবে লেখা হবে না)।
মার্টিনো

7

আপনি যদি ফাইলে নতুন লাইন না পান তবে এখানে আপনি কী করবেন:

with open('large_text.txt') as f:
  while True:
    c = f.read(1024)
    if not c:
      break
    print(c)

যখন আমি এই পদ্ধতিটি পছন্দ করি, আপনি নিজের পাঠ্যে লাইন পড়ার ঝুঁকিটি ভাগ করে দিন। আমি এটি ব্যক্তিগতভাবে দেখেছি যার অর্থ আপনি যদি আমার মতো ফাইলে স্টারস্টিং অনুসন্ধান করে থাকেন তবে আমি কিছু মিস করব কারণ তারা যে রেখাটি ছিল তার রেখাটি খণ্ড খণ্ড হয়ে গেছে। এই কাছাকাছি পেতে একটি উপায় আছে? রিডলাইনগুলি ব্যবহার করা ঠিক তেমন কার্যকর হয়নি কারণ আমি @ আরিল ক্যাবিবকে ভুল পেয়েছি
এডো ১০১১

6

দয়া করে এটি চেষ্টা করুন:

with open('filename','r',buffering=100000) as f:
    for line in f:
        print line

দয়া করে ব্যাখ্যা করুন?
নিখিল ভিজে

3
পাইথনের অফিসিয়াল ডকুমিনেটস থেকে: লিঙ্ক alচ্ছিক বাফারিং যুক্তিটি ফাইলের পছন্দসই বাফার আকারটি নির্দিষ্ট করে: 0 এর অর্থ আনবার্ফার্ড নয়, 1 টি লাইন বাফার করেছে, অন্য কোনও ধনাত্মক মান বলতে বোঝায় যে আকারের (আনুমানিক) বাফারটি ব্যবহার করুন। নেতিবাচক বাফারিংয়ের অর্থ সিস্টেম ডিফল্ট ব্যবহার করা হয় যা সাধারণত টিটি ডিভাইসগুলির জন্য লাইন বাফার হয় এবং অন্য ফাইলগুলির জন্য সম্পূর্ণ বাফার হয়। বাদ দেওয়া থাকলে, সিস্টেম ডিফল্টটি ব্যবহৃত হয়
জ্যোতি দাস

আমার দিনটি সংরক্ষণ করা হয়েছে, আমার ক্ষেত্রে,> চারটি জিবি ফাইলের সাথে দুটি ফাইল হ্যান্ডলারের সাথে (এক পড়ুন, অন্যটি লিখুন) অজগরটি ঝুলছিল এবং এখন ঠিক আছে! ধন্যবাদ।
এক্সেল্ট

@ জ্যোতিডাস আমার এই পদ্ধতিটি পছন্দ করার পরেও আপনি আপনার পাঠ্যকে ফাঁকে ফাঁকে ফেলার ঝুঁকিটি চালান run আমি এটি ব্যক্তিগতভাবে দেখেছি যার অর্থ আপনি যদি আমার মতো ফাইলে স্টারস্টিং অনুসন্ধান করে থাকেন তবে আমি কিছু মিস করব কারণ তারা যে রেখাটি ছিল তার রেখাটি খণ্ড খণ্ড হয়ে গেছে। এই কাছাকাছি পেতে একটি উপায় আছে? রিডলাইনগুলি ব্যবহার করা ভাল কাজ করেনি কারণ আমি
মিসকাউন্ট

3

@ জন-লা-রোয়ের উত্তর দেখে মনে হয়েছিল যে এটি এতটা সহজ হতে পারে আমি বিশ্বাস করতে পারি না। সুতরাং, আমি cpলাইন রিডিং এবং রাইটিং দ্বারা লাইন ব্যবহার করে কমান্ডটি পুনরায় তৈরি করেছি । এটি ক্রেজি দ্রুত।

#!/usr/bin/env python3.6

import sys

with open(sys.argv[2], 'w') as outfile:
    with open(sys.argv[1]) as infile:
        for line in infile:
            outfile.write(line)

দ্রষ্টব্য: পাইথনের readlineলাইনের সমাপ্তিটিকে মানীকৃত করার কারণে \r\nএটি ডক্স লাইন শেষের ডিক্স লাইন এন্ডিংয়ের সাথে ডকুমেন্টকে রূপান্তর করার পার্শ্ব প্রতিক্রিয়া রাখে \n। এই বিষয়টি অনুসন্ধান করার জন্য আমার পুরো কারণটি হ'ল আমাকে এমন লগ ফাইলটি রূপান্তর করতে হবে যা লাইন শেষের ঝাঁকুনি প্রাপ্ত করে (কারণ বিকাশকারী অন্ধভাবে বিভিন্ন .NET লাইব্রেরি ব্যবহার করেছিল)। আমার প্রাথমিক গতির পরীক্ষার পরে আমি স্তম্ভিত হয়ে গিয়েছিলাম, আমার আর ফিরে যাওয়ার দরকার নেই rstrip। এটি ইতিমধ্যে নিখুঁত ছিল!
ব্রুনো ব্রোনোস্কি

2

আলোকচ্ছটা প্রকল্পের গত 6 বছর ধরে একটি দীর্ঘ পথ আসা হয়েছে। এটিতে একটি সহজ এপিআই রয়েছে যা পান্ডাস বৈশিষ্ট্যগুলির একটি দরকারী উপসেটটি coveringেকে দেয়।

dask.dataframe অভ্যন্তরীণভাবে খননের যত্ন নেয়, অনেক সমান্তরাল ক্রিয়াকলাপ সমর্থন করে এবং মেমরির ক্রিয়াকলাপের জন্য আপনাকে সহজেই পান্ডসে ফালিগুলি রফতানি করতে দেয়।

import dask.dataframe as dd

df = dd.read_csv('filename.csv')
df.head(10)  # return first 10 rows
df.tail(10)  # return last 10 rows

# iterate rows
for idx, row in df.iterrows():
    ...

# group by my_field and return mean
df.groupby(df.my_field).value.mean().compute()

# slice by column
df[df.my_field=='XYZ'].compute()

2

মেমরি সমস্যা সৃষ্টি না করে যে কোনও আকারের পাঠ্য ফাইলগুলি লোড করার জন্য কোডটি এখানে। এটি গিগাবাইট আকারের ফাইলগুলিকে সমর্থন করে

https://gist.github.com/iyvinjose/e6c1cb2821abd5f01fd1b9065cbc759d

ফাইল_ডিলিং_ইটিলস.পি ফাইলটি ডাউনলোড করুন এবং এটি আপনার কোডে আমদানি করুন

ব্যবহার

import data_loading_utils.py.py
file_name = 'file_name.ext'
CHUNK_SIZE = 1000000


def process_lines(data, eof, file_name):

    # check if end of file reached
    if not eof:
         # process data, data is one single line of the file

    else:
         # end of file reached

data_loading_utils.read_lines_from_file_as_data_chunks(file_name, chunk_size=CHUNK_SIZE, callback=self.process_lines)

process_lines পদ্ধতি কলব্যাক ফাংশন। এটি সমস্ত লাইনের জন্য ডেকে আনা হবে, প্যারামিটার ডেটা একসাথে ফাইলের একক লাইন উপস্থাপন করে।

আপনার মেশিন হার্ডওয়্যার কনফিগারেশনগুলির উপর নির্ভর করে আপনি পরিবর্তনশীল CHUNK_SIZE কনফিগার করতে পারেন ।


যখন আমি এই পদ্ধতিটি পছন্দ করি, আপনি নিজের পাঠ্যে লাইন পড়ার ঝুঁকিটি ভাগ করে দিন। আমি এটি ব্যক্তিগতভাবে দেখেছি যার অর্থ আপনি যদি আমার মতো ফাইলে স্টারস্টিং অনুসন্ধান করে থাকেন তবে আমি কিছু মিস করব কারণ তারা যে রেখাটি ছিল তার রেখাটি খণ্ড খণ্ড হয়ে গেছে। এই কাছাকাছি পেতে একটি উপায় আছে? রিডলাইনগুলি ব্যবহার করা ভাল কাজ করেনি কারণ আমি
মিসকাউন্ট

0

এ কেমন? আপনার ফাইলটিকে খণ্ডগুলিতে ভাগ করুন এবং তারপরে একে একে লাইনটি পড়ুন, কারণ আপনি যখন কোনও ফাইল পড়বেন তখন আপনার অপারেটিং সিস্টেমটি পরের লাইনে ক্যাশে যাবে। আপনি যদি লাইন দিয়ে ফাইলটি লাইন পড়ছেন তবে আপনি ক্যাশেড তথ্যটি দক্ষভাবে ব্যবহার করছেন না।

পরিবর্তে, ফাইলটিকে খণ্ডগুলিতে ভাগ করুন এবং পুরো অংশটিকে মেমরিতে লোড করুন এবং তারপরে আপনার প্রক্রিয়াজাতকরণ করুন।

def chunks(file,size=1024):
    while 1:

        startat=fh.tell()
        print startat #file's object current position from the start
        fh.seek(size,1) #offset from current postion -->1
        data=fh.readline()
        yield startat,fh.tell()-startat #doesnt store whole list in memory
        if not data:
            break
if os.path.isfile(fname):
    try:
        fh=open(fname,'rb') 
    except IOError as e: #file --> permission denied
        print "I/O error({0}): {1}".format(e.errno, e.strerror)
    except Exception as e1: #handle other exceptions such as attribute errors
        print "Unexpected error: {0}".format(e1)
    for ele in chunks(fh):
        fh.seek(ele[0])#startat
        data=fh.read(ele[1])#endat
        print data

এটি আশাব্যঞ্জক মনে হচ্ছে। এটি কি বাইট বা লাইনের মাধ্যমে লোড হচ্ছে? আমি লাইনগুলি বাইট দ্বারা ভেঙে যাওয়ার ভয় পাচ্ছি .. আমরা কীভাবে একবারে 1000 লাইন লোড করতে পারি এবং এটি প্রক্রিয়া করি?
নিখিল ভিজে

0

ধন্যবাদ! আমি সম্প্রতি অজগর 3 তে রূপান্তরিত করেছি এবং বড় ফাইলগুলি পড়ার জন্য রিডলাইনগুলি (0) ব্যবহার করে হতাশ হয়েছি। এটি সমস্যার সমাধান করেছে। তবে প্রতিটি লাইন পেতে, আমাকে বেশ কয়েকটি অতিরিক্ত পদক্ষেপ করতে হয়েছিল। প্রতিটি লাইন একটি "বি" দ্বারা পূর্ববর্তী ছিল যা আমি অনুমান করি যে এটি বাইনারি ফর্ম্যাটে ছিল। "ডিকোড (utf-8)" ব্যবহার করে এটি ascii পরিবর্তন করে।

তারপরে আমাকে প্রতিটি লাইনের মাঝখানে একটি "= \ n" সরিয়ে ফেলতে হয়েছিল।

তারপরে আমি নতুন লাইনে লাইনগুলি বিভক্ত করেছি।

b_data=(fh.read(ele[1]))#endat This is one chunk of ascii data in binary format
        a_data=((binascii.b2a_qp(b_data)).decode('utf-8')) #Data chunk in 'split' ascii format
        data_chunk = (a_data.replace('=\n','').strip()) #Splitting characters removed
        data_list = data_chunk.split('\n')  #List containing lines in chunk
        #print(data_list,'\n')
        #time.sleep(1)
        for j in range(len(data_list)): #iterate through data_list to get each item 
            i += 1
            line_of_data = data_list[j]
            print(line_of_data)

आरोহির কোডটিতে "মুদ্রিত ডেটা" এর ঠিক উপরে কোডটি এখানে দেওয়া হচ্ছে।


0

আমি এই অন্যান্য প্রশ্নে এখানে সমান্তরাল বাইট স্তরের এলোমেলো অ্যাক্সেসের পদ্ধতির প্রদর্শন করেছি:

পাঠ্যলাইন ছাড়াই একটি পাঠ্য ফাইলে লাইনের সংখ্যা পাওয়া

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


0

এটি সম্পর্কে আমি সবচেয়ে ভাল সমাধান খুঁজে পেয়েছি এবং আমি এটি 330 এমবি ফাইল দিয়ে চেষ্টা করেছি।

lineno = 500
line_length = 8
with open('catfour.txt', 'r') as file:
    file.seek(lineno * (line_length + 2))
    print(file.readline(), end='')

যেখানে লাইন_ দৈর্ঘ্য হ'ল এক লাইনের অক্ষরের সংখ্যা। উদাহরণস্বরূপ "abcd" এর লাইনের দৈর্ঘ্য 4 আছে।

'Character n' চরিত্রটি এড়িয়ে পরবর্তী অক্ষরটিতে যেতে আমি লাইনের দৈর্ঘ্যে 2 যোগ করেছি।


-1

আপনি যখন সমান্তরালভাবে কাজ করতে চান এবং কেবলমাত্র বিশদ ডেটা পড়তে চান তবে এটি নতুন লাইনে পরিষ্কার রাখতে চাইলে এটি কার্যকর হতে পারে।

def readInChunks(fileObj, chunkSize=1024):
    while True:
        data = fileObj.read(chunkSize)
        if not data:
            break
        while data[-1:] != '\n':
            data+=fileObj.read(1)
        yield data

-10
f=open('filename','r').read()
f1=f.split('\n')
for i in range (len(f1)):
    do_something_with(f1[i])

আশাকরি এটা সাহায্য করবে.


5
এটি কি পুরো ফাইলটি স্মৃতিতে পড়বে না? প্রশ্নটি কীভাবে এড়ানো যায় তা স্পষ্টভাবে জিজ্ঞাসা করে, সুতরাং এটি প্রশ্নের উত্তর দেয় না।
ফার্মি প্যারাডক্স
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.