আমার অনুরূপ প্রশ্নের উত্তরে মন্তব্যকারীদের অনুরোধে একটি উত্তর পোস্ট করা যেখানে একই কৌশলটি কোনও ফাইলের শেষ লাইনটি পরিবর্তনের জন্য ব্যবহার করা হয়েছিল, কেবল এটিই পাওয়া গেল না।
গুরুত্বপূর্ণ আকারের একটি ফাইলের জন্য, mmap
এটি করার সর্বোত্তম উপায়। বিদ্যমান mmap
উত্তরের উন্নতি করতে , এই সংস্করণটি উইন্ডোজ এবং লিনাক্সের মধ্যে বহনযোগ্য এবং দ্রুত চালিত হওয়া উচিত (যদিও এটি জিবি রেঞ্জের ফাইলগুলির সাথে 32 বিট পাইথন-এ কিছু পরিবর্তন না করে কাজ করবে না, এটি পরিচালনা করার জন্য অন্যান্য উত্তর দেখুন , এবং পাইথন 2 এ কাজ করতে সংশোধন করার জন্য )।
import io # Gets consistent version of open for both Py2.7 and Py3.x
import itertools
import mmap
def skip_back_lines(mm, numlines, startidx):
'''Factored out to simplify handling of n and offset'''
for _ in itertools.repeat(None, numlines):
startidx = mm.rfind(b'\n', 0, startidx)
if startidx < 0:
break
return startidx
def tail(f, n, offset=0):
# Reopen file in binary mode
with io.open(f.name, 'rb') as binf, mmap.mmap(binf.fileno(), 0, access=mmap.ACCESS_READ) as mm:
# len(mm) - 1 handles files ending w/newline by getting the prior line
startofline = skip_back_lines(mm, offset, len(mm) - 1)
if startofline < 0:
return [] # Offset lines consumed whole file, nothing to return
# If using a generator function (yield-ing, see below),
# this should be a plain return, no empty list
endoflines = startofline + 1 # Slice end to omit offset lines
# Find start of lines to capture (add 1 to move from newline to beginning of following line)
startofline = skip_back_lines(mm, n, startofline) + 1
# Passing True to splitlines makes it return the list of lines without
# removing the trailing newline (if any), so list mimics f.readlines()
return mm[startofline:endoflines].splitlines(True)
# If Windows style \r\n newlines need to be normalized to \n, and input
# is ASCII compatible, can normalize newlines with:
# return mm[startofline:endoflines].replace(os.linesep.encode('ascii'), b'\n').splitlines(True)
এটি ধরে নেওয়া হয়েছে যে লেজযুক্ত রেখাগুলির সংখ্যা যথেষ্ট কম আপনি নিরাপদে সেগুলি একবারে স্মৃতিতে পড়তে পারেন; আপনি এটিকে একটি জেনারেটর ফাংশনও করতে পারেন এবং চূড়ান্ত লাইনটি প্রতিস্থাপনের মাধ্যমে একবারে ম্যানুয়ালি একটি লাইন পড়তে পারেন:
mm.seek(startofline)
# Call mm.readline n times, or until EOF, whichever comes first
# Python 3.2 and earlier:
for line in itertools.islice(iter(mm.readline, b''), n):
yield line
# 3.3+:
yield from itertools.islice(iter(mm.readline, b''), n)
শেষ অবধি mmap
, এটি বাইনারি মোডে (পড়ার জন্য প্রয়োজনীয় ) পড়ে তাই এটি str
লাইন দেয় (পাই 2) এবং bytes
লাইনগুলি (পাই 3); আপনি যদি unicode
(পাই 2) বা str
(পাই 3) চান তবে পুনরাবৃত্ত পদ্ধতির আপনার জন্য ডিকোড করতে এবং / অথবা নিউলাইনগুলি ঠিক করতে পারে:
lines = itertools.islice(iter(mm.readline, b''), n)
if f.encoding: # Decode if the passed file was opened with a specific encoding
lines = (line.decode(f.encoding) for line in lines)
if 'b' not in f.mode: # Fix line breaks if passed file opened in text mode
lines = (line.replace(os.linesep, '\n') for line in lines)
# Python 3.2 and earlier:
for line in lines:
yield line
# 3.3+:
yield from lines
দ্রষ্টব্য: আমি এগুলি সমস্ত এমন কোনও মেশিনে টাইপ করেছি যেখানে পরীক্ষার জন্য পাইথনে আমার অ্যাক্সেসের অভাব রয়েছে। আমি কিছু টাইপ করলে দয়া করে আমাকে জানান; এটি আমার অন্যান্য উত্তরের মতোই যথেষ্ট ছিল যা আমি মনে করি এটি কাজ করা উচিত, তবে টুইটগুলি (উদাহরণস্বরূপ একটি পরিচালনা করা offset
) সূক্ষ্ম ত্রুটির দিকে পরিচালিত করতে পারে। কোনও ভুল থাকলে দয়া করে আমাকে মন্তব্যে জানান know
seek(0,2)
তখনtell()
) পাওয়ার জন্য এটি সংশোধন করেছি এবং শুরুর তুলনায় সেই মানটি ব্যবহার করি।