Update Txt file in python - python

I have a text file with names and results. If the name already exists, only the result should be updated. I tried with this code and many others, but without success.
The content of the text file looks like this:
Ann, 200
Buddy, 10
Mark, 180
Luis, 100
PS: I started 2 weeks ago, so don't judge my bad code.
from os import rename
def updatescore(username, score):
file = open("mynewscores.txt", "r")
new_file = open("mynewscores2.txt", "w")
for line in file:
if username in line:
splitted = line.split(",")
splitted[1] = score
joined = "".join(splitted)
new_file.write(joined)
new_file.write(line)
file.close()
new_file.close()
maks = updatescore("Buddy", "200")
print(maks)

I would suggest reading the csv in as a dictionary and just update the one value.
import csv
d = {}
with open('test.txt', newline='') as f:
reader = csv.reader(f)
for row in reader:
key,value = row
d[key] = value
d['Buddy'] = 200
with open('test2.txt','w', newline='') as f:
writer = csv.writer(f)
for key, value in d.items():
writer.writerow([key,value])

So what needed to be different mostly is that when in your for loop you said to put line in the new text file, but it's never said to Not do that when wanting to replace a score, all that was needed was an else statement below the if statement:
from os import rename
def updatescore(username, score):
file = open("mynewscores.txt", "r")
new_file = open("mynewscores2.txt", "w")
for line in file:
if username in line:
splitted = line.split(",")
splitted[1] = score
print (splitted)
joined = ", ".join(splitted)
print(joined)
new_file.write(joined+'\n')
else:
new_file.write(line)
file.close()
new_file.close()
maks = updatescore("Buddy", "200")
print(maks)

You can try this, add the username if it doesn't exist, else update it.
def updatescore(username, score):
with open("mynewscores.txt", "r+") as file:
line = file.readline()
while line:
if username in line:
file.seek(file.tell() - len(line))
file.write(f"{username}, {score}")
return
line = file.readline()
file.write(f"\n{username}, {score}")
maks = updatescore("Buddy", "300")
maks = updatescore("Mario", "50")

You have new_file.write(joined) inside the if block, which is good, but you also have new_file.write(line) outside the if block.
Outside the if block, it's putting both the original and fixed lines into the file, and since you're using write() instead of writelines() both versions get put on the same line: there's no \n newline character.
You also want to add the comma: joined = ','.join(splitted) since you took the commas out when you used line.split(',')
I got the result you seem to be expecting when I put in both these fixes.
Next time you should include what you are expecting for output and what you're giving as input. It might be helpful if you also include what Error or result you actually got.
Welcome to Python BTW

Removed issues from your code:
def updatescore(username, score):
file = open("mynewscores.txt", "r")
new_file = open("mynewscores2.txt", "w")
for line in file.readlines():
splitted = line.split(",")
if username == splitted[0].strip():
splitted[1] = str(score)
joined = ",".join(splitted)
new_file.write(joined)
else:
new_file.write(line)
file.close()
new_file.close()

I believe this is the simplest/most straightforward way of doing things.
Code:
import csv
def update_score(name: str, score: int) -> None:
with open('../resources/name_data.csv', newline='') as file_obj:
reader = csv.reader(file_obj)
data_dict = dict(curr_row for curr_row in reader)
data_dict[name] = score
with open('../out/name_data_out.csv', 'w', newline='') as file_obj:
writer = csv.writer(file_obj)
writer.writerows(data_dict.items())
update_score('Buddy', 200)
Input file:
Ann,200
Buddy,10
Mark,180
Luis,100
Output file:
Ann,200
Buddy,200
Mark,180
Luis,100

Related

How to replace a line with another line?

I am trying to make a contact book application with command-line arguments. This is the code written so far to update the new contact details of a particular contact. args.name has the name of the contact. And args.number has the new number which needs to be updated.
How can I update the entire line? When I run this, it replaces the entire file, contacts.txt, with an empty string. This functionality will also help in the delete function.
thefile = open("contacts.txt","w+")
lines = thefile.readlines()
for line in lines:
if name in line:
line.replace(line,"Name: "+ args.name + " Number: "+args.number+ "\n")
You could firstly read the data from the file, create an empty string, append each line to the newly created string conditionally, and write(replace) the newly obtained string onto the existing file.
f1 = open('contacts.txt','r')
data = f1.readlines()
f1.close()
new_data = ""
for line in data:
if name in line:
update = line.replace(line,"Name: "+ args.name + " Number: "+args.number+ "\n")
new_data += update
else:
new_data += line
f2 = open('contacts.txt','w')
f2.write(new_data)
f2.close()
When you open a file with "w+" python erase the file !
First you whoud write two function: One that writes data and the other read data
def reader():
f = open("MYFILE.txt", "r")
lines = f.readlines()
f.close()
return lines
def writer(data):
f = open("MYFILE.txt", "w")
for i in data:
f.write(i)
f.close()
Then you can actualise lines how you want:
lines = reader()
for i in range(len(lines)):
if lines[i] == "Something\n":
lines[i] = "New_Value\n"
writer(lines)

