Prevent blank line at the end of a text file [duplicate] - python

This question already has answers here:
Why should text files end with a newline?
(19 answers)
Closed 11 months ago.
I have created a program in python that uses a .txt file as a database, so I save the user data there.
The data is stored in the file as follows:
Each line in the file represents a user
Users are stored as: User_ID,First Name,Last Name,Phone Number,Country
The problem arises when I try to delete a user that is in the last position of the file, because it leaves a blank line that breaks the function of listing the users in the program.
Example:
Suppose I have two users in the text file: image1
And now I delete the last user (00002): image2
So, there is a blank line, and when I add a new user, it looks like this: image3
Here is the code I use to delete users:
def delete_user(file, user_id):
with open(file, 'r+') as f:
users = f.readlines()
f.seek(0)
for user in users:
if user.split(',')[0] != user_id:
f.write(user)
f.truncate()
Code I use to add users:
def add_user(file, first_name, last_name, phone_number, country):
filesize = os.path.getsize(file)
with open(file, 'r+') as f:
if filesize == 0:
f.write(f'{"1".zfill(5)},{first_name},{last_name},{phone_number},'
f'{country}')
else:
last_line = f.readlines()[-1]
user_id = int(last_line.split(',')[0])
f.write(f'\n{str(user_id+1).zfill(5)},{first_name},{last_name},'
f'{phone_number},{country}')
Upon investigation, I realized that the problem occurs because there is a newline character (\n) left at the end of the last line, which should not be there.
So, how could I solve this problem?

A trailing newline shouldn't break your program. You seem to be using a newline as a line separator, but on Unix-like OSs, a newline is actually considered a line terminator, meaning there should be one at the end of every line.
However, you'll have a much easier time by using a standard data format. What you're using resembles CSV, so I recommend csv.DictReader and csv.DictWriter, which would also involve putting a column header in the file to label the fields. You might also consider using Pandas (e.g. pandas.read_csv() and df.to_csv()).

Related

How to remove a line and replace with another line? [duplicate]

