我正在使用Python,并希望在不删除或复制文件的情况下将字符串插入文本文件。我该怎么做呢?
当前回答
Python的mmap模块将允许您插入到文件中。下面的示例展示了如何在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 -这可能非常大。
其他回答
这取决于你想做什么。你可以用"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
不幸的是,没有办法在不重写文件的情况下插入到文件中间。正如之前的海报所指出的,你可以使用seek附加到一个文件或覆盖它的一部分,但如果你想在开始或中间添加东西,你必须重写它。
这是操作系统的问题,不是Python的问题。这在所有语言中都是一样的。
我通常会从文件中读取,进行修改,并将其写入一个名为myfile.txt.tmp的新文件或类似的文件。这比将整个文件读入内存要好,因为文件可能太大了。临时文件完成后,我将其重命名为与原始文件相同的名称。
这是一种很好的、安全的方法,因为如果文件写入由于任何原因崩溃或中止,您仍然拥有原始文件。
Python的mmap模块将允许您插入到文件中。下面的示例展示了如何在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 -这可能非常大。
如果你使用inplace=1参数,Python标准库的fileinput模块将会inplace重写文件:
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
写了一个小类来干净地做这件事。
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