Замена строки Python в файле, не касаясь файла, если подстановка не была сделана - PullRequest
5 голосов
/ 13 марта 2011

Что Python возвращает string.replace, если не было подстановки строки?Всегда ли Python file.open (f, 'w') затрагивает файл, даже если не было внесено никаких изменений?

Используя Python, я пытаюсь заменить вхождения «oldtext» на «newtext» в наборефайлов.Если файл содержит «старый текст», я хочу сделать замену и сохранить файл.В противном случае ничего не делать, поэтому файл сохраняет свою старую метку времени.

Следующий код работает нормально, за исключением того, что записываются все файлы, даже если не было подстановки строк, и у всех файлов новая метка времени.

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 - это общее количество файлов, а не количество измененных файлов.Какие-либо предложения?Спасибо.

Я использую Python 3.1.2 в Windows.

Ответы [ 3 ]

14 голосов
/ 13 марта 2011

Что делает Python's string.replace вернуть, если не было подстановки строки сделал

Возвращает исходную строку.

Всегда ли Python file.open (f, 'w') коснитесь файла, даже если никаких изменений не было сделал

Больше, чем просто прикосновение к файлу, он уничтожает любой контент f, который раньше содержал.

Таким образом, вы можете проверить, нужно ли переписать файл с помощью 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
4 голосов
/ 13 марта 2011

Что Python возвращает string.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)   
2 голосов
/ 15 марта 2011

Ваш случай является частным случаем: 'newtext' имеет точно такое же количество символов, что и 'oldtext' .

Следовательно, можно использовать один из следующих кодов, чтобы точно заменить слово 'oldtext' или строку, в которой присутствует слово 'oldtext' , словом 'newtext' или строкой, в которой 'newtext' заменяет 'oldtext' .

.

Если файлы имеют не очень большой размер, содержимое каждого файла может быть полностью прочитано в память:

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

.

Эти программы делают минимум.Поэтому я думаю, что они быстрые.

.

Nota bene : файл, открытый в режиме 'rb+', не имеет изменения времени его последней модификации, если нет измененийбыло выполнено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...