Illusionist
Illusionist

Reputation: 31

python - rewrite a file with modifications

I have a file called inputs.txt and I am trying to replace a string in that file with the value of a function. The problem is I am not able to write to that file. I just started learning python so struggling with this. Any help please.

When I have it as a string it works fine

Content of the file

[aws_s3://MAC_10]
key_name = ABC/YYZZ/daily

Desired output

[aws_s3://MAC_2014-12-31]
key_name = ABC/YYZZ/daily/2014-12-31_

I wrote the function which gets the time value as

def change_time(match):
    match = match.group()
    date_time = datetime.datetime.now()
    value = str(date_time.strftime('%Y-%m-%d'))
    return value

I was able to open the file and read and match content but I am not able to write to it

f=open('test.txt','w')

print re.sub(r'_[0-9-]+',change_time,string) outputs the required changed first line to stdout, but how do I modify the contents of the file?

Upvotes: 1

Views: 382

Answers (3)

stochastic
stochastic

Reputation: 3433

If you have not programmed much, it might be easy to think of a file as it is seen in an editor, where you can position your cursor at a particular point and insert characters at that point, causing other characters in the file to "slide to the right". Writing to a file does not work this way. Instead, writing a file at a particular point deletes all file contents after that point, meaning that you need to read the whole file into memory, modify the contents of the file, and then write the contents back out to the file.

More specifically, since the file will have a different number of bytes in it after your modifications, and all the insertion/deletion of characters do not happen at the end of the file, here is the procedure you generally want to follow:

First, you read the entire contents of the file into memory, something like

import io
with io.open('file.ini') as fobj:
    contents = fobj.read()

Note that after this code has run, the file is closed again: you have copied the contents of the file into memory, and the file remains unchanged on disk.

Next, you modify the contents of the file in your desired way

def change_time(match):
    match = match.group()
    date_time = datetime.datetime.now()
    value = str(date_time.strftime('%Y-%m-%d'))
    return value

new_contents = re.sub(r'_[0-9-]+',change_time,contents)

Now, you re-open the file in write mode. This immediately throws away the contents of the file, and you write back your own (now modified) copy from memory

with io.open('file.ini','wb') as fobj:
    fobj.write(new_contents)

Upvotes: 1

Alex Martelli
Alex Martelli

Reputation: 882291

Reading and writing the same file can be tricky, but the fileinput module of the standard library supports that well:

import fileinput

for line in fileinput.input(['inputs.txt'], inplace=True):
    print re.sub(r'_[0-9-]+', change_time, line) ,

I'm giving the Python 2 form of print because it seems that's what you're using. Anyway, in Python 3 it would be similar and more readable:

    print(re.sub(r'_[0-9-]+', change_time, line), end='')

At any rate, fileinput redirects standard output so that all prints go to the very file you're reading (when the inplace=True has been set) -- you need to print out all you're reading in, with changes were needed. Works on as many files as you need (note that the first argument is a list of filenames), no matter how big they are, etc, etc.

See https://docs.python.org/2/library/fileinput.html for much, much more:-)

Upvotes: 3

user590028
user590028

Reputation: 11728

The solution is to read in value, edit change in memory and write our new value

contents = open('file.ini').read()
contents = re.sub(r'_[0-9-]+',change_time,contents)
with open('file.ini', 'w') as fout:
    fout.write(contents)

Upvotes: 0

Related Questions