如何修改文本文件?

时间:2008-09-24 06:30:57

标签: python file text

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

8 个答案:

答案 0 :(得分:127)

不幸的是,如果不重写它,就无法插入到文件的中间。正如之前的海报所示,您可以使用搜索附加到文件或覆盖部分文件,但如果您想在开头或中间添加内容,则必须重写它。

这是一个操作系统的东西,而不是Python的东西。它在所有语言中都是一样的。

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

这是一种安全的好方法,因为如果文件写入因任何原因而崩溃或中止,您仍然可以使用原始文件。

答案 1 :(得分:94)

取决于你想做什么。要追加你可以用“a”打开它:

 with open("foo.txt", "a") as f:
     f.write("new line\n")

如果您想预先制作一些必须先从文件中读取的内容:

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

答案 2 :(得分:64)

如果使用inplace = 1参数,Python标准库的fileinput模块将在本地重写文件:

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

答案 3 :(得分:31)

通常使用修改后的名称保存旧副本来重写文件。 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+"~" )

答案 4 :(得分:14)

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 - 这可能是巨大的。

答案 5 :(得分:12)

正如Adam所提到的,你必须考虑系统限制,然后才能决定是否有足够的内存将其全部读入内存替换它的部分并重新编写它。

如果您正在处理小文件或没有内存问题,这可能会有所帮助:

选项1) 将整个文件读入内存,在整个或部分行上进行正则表达式替换,并用该行加上额外的行替换它。您需要确保文件中的“中间线”是唯一的,或者如果每行都有时间戳,这应该非常可靠。

# 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()

答案 6 :(得分:1)

为干净利落地写了一个小班。

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

答案 7 :(得分:1)

如果您知道一些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,请检查一下,它非常有用。