How to extract one column to another file from a 300GB file

Problem was the huge data number, and I have to do it with my personal laptop with 12GB RAM. I tried a loop with 1M. lines every round, and used csv.writer. But csv.writer wrote like 1M. lines every two hours. So, any other ways worth to try?
lines = 10000000
for i in range(0, 330):
list_str = []
with open(file, 'r') as f:
line_flag = 0
for _ in range(i*lines):
next(f)
for line in f:
line_flag = line_flag + 1
data = json.loads(line)['name']
if data != former_str:
list_str.append(data)
former_str = data
if line_flag == lines:
break
with open(self.path + 'data_range\\names.csv', 'a', newline='') as writeFile:
writer = csv.writer(writeFile, delimiter='\n')
writer.writerow(list_str)
writeFile.close()
another version
def read_large_file(f):
block_size = 200000000
block = []
for line in f:
block.append(line[:-1])
if len(block) == block_size:
yield block
block = []
if block:
yield block
def split_files():
with open(write_file, 'r') as f:
i = 0
for block in read_large_file(f):
print(i)
file_name = write_name + str(i) + '.csv'
with open(file_name, 'w', newline='') as f_:
writer = csv.writer(f_, delimiter='\n')
writer.writerow(block)
i += 1
This was after it read a block and writing ... I wonder how come the rate of data trasmission was keeping about 0.
It should be as simple as this:
import json
import csv
with open(read_file, 'rt') as r, open(write_file, 'wt', newline='') as w:
writer = csv.writer(w)
for line in r:
writer.writerow([json.loads(line)['name']])
I tried the loop inside the file, but I always get me a Error, I guessed we cannot write the data into another file while opening the file?
You totally can write data in one file while reading another. I can't tell you more about your error until you post what it said, though.
There was a bit in your code about former_str which is not covered under "extract one column", so I did not write anything about it.
Would something like this work?
Essentially using a generator to avoid reading the entire file in memory, and writing the data one line at a time.
import jsonlines # pip install jsonlines
from typing import Generator
def gen_lines(file_path: str, col_name: str) -> Generator[str]:
with jsonline.open(file_path) as f:
for obj in f:
yield obj[col_name]
# Here you can also change to writing a jsonline again
with open(output_file, "w") as out:
for item in gen_lines(your_file_path, col_name_to_extract):
out.write(f"{item}\n")

Python : Why do new lines keep appearing after every value amend?

I'm new to python and I'm trying various small things to see how they work:
items = dict()
with open(path) as f:
content = f.readlines()
for line in content:
splitStuff = line.split('!')
if splitStuff[0] in item:
items[splitStuff[0]] += ',' + Results[1]
else:
items[splitStuff[0]] = Results[1]
f.close()
with open(path2, 'a') as f:
for key, value in items.items():
f.write(key + '!' + value)
f.close()
It opens a file with this content:
3!Angel
3!Devil
4!Nasko
4!Pesho
4!Gosho
5!Kalin
6!Gancho
6!Boncho
6!Toncho
6!Moncho
And ends up writing a file with this content:
3!Angel
,Devil
4!Nasko
,Pesho
,Gosho
5!Kalin
6!Gancho
,Boncho
,Toncho
,Moncho
The part I don't understand is where are those new lines appearing from every time I edit a value?
EDIT: This is the desired output.
3!Angel,Devil
4!Nasko,Pesho,Gosho
5!Kalin
6!Gancho,Boncho,Toncho,Moncho
EDIT2: Never mind figured it out. Its because there are new lines in the original file and apparently reading file line by line catches them as well in python, unlike c# where they are ignored.
Lines you read with readlines() have a trailing newline.
for line in content:
line = line.rstrip()
splitStuff = line.split('!')
... etc ...
A solution could look like this:
path = "file1"
path2 = "file2"
items = dict()
with open(path) as f:
content = f.readlines()
for line in content:
splitStuff = line.split('!')
if splitStuff[0] in items:
items[splitStuff[0]] += ',' + splitStuff[1][:-1]
else:
items[splitStuff[0]] = splitStuff[1][:-1]
f.close()
with open(path2, 'a') as f:
for key, value in items.items():
f.write(key + '!' + value)
f.write("\n")
f.close()
You just had to remove the newline from each line of the file by adding [:-1].

How do I remove lines from a file and move them to another file?

