Reading a file and then overwriting it in Python - python

I've been trying to read a file and then overwrite it with some updated data.
I've tried doing it like this:
#Created filename.txt with some data
with open('filename.txt', 'r+') as f:
data = f.read()
new_data = process(data) # data is being changed
f.seek(0)
f.write(new_data)
For some reason, it doesn't overwrite the file and the content of it stays the same.

Truncate the file after seeking to the front. That will remove all of the existing data.
>>> open('deleteme', 'w').write('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
>>> f = open('deleteme', 'r+')
>>> f.read()
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> f.seek(0)
>>> f.truncate()
>>> f.write('bbb')
>>> f.close()
>>> open('deleteme').read()
'bbb'
>>>

You should add a call to truncate after seek as tdelaney suggested.
Try reading and writing in different scopes, the code is more clear that way and the data processing is not done when the file handlers are open.
data = ''
with open('filename.txt', 'r') as f:
data = f.read()
new_data = process(data)
with open('filename.txt', 'w+') as f:
f.write(new_data)

Related

How to write an array to a file and then call that file and add more to the array?

So as the title suggests I'm trying to write an array to a file, but then I need to recall that array and append more to it and then write it back to the same file, and then this same process over and over again.
The code I'm have so far is:
c = open(r"board.txt", "r")
current_position = []
if filesize > 4:
current_position = [c.read()]
print(current_position)
stockfish.set_position(current_position)
else:
stockfish.set_fen_position("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
#There is a lot more code here that appends stuff to the array but I don't want to #add anything that will be irrelevant to the problem
with open('board.txt', 'w') as filehandle:
for listitem in current_position:
filehandle.write('"%s", ' % listitem)
z = open(r"board.txt", "r")
print(z.read())
My array end up looking like this when I read the file
""d2d4", "d7d5", ", "a2a4", "e2e4",
All my code is on this replit if anyone needs more info
A few ways to do this:
First, use newline as a delimiter (simple, not the most space efficient):
# write
my_array = ['d2d4', 'd7d5']
with open('board.txt', 'w+') as f:
f.writelines([i + '\n' for i in my_array])
# read
with open('board.txt') as f:
my_array = f.read().splitlines()
If your character strings all have the same length, you don't need a delimiter:
# write
my_array = ['d2d4', 'd7d5'] # must all be length 4 strs
with open('board.txt', 'w+') as f:
f.writelines(my_array)
# read file, splitting string into groups of 4 characters
with open('board.txt') as f:
in_str = f.read()
my_array = [in_str[i:i+4] for i in range(0, len(in_str), 4)]
Finally, consider pickle, which allows writing/reading Python objects to/from binary files:
import pickle
# write
my_array = ['d2d4', 'd7d5']
with open('board.board', 'wb+') as f: # custom file extension, can be anything
pickle.dump(my_array, f)
# read
with open('board.board', 'rb') as f:
my_array = pickle.load(f)
as you're reusing the file to append data to it, you should replace:
open('board.txt', 'w')
with
open('board.txt', 'a')
a denotes append mode. Which will not overwrite what you have in your file, it will append to it.

How to read last string in a file

I have a file.txt which is saving as list
['Joe', '101', '/home/Joe', '43242', '/home/Joe/1.txt']
How to read the last element in the file here it is '/home/Joe/1.txt'
I tried to read
with open ('file.txt', r) as fr:
fd = fr.readlines()
print (fd[-1])
You could use ast.literal_eval()
from ast import literal_eval
with open("test.txt") as fp:
content = fp.read()
lst = literal_eval(content)
print(lst[-1])
# /home/Joe/1.txt
As said in the commentary, better use other structures to store your information, e.g. pickle, json, etc.
Please change t to 'rt' when reading from a file in python:
with open ('file.txt', 'rt') as fr:
fd = fr.readlines()
print (fd[-1])
Note: it is 'rt' instead of t.
Try to,
with open('file.txt') as fr:
fd = fr.readlines()[0].split(',')[-1].strip(']')
print(fd)
#'/home/Joe/1.txt'

Python can't load JSON created by json.dump

This seems to be a very straightforward problem where I am trying to read a JSON file and modify a few of the fields.
with open("example.json", "r+") as f:
data = json.load(f)
# perform modifications to data
f.truncate(0)
json.dump(data, f)
It worked the first time I manually created a JSON file and stored the correct JSON file, but by the second time I run the same script it gives me this error:
ValueError: No JSON object could be decoded
Why is that? It surprises me that the json module cannot parse the file created by the module itself.
Based on the code you provided, and what you are trying to do (return the file cursor back to the beginning of the file), you are not actually doing that with f.truncate. You are actually truncating your file. i.e. Clearing the file entirely.
Per the help on the truncate method:
truncate(...)
truncate([size]) -> None. Truncate the file to at most size bytes.
Size defaults to the current file position, as returned by tell().
What you are actually looking to do with returning the cursor back to the beginning of the file is using seek.
The help on seek:
seek(...)
seek(offset[, whence]) -> None. Move to new file position.
So, explicitly, to get back to the beginning of the file you want f.seek(0).
For the sake of providing an example of what is happening. Here is what happens with truncate:
File has stuff in it:
>>> with open('v.txt') as f:
... res = f.read()
...
>>> print(res)
1
2
3
4
Call truncate and see that file will now be empty:
>>> with open('v.txt', 'r+') as f:
... f.truncate(0)
...
0
>>> with open('v.txt', 'r') as f:
... res = f.read()
...
>>> print(res)
>>>
Using f.seek(0):
>>> with open('v.txt') as f:
... print(f.read())
... print(f.read())
... f.seek(0)
... print(f.read())
...
1
2
3
4
0
1
2
3
4
>>>
The long gap between the first output shows the cursor at the end of the file. Then we call the f.seek(0) (the 0 output is from the f.seek(0) call) and output our f.read().
You are missing one line, f.seek(0)
with open("example.json", "r+") as f:
data = json.load(f)
# perform modifications to data
f.seek(0);
f.truncate(0)
json.dump(data, f)

Python 3 Replace Lines

I have a little trouble with Python. Here is code:
f = open('/path/to/file', 'r')
filedata = f.read()
f.close()
postgres = filedata.replace('# DBENGINE=MYSQL', 'DBENGINE=PGSQL')
dbname = filedata.replace('# DBNAME=DB1', 'DBNAME=DB1')
dbrwuser = filedata.replace('# DBRWUSER="user1"', 'DBRWUSER="user1"')
f = open('/path/to/file', 'w')
f.write(postgres)
f.write(dbname)
f.write(dbrwuser)
f.close()
As you can see I'm trying to read a big file and when I try to replace it it just replaces "Postgres" and it does not make change "dbname, dbrwuser" etc. So I tried to figured it out but couldn't do it.
Any idea or sample?
Thanks.
You make three copies of the input instead of replacing it each time. Use the following:
filedata = filedata.replace('# DBENGINE=MYSQL', 'DBENGINE=PGSQL')
filedata = filedata.replace('# DBNAME=DB1', 'DBNAME=DB1')
filedata = filedata.replace('# DBRWUSER="user1"', 'DBRWUSER="user1"')
...
f.write(filedata)
You can also do it by take all replacement string into a dictonary
import re
repString = {'# DBENGINE=MYSQL': 'DBENGINE=PGSQL', '# DBNAME=DB1': 'DBNAME=DB1', '# DBRWUSER="user1"': 'DBRWUSER="user1"'}
repString = dict((re.escape(k), v) for k, v in repString.iteritems())
pattern = re.compile("|".join(repString.keys()))
filedata = pattern.sub(lambda m: repString[repString.escape(m.group(0))], filedata)
f = open('/path/to/file', 'w')
f.write(filedata)
f.close()
A few suggestions and clarifications:
f.read() reads the entire file. This is probably not a good idea for large files. Instead, use
with open(filename, "r") as f:
for line in f:
# do something with the line
Using with open() also eliminates the need for closing the file afterwards - it's done automatically.
string.replace() returns the entire string with the first argument replaced by the second. Since you make a new variable every time you use replace, the changes only apply to the individual variables. Changes made in postgres will not exist in dbname.
Instead, redefine the variable filedata for every replace to keep the changes and avoid needless copying:
filedata = filedata.replace('# DBENGINE=MYSQL', 'DBENGINE=PGSQL')
filedata = filedata.replace('# DBNAME=DB1', 'DBNAME=DB1')
filedata = filedata.replace('# DBRWUSER="user1"', 'DBRWUSER="user1"')
# at this point, filedata contains all three changes
When you open a file for writing using the w option, the file is overwritten. This means that the file will only contain the contents written by your last write, f.write(dbrwuser). Instead, make your changes and only write once or append to the file instead:
filedata = filedata.replace('# DBENGINE=MYSQL', 'DBENGINE=PGSQL')
...
...
with open('/path/to/file', 'w') as f:
f.write(filedata)

How to read one particular line from .txt file in python?

I know I can read the line by line with
dataFile = open('myfile.txt', 'r')
firstLine = dataFile.readline()
secondLine = dataFile.readline()
...
I also know how to read all the lines in one go
dataFile = open('myfile.txt', 'r')
allLines = dataFile.read()
But my question is how to read one particular line from .txt file?
I wish to read that line by its index.
e.g. I want the 4th line, I expect something like
dataFile = open('myfile.txt', 'r')
allLines = dataFile.readLineByIndex(3)
Skip 3 lines:
with open('myfile.txt', 'r') as dataFile:
for i in range(3):
next(dataFile)
the_4th_line = next(dataFile)
Or use linecache.getline:
the_4th_line = linecache.getline('myfile.txt', 4)
From another Ans
Use Python Standard Library's linecache module:
line = linecache.getline(thefilename, 33)
should do exactly what you want. You don't even need to open the file -- linecache does it all for you!
You can do exactly as you wanted with this:
DataFile = open('mytext.txt', 'r')
content = DataFile.readlines()
oneline = content[5]
DataFile.close()
you could take this down to three lines by removing oneline = content[5] and using content[5] without creating another variable (print(content[5]) for example) I did this just to make it clear that content[5] must be a used as a list to read the one line.

Categories

Resources