Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to modify a text file in-place?

I have a text file, (let's call it 'Potatoes.txt') containing the following info:

Town 1,300,
Town 2,205,
Town 3,600,
Town 4,910,
Town 5,360,

What I want to do is decrease the number for certain towns, and modify the text file accordingly. I did a little research and it appears you can't modify text files, and I need the text file to have the same name, just have different values inside it, so I'm currently doing this instead:

f = open("ModifiedPotatoes.txt","w")
f.close()

with open("Potatoes.txt","r") as file:
    for line in file:
       info = line.split(",")
       if "Town 2" or "Town 4" in line:
           info[1] -= 20
       with open("ModifiedPotatoes.txt","a"):
           infoStr = "\n" + ",".join(str(x) for x in info)
           file.write(infoStr)

f = open("Potatoes.txt","w")
f.close()

with open("ModifedPotatoes.txt","r") as file:
    for line in file:
        with open("Potatoes.txt","a") as potatoesFile:
            potatoesFile.write(line)

So basically I'm just overwriting the old file to a blank one, then copying the value from the modified/temporary file. Is there a better way to do this I'm missing?

like image 884
Dovahkiin Avatar asked Feb 24 '17 01:02

Dovahkiin


People also ask

How do you rewrite a text file?

Another way to create a text file is to right-click an empty area on the desktop, and in the pop-up menu, select New, and then select Text Document. Creating a text file this way opens your default text editor with a blank text file on your desktop. You can change the name of the file to anything you want.


2 Answers

I did a little research and it appears you can't modify text files

There is a module that gives you the same effect as modifying text as you loop over it. Try using the fileinput module with the inplace option set to True.

Here is a little Python3.6 code to get you started:

from fileinput import FileInput

with FileInput(files=['Potatoes.txt'], inplace=True) as f:
    for line in f:
        line = line.rstrip()
        info = line.split(",")
        if "Town 2" in line or "Town 4" in line:
            info[1] = int(info[1]) - 20
            line = ",".join(str(x) for x in info))
        print(line)
like image 168
Raymond Hettinger Avatar answered Sep 18 '22 01:09

Raymond Hettinger


It is possible to open a file for both reading and writing using mode "r+"

data = []
with open("temp", "r+") as inFile:
    for line in inFile:
        ar = line.split(",")
        if ar[0] in ("Town 2", "Town 4"):
            data.append( (ar[0], int(ar[1]) - 20, "\n") )
        else:
            data.append(ar)

    inFile.seek(0)
    for d in data:
        inFile.write(",".join([str(x) for x in d]))
    inFile.truncate()

In order to keep everything clean, I rewind the file after reading it using seek(0), write every line back into it from a buffer, and truncate any remaining part of the file before closing it. I would be interested to know if and when these operations aren't necessary.

This variation doesn't modify (clobber) any other files in the directory, which is a benefit in cases where the code might run simultaneously on different input files. I have no idea if only opening one file one time has any performance benefit, but it probably does to a small degree.

like image 23
Jeff K Avatar answered Sep 18 '22 01:09

Jeff K