Ok so the file contains:
apple,bot,cheese,-999
tea,fire,water,1
water,mountain,care,-999
So I want to check if the lines in file 1 have a -999 at the end and if they do, remove that line, and transfer the one that does not into a new file. So far my function has:
def clean(filename,cleanfile,value,position):
filename.readline()
for line in filename:
if line[position] != value:
cleanfile.write(line)
Value is -999 and position is 3. I opened my files in my main and passed them to the function, the problem is that the new file is empty.
You can use the csv module to figure out the details of splitting and joining the comma-separated values.
import csv
def clean(filename,cleanfile,value,position):
with open(filename) as reader_fp, open(cleanfile, 'w') as writer_fp:
reader = csv.reader(reader_fp)
writer = csv.writer(writer_fp)
for row in reader:
if row[position] != value:
writer.writerow(row)
try this:
def clean(filename,cleanfile,value,position):
for lines in filename.readlines():
line = lines.strip().split(",")
if line[position] != value:
cleanfile.write(",".join(line) + "\n")
clean(open("readFrom.txt", "r"), open("writeTo.txt", "w"), "-999", 3)
if you know that the value is always at the end of each line, you can try :
def clean (file1, file2, value):
for line in file1 :
if line.strip().split(",")[-1] != value :
file2.write(line)
file1.close()
file2.close()
clean(open("readFrom.txt", "r"), open("writeTo.txt", "w"), "-999")

Changing a file line - Python

I've a file entitled 'users.txt' with the following structure; username:info_about_the_user.
Something like this:
users.txt:
mark:stuffabouthim anthony:stuffabouthim peter:stuffabouthim peterpeter:stuffabouthim peterpeterpeter:stuffabouthim peterpeterpeterpeter:stuffabouthim
The following part of the script needs to change a line (change info about an user) but I'm having problems when the string is duplicated (peter - peterpeter) and I dont know how to fix it.
def test():
fn = 'users.txt'
f = open(fn)
output = []
changeuser = 'peterpeter'
userinfo = 'HeIsTall'
for line in f:
if not changeuser+":" in line:
output.append(line)
f.close()
f = open(fn, 'w')
f.writelines(output)
f.close()
f = open("users.txt", "a")
f.write(changeuser + ":" + userinfo+"\n")
f = open("users.txt", "a")
test()
This is the input I have:
Input: users.txt:
mark:stuffabouthim anthony:stuffabouthim peter:stuffabouthim peterpeter:HesAwesome peterpeterpeter:stuffabouthim peterpeterpeterpeter:stuffabouthim
I want to change info about peterpeter and have the following output:
Output I want to have: users.txt:
mark:stuffabouthim anthony:stuff about him peter:stuffabouthim peterpeter:HeIsTall peterpeterpeter:stuffabouthim peterpeterpeterpeter:stuffabouthim
But this is the input I'm having. All the lines behind peterpeter are getting deleted among other things.
mark:stuffabouthim
anthony:stuffabouthim
peter:stuffabouthim
peterpeter:HeIsTall
Can anyone give me a help with the code below to have the desired output? Thanks.
You can have it the easy way with the fileinput module:
import fileinput
def test():
fn = 'users.txt'
changeuser = 'peterpeter'
newinfo = 'HeIsTall'
for line in fileinput.input(fn, inplace=1):
user, oldinfo = line.split(':')
print '%s:%s' % (user, newinfo if user == changeuser else oldinfo.replace('\n', ''))
if __name__ == "__main__":
test()
try this:
def test():
fn = 'users.txt.txt'
f = open(fn)
output = []
changeuser = 'peterpeter'
userinfo = 'HeIsTall'
for line in f:
if line.strip().split(':')[0]!=changeuser:
output.append(line)
else:
output.append(changeuser + ":" + userinfo+"\n")
f.close()
f = open(fn, 'w')
f.writelines(output)
f.close()
test()
output:
mark:stuffabouthim
anthony:stuffabouthim
peter:stuffabouthim
peterpeter:HeIsTall
peterpeterpeter:stuffabouthim
peterpeterpeterpeter:stuffabouthim
You got a logical error in the if-clause, which DELETES all peters*, the only peter remaining is the one you append to the file.
for line in f:
if not changeuser+":" in line: #THAT MEANS ALL PETERS ARE IGNORED!
output.append(line)
It's generaly easier to understand positive clauses then a negation:
for line in f:
if changeuser+":" in line:
output.append('%s:%s\n' %(changeuser,userinfo))
else:
output.append(line)
Good code is easy to read. Try to code like you would try to write a report! That leads automatically to spliting your code into smaller pieces like functions. e.g.:
lines = read_all_lines_from_file(filename)
change_user_info(lines, user, userinfo)
save_lines_to_file(lines, filename)
Your code gets split into smaller pieces and if an error occurs you can pin it down to a few lines of code instead of having to work over several pages. ;-)

Categories