ฉันใช้ Python และต้องการแทรกสตริงลงในไฟล์ข้อความโดยไม่ลบหรือคัดลอกไฟล์ ฉันจะทำสิ่งนั้นได้อย่างไร
ฉันใช้ Python และต้องการแทรกสตริงลงในไฟล์ข้อความโดยไม่ลบหรือคัดลอกไฟล์ ฉันจะทำสิ่งนั้นได้อย่างไร
คำตอบ:
น่าเสียดายที่ไม่มีวิธีการแทรกลงในกลางไฟล์โดยไม่ต้องเขียนใหม่ ดังที่ผู้โพสต์ก่อนหน้านี้ระบุไว้คุณสามารถต่อท้ายไฟล์หรือเขียนทับส่วนหนึ่งของมันโดยใช้การค้นหา แต่ถ้าคุณต้องการที่จะเพิ่มสิ่งต่าง ๆ ที่จุดเริ่มต้นหรือตรงกลางคุณจะต้องเขียนใหม่
นี่คือสิ่งที่ระบบปฏิบัติการไม่ใช่สิ่งที่หลาม มันเหมือนกันในทุกภาษา
สิ่งที่ฉันมักจะทำคืออ่านจากไฟล์ทำการแก้ไขและเขียนลงในไฟล์ใหม่ที่ชื่อว่า myfile.txt.tmp หรืออะไรทำนองนั้น วิธีนี้ดีกว่าการอ่านไฟล์ทั้งหมดในหน่วยความจำเพราะไฟล์อาจใหญ่เกินไป เมื่อไฟล์ชั่วคราวเสร็จสมบูรณ์ฉันจะเปลี่ยนชื่อไฟล์เหมือนกับไฟล์ต้นฉบับ
นี่เป็นวิธีที่ดีและปลอดภัยในการทำเพราะหากไฟล์เขียนขัดข้องหรือยกเลิกด้วยเหตุผลใดก็ตามคุณยังมีไฟล์ต้นฉบับที่ยังไม่ถูกแตะต้อง
ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำ ในการผนวกคุณสามารถเปิดด้วย "a":
with open("foo.txt", "a") as f:
f.write("new line\n")
หากคุณต้องการ preprend สิ่งที่คุณต้องอ่านจากไฟล์ก่อน:
with open("foo.txt", "r+") as f:
old = f.read() # read everything in the file
f.seek(0) # rewind
f.write("new line\n" + old) # write the new line before
with
คำสั่งใน Python 2.5 คุณจำเป็นต้องเพิ่ม "จากการนำเข้าในอนาคต with_statement" นอกจากนั้นการเปิดไฟล์ที่มีwith
คำสั่งนั้นสามารถอ่านได้ง่ายกว่าและมีข้อผิดพลาดน้อยกว่าการปิดแมนนวล
fileinput
ช่วย lib พร้อมกับจัดการรูทีน open / read / modified / write / replace สกปรกอย่างดีเมื่อใช้inline=True
ARG ตัวอย่างที่นี่: stackoverflow.com/a/2363893/47390
f.Close()
fileinput
โมดูลของห้องสมุดมาตรฐานหลามจะเขียนซ้ำ inplace ไฟล์ถ้าคุณใช้ inplace = 1 พารามิเตอร์:
import sys
import fileinput
# replace all occurrences of 'sit' with 'SIT' and insert a line after the 5th
for i, line in enumerate(fileinput.input('lorem_ipsum.txt', inplace=1)):
sys.stdout.write(line.replace('sit', 'SIT')) # replace 'sit' and write
if i == 4: sys.stdout.write('\n') # write a blank line after the 5th line
การเขียนไฟล์ซ้ำมักจะทำโดยการบันทึกสำเนาเก่าด้วยชื่อที่แก้ไข คน Unix เพิ่ม a ~
เพื่อทำเครื่องหมายเก่า ผู้ใช้ Windows ทำทุกสิ่ง - เพิ่ม. bak หรือ. old - หรือเปลี่ยนชื่อไฟล์ทั้งหมดหรือใส่เครื่องหมาย ~ ที่ด้านหน้าของชื่อ
import shutil
shutil.move( afile, afile+"~" )
destination= open( aFile, "w" )
source= open( aFile+"~", "r" )
for line in source:
destination.write( line )
if <some condition>:
destination.write( >some additional line> + "\n" )
source.close()
destination.close()
แทนที่จะshutil
ใช้คุณสามารถใช้สิ่งต่อไปนี้
import os
os.rename( aFile, aFile+"~" )
os.rename(aFile, aFile + "~")
จะแก้ไขชื่อของไฟล์ต้นฉบับไม่ใช่การสร้างสำเนา
โมดูล mmap ของ Python จะอนุญาตให้คุณแทรกลงในไฟล์ ตัวอย่างต่อไปนี้แสดงวิธีการที่สามารถทำได้ใน Unix (Windows mmap อาจแตกต่างกัน) โปรดทราบว่าสิ่งนี้ไม่ได้จัดการกับเงื่อนไขข้อผิดพลาดทั้งหมดและคุณอาจเสียหายหรือสูญเสียไฟล์ต้นฉบับ นอกจากนี้สิ่งนี้จะไม่จัดการกับสตริง Unicode
import os
from mmap import mmap
def insert(filename, str, pos):
if len(str) < 1:
# nothing to insert
return
f = open(filename, 'r+')
m = mmap(f.fileno(), os.path.getsize(filename))
origSize = m.size()
# or this could be an error
if pos > origSize:
pos = origSize
elif pos < 0:
pos = 0
m.resize(origSize + len(str))
m[pos+len(str):] = m[pos:origSize]
m[pos:pos+len(str)] = str
m.close()
f.close()
นอกจากนี้ยังเป็นไปได้ที่จะทำเช่นนี้โดยไม่ต้อง mmap กับไฟล์ที่เปิดในโหมด 'r +' แต่สะดวกและมีประสิทธิภาพน้อยลงเนื่องจากคุณต้องอ่านและจัดเก็บเนื้อหาของไฟล์ชั่วคราวจากตำแหน่งแทรกไปยัง EOF - ซึ่งอาจ ใหญ่
ตามที่กล่าวไว้โดย Adam คุณจะต้องคำนึงถึงข้อ จำกัด ของระบบของคุณก่อนจึงจะสามารถตัดสินใจได้ว่าคุณมีหน่วยความจำเพียงพอที่จะอ่านข้อมูลทั้งหมดลงในหน่วยความจำหรือไม่
หากคุณกำลังเผชิญกับไฟล์ขนาดเล็กหรือไม่มีปัญหาเรื่องความจำนี่อาจช่วยได้:
ตัวเลือก 1) อ่านไฟล์ทั้งหมดลงในหน่วยความจำทำการทดแทน regex ทั้งหมดหรือบางส่วนของบรรทัดแล้วแทนที่ด้วยบรรทัดนั้นบวกกับบรรทัดเพิ่มเติม คุณจะต้องตรวจสอบให้แน่ใจว่า 'เส้นกลาง' ไม่ซ้ำกันในไฟล์หรือถ้าคุณมีการประทับเวลาในแต่ละบรรทัดสิ่งนี้น่าจะน่าเชื่อถือ
# open file with r+b (allow write and binary mode)
f = open("file.log", 'r+b')
# read entire content of file into memory
f_content = f.read()
# basically match middle line and replace it with itself and the extra line
f_content = re.sub(r'(middle line)', r'\1\nnew line', f_content)
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(f_content)
# close file
f.close()
ตัวเลือก 2) ขบกลางบรรทัดและแทนที่ด้วยบรรทัดนั้นบวกกับบรรทัดพิเศษ
# open file with r+b (allow write and binary mode)
f = open("file.log" , 'r+b')
# get array of lines
f_content = f.readlines()
# get middle line
middle_line = len(f_content)/2
# overwrite middle line
f_content[middle_line] += "\nnew line"
# return pointer to top of file so we can re-write the content with replaced string
f.seek(0)
# clear file content
f.truncate()
# re-write the content with the updated content
f.write(''.join(f_content))
# close file
f.close()
เขียนชั้นเรียนขนาดเล็กเพื่อทำสิ่งนี้อย่างหมดจด
import tempfile
class FileModifierError(Exception):
pass
class FileModifier(object):
def __init__(self, fname):
self.__write_dict = {}
self.__filename = fname
self.__tempfile = tempfile.TemporaryFile()
with open(fname, 'rb') as fp:
for line in fp:
self.__tempfile.write(line)
self.__tempfile.seek(0)
def write(self, s, line_number = 'END'):
if line_number != 'END' and not isinstance(line_number, (int, float)):
raise FileModifierError("Line number %s is not a valid number" % line_number)
try:
self.__write_dict[line_number].append(s)
except KeyError:
self.__write_dict[line_number] = [s]
def writeline(self, s, line_number = 'END'):
self.write('%s\n' % s, line_number)
def writelines(self, s, line_number = 'END'):
for ln in s:
self.writeline(s, line_number)
def __popline(self, index, fp):
try:
ilines = self.__write_dict.pop(index)
for line in ilines:
fp.write(line)
except KeyError:
pass
def close(self):
self.__exit__(None, None, None)
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
with open(self.__filename,'w') as fp:
for index, line in enumerate(self.__tempfile.readlines()):
self.__popline(index, fp)
fp.write(line)
for index in sorted(self.__write_dict):
for line in self.__write_dict[index]:
fp.write(line)
self.__tempfile.close()
จากนั้นคุณสามารถใช้วิธีนี้:
with FileModifier(filename) as fp:
fp.writeline("String 1", 0)
fp.writeline("String 2", 20)
fp.writeline("String 3") # To write at the end of the file
หากคุณรู้ว่ายูนิกซ์คุณสามารถลองสิ่งต่อไปนี้:
หมายเหตุ: $ หมายถึงพรอมต์คำสั่ง
สมมติว่าคุณมีไฟล์ my_data.txt พร้อมเนื้อหาดังนี้:
$ cat my_data.txt
This is a data file
with all of my data in it.
จากนั้นใช้os
โมดูลที่คุณสามารถใช้sed
คำสั่งปกติ
import os
# Identifiers used are:
my_data_file = "my_data.txt"
command = "sed -i 's/all/none/' my_data.txt"
# Execute the command
os.system(command)
หากคุณไม่ทราบว่ามีสติอยู่ลองดูสิมันมีประโยชน์มาก