This question already has answers here:
Is it possible to modify lines in a file in-place?
(5 answers)
Closed 1 year ago.
I am creating an application with Pyqt5 (QT). The application do the Password Manager tasks.
I have a text file that names and passwords stored in it (encrypted).
One section of app has a tool that user can change the password from entering the name. (If you don't understand look at the picture.)
My text file is like this :
newname1|password1
newname2|password2
...
As you noticed, after "|" is the password. How can I find newname2 and just replace the password section from new password field, or remove the line and replace with a new one (for example: newname2|newpassword)?
Also I have to say that I know how to fetch data from inputs, I just want to know how to do it in python code.
Something like this should work:
out = open('file.txt', 'r').readlines()
name, newPass = 'newname2', 'NewPassword2'
for idx,line in enumerate(out):
if line.startswith(name+'|'):
out[idx] = f'{name}|{newPass}'
fBuffer = open('file.txt', 'w')
fBuffer.writelines(out)
break
else:
print('User Name not found')
You can take the name, and newPass from PyQt UI's lineEdit, read the file which has the name and the passwords stored, then iterate through these lines and check if newname2| is there in the file, if so, update the list. Then write back to the file, and exit the loop immediately.
string = '''
a|b
c|d
'''
username = 'a'
new_password = '123'
import re
new_string = re.sub(f'(?<=^{username}\|).*', new_password , string, flags=re.M)
print(new_string) # This string can be written back to the file.
Note: Not efficient but works.

How can I delete and rewrite a line without unknown characters?

I have a database.txt file the first column is for usernames the second passwords and the rest 5 recovery question and answers alternating. I want to allow the user to be able to change the password of their details, without affecting another users username as they may be the same. I have found a way to delete the previous one and append the new line of modified details to the file. However, the is always a string or unknown characters at the start of the appended line. AND other characters are being changed not the second value in the list. Please help me find a way to avoid this.
https://repl.it/repls/NecessaryBoldButtonsYou can find the code here changing it will affect everyone, so please copy it elsewhere.
https://onlinegdb.com/BJbsn9-cL
I just need the password to be changed on a user input not other strings, the reason for all this code is that when changing a person's password another username could be changed.This is the original file
This is what happens afterwards, the second string in the list of the line which where data[0] = "bye" should only be changed to newpass, not all of the others
'''
import linecache
f = open("database.txt" , "r+")
for loop in range(3):
line = f.readline()
data = line.split(",")
if data[1] == "bye":
print(data[1]) #These are to help me understand what is happening
print(data[0])
b = data[0]
newpass = "Hi"
a = data[1]
fn = 'database.txt'
e = open(fn)
output = []
str="happy"
for line in e:
if not line.startswith(str):
output.append(line)
e.close()
print(output)
e = open(fn, 'w')
e.writelines(output)
e.close()
line1 = linecache.getline("database.txt" ,loop+1)
print(line)
password = True
print("Password Valid\n")
write = (line1.replace(a, newpass))
write = f.write(line1.replace(a, newpass))
f.close()
'''
This is the file in text:
username,password,Recovery1,Answer1,Recovery2,Answer2,Recovery3,Answer3,Recovery4,Answer4,
Recovery5,Answer5,o,o,o,o,o,o,o,o,o,o,
happy,bye,o,o,o,o,o,o,o,o,o,o,
bye,happy,o,o,o,o,o,o,o,o,o,o,
Support is very much appreciated
Feel free to change the code as much as you need to, as it is already a mess
Thanks in Advance
This should be pretty easy. The basic idea is:
open input file for reading
open output file for writing
for each line in input file
if password = "happy"
change user name in line
write line to output file
It should be pretty easy to convert that to python.
From comments, and by examining your code, I get the feeling that you're trying to update a line in-place. That is, it looks like your expectation is that given the file "database.txt" that contains this:
username,password,Recovery1,Answer1,Recovery2,Answer2,Recovery3,Answer3, Recovery4,Answer4,Recovery5,Answer5,
o,o,o,o,o,o,o,o,o,o,
happy,bye,o,o,o,o,o,o,o,o,o,o,
bye,happy,o,o,o,o,o,o,o,o,o,o,
When you make the change, your new "database.txt" will contain this:
username,password,Recovery1,Answer1,Recovery2,Answer2,Recovery3,Answer3, Recovery4,Answer4,Recovery5,Answer5,
o,o,o,o,o,o,o,o,o,o,
happy,Hi,o,o,o,o,o,o,o,o,o,o,
bye,happy,o,o,o,o,o,o,o,o,o,o,
You can do that, but you can't do it in-place. You have to write all the lines of the file, including the changed line, to a new temporary file. Then you can delete the old "database.txt" and rename the temporary file.
You can't update a line in a text file, because if you change the length of the line then you'll either end up with extra space at the end of the line you changed (because the new line has fewer characters than the old line), or you'll overwrite the beginning of the next line (the new line is longer than the old line).
The only other option is to load all of the lines into memory and close the file. Then change the line or lines you want to change, in memory. Finally, open the "database.txt" file for writing and output all of the lines from memory to the file.

Writing to a file also appending

i've run into a problem where: My code creates a file with headers, writes data to it. And then when i run it for a second time it overwrites the data, which it should but start a new line. Also, what does delimiter mean?
#Intro
import csv
headers=["Name","Age","Year Group"]
with open("Details.csv","a" and "w") as i:
w=csv.writer(i,delimiter=",")
w.writerow(headers)
print("Welcome User, to my Topics Quiz!\n------------------------------
---------\nYou can choose from 3 different topics:\n • History\n • Music\n •
Computer Science\n---------------------------------------")
#Storing: User's name, age and year group
print("Before we start, we need to register an account.")
User=input("Enter your name:\n")
Age=input("Enter your age:\n")
Year=input("Enter your year group:\n")
details=[User,Age,Year]
w.writerow(details)
with open("UserPass.csv","a" and "w") as Userpass:
w=csv.writer(Userpass,delimiter=",")
headers=["Username","Password"]
w.writerow(headers)
NewUser=(User[:3]+Age)
print("Great! Your username is set to: {}".format(NewUser))
Pass=input("Enter a password for your account:\n")
userpass=[NewUser,Pass]
w.writerow(userpass)
So the code will write out the data when i want it to add.
Thanks in advance.
You're mode is only "w":
>>> "a" and "w" == "w"
True
Instead use only "a".
a is enough for the open mode.
Append: "a" has Write: "w" in its definition. When you say you want to append it means you want to write at the end... So don't use them together.
delimiter means separator which most of the times refers to some characters like comma, space, dot, etc.
If you wish to append to an existing .csv file you need to either:
skip writing the header if the file already exists, (check with os.path.exists() before opening it) or
open the file in read mode & read the file into memory first, (as a list of lists), close it then add the new row to the data and then overwrite the whole thing, including headers, over the original, (this does let you do things like sorting the rows).
As others have said your file open mode should be one of:
"r" = Read Text
"rb" = Read Binary
"w" = *Over***W**rite Text
"wb" = *Over***Write **Binary
"a" = Append Text
"ab" = Append Binary
The delimiter specifies what separates the fields in the .csv file.
As an aside you should never store passwords - instead you should store a hash of the password and when the user next enters a password calculate the same hash and compare it with the stored hash. Something like:
import hashlib
import getpass
pswd = getpass.getpass()
userpass = hashlib.sha256(pswd.encode('ascii')).hexdigest()
As for the term delimiter, remember that CSV stands for Comma Seperated Values. Delimiter means seperator; CSV uses a comma (",") as its seperator or delimiter, but the python module csv gives you the option to specify a different delimiter, such as a tab character ("\t"), etc.
As for the file operations, you could check if the file is blank. If it is, write the headers. Then (always) append the data. Something like this:
# open the file for appending (the "a"). Create it if it doesn't exist (the "+")
with open(filename, "a+") as f:
w = csv.writer(f, delimiter=",")
# only write the headers if the file is blank (i.e. the first time the program runs)
if f.read() == "":
w.writerows[headers]
# get `details` from the user.
# ...
# the data always gets appended
w.writerows(details)
Hope this helps!

How do I delete multiple lines in a text file with python?

I am practicing my python skills by writing a Phone book program. I am able to search and add entries but I am having a lot of trouble deleting entries.
I am trying to find a line that matches my search and delete it as well as the next 4 lines. I have a function to delete here:
def delete():
del_name = raw_input("What is the first name of the person you would like to delete? ")
with open("phonebook.txt", "r+") as f:
deletelines = f.readlines()
for i, line in enumerate(deletelines):
if del_name in line:
for l in deletelines[i+1:i+4]:
f.write(l)
This does not work.
How would I delete multiple entries from a text file like this?
Answering your direct question: you can use fileinput to easily alter a text file in-place:
import fileinput
file = fileinput.input('phonebook.txt', inplace=True)
for line in file:
if word_to_find in line:
for _ in range(4): # skip this line and next 4 lines
next(file, None)
else:
print line,
In order to avoid reading the entire file into memory, this handles some things in the background for you - it moves your original file to a tempfile, writes the new file, and then deletes the tempfile.
Probably better answer: it looks like you have rolled a homemade serialization solution. Consider using a built-in library like csv, json, shelve, or even sqlite3 to persist your data in an easier-to-work-with format.

adding a line to a txt file

I am trying to add a line to the end of a txt file. I have been reading some posts here and trying differents options, but, for some reason, the new line is neved added after the last one, it is just appended next to the last one.
So I was wondering what I am doing wrong....here I am showing my tests:
TEST 1:
#newProt is a new data entered by the user in this case 12345
exists = False
f = open('protocols.txt', 'a+')
for line in f:
if newProt == line:
exists = True
if not exists:
f.write(newProt)
f.close()
txt file after this code:
2sde45
21145
we34z12345
TEST 2:
exists = False
with open('protocols.txt', 'r+') as f:
for line in f:
if newProt == line:
exists = True
if not exists:
f.write(newProt)
txt file after this code: exactly the same as above...
And, like this, I have tested some combinations of letters to open the file, rb+, w, etc but for some reason I never get the desired output txt file:
2sde45
21145
we34z
12345
So I do not know what I am doing wrong, I am following some examples I gor from some other posts here.
Try this:
exists = False
f = open('protocols.txt', 'a+')
for line in f:
if newProt == line:
exists = True
if not exists:
f.write('\n' + newProt)
f.close()
This adds the new line character to the end of the file then adds 'newProt'.
EDIT:
The reason why your code did not produce the desired result is because you were simply writing a string to the file. New lines in text are not really 'in' the text file. The text file is literally a series of bytes known as chars. The reason why various applications such as text editors show you new lines is because it interprets certain characters as formatting elements rather than letters or numbers.
'\n' is one such formatting character (in the ASCII standard), and it tells your favorite text editor to start a new line. There are others such as '\t' which makes a tab.
Have a look at the wiki article on Newline character for more info
You can use f.seek(-x,x), reach the last line and then f.write().
Otherwise my understanding is if you open a file in "a" (append) mode, it'll anyways be written in the end
Refer to this link: Appending line to a existing file having extra new line in Python

Categories