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

评论

您可以参考Alex Martelli的答案。

stackoverflow.com/a/4358169/538284

在python中的csv文件的最上一行上写入的可能重复项

@Ani,另一则帖子无论如何都是在文本文件的指定位置插入行的重复,并且肯定在这里有清晰明确的答案,为什么不在这里添加答案呢?接受答案不是一个好问题的要求。

@BhargavRao投票已撤回。我应该已经找到了重复的东西!

#1 楼

不幸的是,没有重写就无法插入文件中间。如先前的张贴者所指出的,您可以将文件追加到文件中或使用“搜索”覆盖文件的一部分,但是如果要在文件的开头或中间添加内容,则必须重写它。

此是操作系统的东西,而不是Python的东西。在所有语言中都是相同的。

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

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

评论


像awk / sed这样的unix工具在代码中是否做类似的事情?

– Manish Gill
13年3月22日在19:16

并非所有语言都一样。在ActionScript中:fileStream.openAsync(filename,FileMode.UPDATE);然后,我可以在文件中的任意位置进行更改。

– AndrewBenjamin
2014年7月11日在3:58



@AndrewBenjamin您知道ActionScript正在制作什么系统吗? openAsync是否有可能在调用之后读取文件并写入一个新文件?

– AlexLordThorsen
2014年12月2日在22:23

@Rawrgulmuffins我不知道。但是,我确实知道它不会将整个文件读入内存,因为我已经使用它来处理几GB的文件大小。我怀疑这与使用C#Streamwriter编写相同。我认为python是一种快速完成小事情的工具,而不是大规模开发和文件操作的工具。

– AndrewBenjamin
15年3月26日在21:48

@AndrewBenjamin,用户并没有要求在文件中四处寻找和更改它(我所知道的每种语言都可以做到这一点);他询问的是插入文本,这与简单地更改/覆盖文件中已有的内容不同。也许在实际应用中它有所不同,但是我在ActionScript API中找不到任何东西表明它在这方面与任何其他语言都不同。

– esstrada
15年7月22日在14:44

#2 楼

取决于您要做什么。要追加,可以用“ 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


评论


只是一小部分,要在Python 2.5中使用with语句,您需要添加“ from future import with_statement”。除此之外,与手动关闭相比,使用with语句打开文件绝对更具可读性,并且不易出错。

–亚历山大·科耶夫尼科夫(Alexander Kojevnikov)
08年9月24日在6:48

您可能会考虑在使用inline = True arg时,fileinput helper lib可以很好地处理脏的open / read / modify / write / replace例程。此处的示例:stackoverflow.com/a/2363893/47390

–mikegreenberg
2012年2月1日在21:14

只是不要忘记关闭文件。 f。关闭()

–D.Rosado
2012年5月2日14:35



我使用的不是D.Rosado样式,但是使用with样式时,我认为您无需手动关闭。 with跟踪其创建的资源。

–克里斯
2012年5月14日17:47

您不需要手动关闭文件。这就是在此处使用“ with”的全部意义。 (实际上,Python会在文件对象被垃圾回收后立即执行此操作,这在CPython中会在绑定到该对象的名称超出范围时发生……但是其他实现则不会,并且CPython可能有一天会停止这样做,因此建议使用“ with”)

–于尔根·艾哈德(JürgenA. Erhard)
13年6月22日在11:16

#3 楼

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


评论


这在python3中应该如何工作?我只是将一个具有这样的代码的应用程序从python移植到了python3,而我根本无法正常工作。 'line'变量是字节类型,我尝试将其解码为unicode,然后对其进行修改,然后再将其编码回字节,但它无法正常工作。这引起了一些我记不住脑海的异常。人们在python3中使用fileinput inplace = 1成功吗?

– robru
2015年2月21日在5:08

@Robru:这是Python 3代码

– jfs
16 Dec 19'在8:02

但这没问题,因为您首先在不重要的文件上对其进行了测试,对吗?

– Paula Livingstone
17年11月18日在13:55



#4 楼

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


评论


看起来不错。想知道.readlines()是否比迭代源更好?

– bozdoz
13年4月10日在15:48

@bozdoz:因为readlines读取整个文件,所以迭代更好。不适用于大文件。当然,这假定您可以以这种本地化的方式进行修改。有时您做不到,或者您的代码变得更加复杂。

–于尔根·艾哈德(JürgenA. Erhard)
13年6月22日在11:20

@ S.Lott:os.rename(aFile,aFile +“〜”)将修改源文件的名称,而不创建副本。

–Patapoom
3月12日9:39



#5 楼

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-这可能会很大。

#6 楼

正如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'\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()


#7 楼

编写了一小堂课,干净利落地做这件事。

评论


这对我个人而言不起作用,它确实向文件中添加了文本,但它首先删除了所有内容!

–布雷特·霍克(Bret Hawker)
19年1月12日在19:47

确实,这根本不起作用。丢脸,因为这似乎是个好主意。

–马里奥(MarioKrušelj)
19年6月14日在9:39

#8 楼

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

评论


根本不是Pythonic

– DarkSuniuM
19年5月27日在1:02