我正在使用Python,并希望在不删除或复制文件的情况下将字符串插入文本文件。我该怎么做呢?


当前回答

如果你使用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

就地重写文件通常是通过用修改过的名称保存旧副本来完成的。Unix用户添加了一个~来标记旧的。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 + "~")

如果你知道一些unix,你可以尝试以下:

注意:$表示命令提示符

假设你有一个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)

如果您不了解sed,请查看它,它非常有用。

不幸的是,没有办法在不重写文件的情况下插入到文件中间。正如之前的海报所指出的,你可以使用seek附加到一个文件或覆盖它的一部分,但如果你想在开始或中间添加东西,你必须重写它。

这是操作系统的问题,不是Python的问题。这在所有语言中都是一样的。

我通常会从文件中读取,进行修改,并将其写入一个名为myfile.txt.tmp的新文件或类似的文件。这比将整个文件读入内存要好,因为文件可能太大了。临时文件完成后,我将其重命名为与原始文件相同的名称。

这是一种很好的、安全的方法,因为如果文件写入由于任何原因崩溃或中止,您仍然拥有原始文件。

如果你使用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