Python在文件中替换字符串,未更改则不触碰文件

5 投票
3 回答
6034 浏览
提问于 2025-04-16 13:34

如果在Python中使用字符串的replace方法,但没有进行任何替换,它会返回什么?另外,使用Python的file.open(f, 'w')时,即使没有做任何更改,文件也会被更新吗?

我在用Python尝试把一组文件中的'oldtext'替换成'newtext'。如果文件里有'oldtext',我想替换并保存文件;如果没有,就什么都不做,这样文件的时间戳就不会改变。

下面的代码运行得很好,但问题是所有文件都会被写入,即使没有进行字符串替换,所有文件的时间戳也都会更新。

for match in all_files('*.html', '.'):  # all_files returns all html files in current directory     
  thefile = open(match)
  content = thefile.read()              # read entire file into memory
  thefile.close()
  thefile = open(match, 'w')             
  thefile.write(content.replace(oldtext, newtext))  # write the file with the text substitution
  thefile.close()

在这段代码中,我想只有在发生字符串替换时才执行file.write,但结果是所有文件的时间戳都被更新了:

count = 0
for match in all_files('*.html', '.'):       # all_files returns all html files in current directory
    thefile = open(match)
    content = thefile.read()                 # read entire file into memory
    thefile.close()
    thefile = open(match, 'w')
    replacedText = content.replace(oldtext, newtext) 
    if replacedText != '':
        count += 1
        thefile.write(replacedText)
    thefile.close()
print (count)        # print the number of files that we modified

最后,count是文件的总数,而不是被修改的文件数。有什么建议吗?谢谢。

我在Windows上使用的是Python 3.1.2。

相关问题:

3 个回答

3

你的情况是一个特殊的例子:'newtext''oldtext' 的字符数是完全相同的。

因此,可以使用以下代码之一,准确地将一个单词'oldtext'或包含这个单词的整行,替换为'newtext'或包含'newtext'的整行。

.

如果文件的大小不是特别大,可以将每个文件的内容全部读入内存:

from os import fsync      # code using find()

count = 0
for match in all_files('*.html', '.'):
    with open(match,'rb+') as thefile:
        diag = False
        fno = thefile.fileno()
        content = thefile.read()
        thefile.seek(0,0)
        x = content.find('oldtext')
        while x>=0:
            diag = True
            thefile.seek(x,1)
            thefile.write('newtext')
            thefile.flush()
            fsync(fno)
            x = content[thefile.tell():].find('oldtext')
    if diag:
        cnt += 1

或者

from os import fsync     # code using a regex
import re
pat = re.compile('oldtext')

count = 0
for match in all_files('*.html', '.'):
    with open(match,'rb+') as thefile:
        diag = False
        fno = thefile.fileno()
        content = thefile.read()
        thefile.seek(0,0)
        prec = 0
        for mat in pat.finditer(content):
            diag = True
            thefile.seek(mat.start()-prec,1)
            thefile.write('newtext')
            thefile.flush()
            fsync(fno)
            prec = mat.end()
    if diag:
        cnt += 1

.

对于较大的文件,可以逐行读取和重写:

from os import fsync   # code for big files, using regex
import re
pat = re.compile('oldtext')

count = 0
for match in all_files('*.html', '.'):
    with open(match,'rb+') as thefile:
        diag = False
        fno = thefile.fileno()
        line = thefile.readline()
        while line:
            if 'oldtext' in line:
                diag = True
                thefile.seek(-len(line),1)
                thefile.write(pat.sub('newtext',line))
                thefile.flush()
                fsync(fno) 
            line = thefile.readline()
    if diag:
        cnt += 1

.

在每次写入后,需要使用 thefile.flush()fsync(fno) 这两个指令,以确保文件处理器 thefile 在任何时候都能准确指向文件中的确切位置。这样可以确保通过 write() 指令进行有效的写入。

flush() 不一定会将文件的数据写入磁盘。使用 flush() 后再调用 os.fsync() 可以确保这个行为。 http://docs.python.org/library/stdtypes.html#file.flush

.

这些程序做的事情是最基本的,所以我认为它们的速度很快。

.

注意以模式 'rb+' 打开的文件,如果没有进行任何修改,其最后修改时间不会改变。

4

如果在Python中使用字符串的.replace方法,但没有进行任何替换,它会返回什么?

str.replace() 方法会返回原来的字符串,或者如果这个对象是字符串的子类,它会返回一个字符串的副本。

在Python中,使用file.open(f, 'w')时,即使没有做任何更改,文件也会被修改吗?

open(f, 'w') 会打开文件 f 并清空它的内容。

请注意,下面的代码是针对CPython的,不能在pypy或jython上正常工作:

count = 0
for match in all_files('*.html', '.'):
    content = open(match).read()
    replacedText = content.replace(oldtext, newtext) 
    if replacedText is not content:
       count += 1
       open(match, 'w').write(replacedText)
print (count)   
14

如果Python的字符串替换(string.replace)没有进行任何替换,它会返回什么?

它会返回原来的字符串。

Python的文件打开(file.open(f, 'w'))即使没有做任何更改,也总是会触碰到文件吗?

不仅仅是触碰文件,它还会删除文件中原本的内容。

所以,你可以通过检查 if replacedText != content 来判断文件是否需要被重新写入,只有在这种情况下才打开文件进行写入:

count = 0
for match in all_files('*.html', '.'):       # all_files returns all html files in current directory
    with open(match) as thefile:
        content = thefile.read()                 # read entire file into memory
        replacedText = content.replace(oldtext, newtext)
    if replacedText!=content:
        with open(match, 'w') as thefile:
            count += 1
            thefile.write(replacedText)
print (count)        # print the number of files that we modified

撰写回答