Reputation: 1495
I am trying to read the following file line by line and check if a value exists in the file. What I am trying currently is not working. What am I doing wrong?
If the value exists I do nothing. If it does not then I write it to the file.
file.txt:
123
345
234
556
654
654
Code:
file = open("file.txt", "a+")
lines = file.readlines()
value = '345'
if value in lines:
print('val ready exists in file')
else:
# write to file
file.write(value)
Upvotes: 10
Views: 6872
Reputation: 46
When you are opening file in "a+
" mode the file cursor from where the readlines()
method will start reading will be at the end so readlines
would read nothing. You need to do f.seek(0)
in order to move the cursor to the beginning.
file = open("file.txt", "a+")
file.seek(0)
lines = [line.strip() for line in file.readlines()]
print(lines)
value = '345'
if value in lines:
print('val ready exists in file')
else:
print("else")
# write to file
file.write(value)
file.close()
Upvotes: 2
Reputation: 1734
I would consider several changes.
1: Use with
to automatically close the file.
2: Use strip()
to remove leading or trailing stuff, like \n
3: Use a break
for the loop.
4: Add \n
in the write
part.
value = "345"
with open("file.txt", "a+") as file:
file.seek(0)
for line in file.readlines():
if line.strip("\n") == value:
print('val ready exists in file')
break
else:
# write to file
file.write(f"\n{value}")
Upvotes: 6
Reputation: 26315
Since you want to open the file for reading and writing, I suggest using the r+
mode from open()
. This will open the file at the beginning of the file, since we want to first read all lines. Using a+
will open the file for reading and writing at the end of the file, which will cause lines
to give you an empty list from readlines()
.
You also need to strip newlines from lines
before checking if the value exists. This is because 345
is not equal to 345/n
. We can use a list comprehension to strip the newlines from lines
using str.rstrip()
, which strips whitespace from the right. Additionally, If you have to do repetitive lookups for multiple values, it might be worth converting lines
to a set
for constant time lookups, instead of doing a linear search with a list.
Its also worth using With Statement Context Managers when reading files, since the closing of the file is handled for you.
value = '345'
with open("file.txt", mode="r+") as file:
lines = [line.rstrip() for line in file.readlines()]
if value in lines:
print('value ready exists in file')
else:
file.write(f"{value}\n")
The other choice is to use f.seek(0)
with a+
to set the position at the beginning of the file, as shown in @Cihan Ceyhan's answer. However I think this overcomplicates things, and its just easier to use the r+
mode.
Upvotes: 3
Reputation: 135
The readlines() method returns a list containing \n with each element so when the condition is checked it is not compared with value with \n so the statement is always false so i have a code that solve your problem.
f_name = "file.txt"
text = "102"
def check_in_file(file_name, value):
with open(file_name, 'r') as read_obj:
for line in read_obj:
if value in line:
return True
return False
if check_in_file(f_name, text):
print('Yes, string found in file')
else:
print('String not found in file')
file = open(f_name, 'a')
file.write("\n"+text)
file.close()
Upvotes: 1
Reputation: 2307
There are two problems here:
.readlines()
returns lines with \n
not trimmed, so your check will not work properly.a+
mode opens a file with position set to the end of the file. So your readlines()
currently returns an empty list!Here is a direct fixed version of your code, also adding context manager to auto-close the file
value = '345'
with open("file.txt", "a+") as file:
file.seek(0) # set position to start of file
lines = file.read().splitlines() # now we won't have those newlines
if value in lines:
print('val ready exists in file')
else:
# write to file
file.write(value + "\n") # in append mode writes will always go to the end, so no need to seek() here
However, I agree with @RoadRunner that better is to just use r+
mode; then you don't need the seek(0)
. But the cleanest is just to split out your read and write phases completely, so you don't run into file position problems.
Upvotes: 12
Reputation: 2940
when working with io the recomended approach is to use the context manager
. Context managers
allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with
statement. if you have a large file better not to use file.readlines()
or the read()
method. The readlines()
method returns a list
containing each line in the file as a list item. better to iterate on the file stream line by line (generator). always use try except with io operations! :
values=['123','233'...]
try:
with open("file.txt", "r+") as fp:
for line in fp:
for val in values:
if val not in line.strip():
fp.write(val)
else:
print('val ready exists in file')
except (OSError,...): #catch what ever you think this code above can raise, and re raise in except block if you want.
#do exception handling
Upvotes: 3
Reputation: 65
This should work :)
filename = 'file.txt'
value = '345'
with open(filename) as f:
if value in f.read(): # read if value is in file
print('Value is in the file')
This will check if the value is in the file and if it's not there. It will add value to the file.
filename = 'file_1.txt'
value = '999'
with open(filename, 'r+') as f:
if value in f.read():
print(f"Value {value} is in the file")
else:
print("The value not in the file.\nTherefore, saving the value in the file.")
f.write(f"{value}\n")
Upvotes: 2
Reputation: 122
Your python script works for me properly. I guess the last line in the else statement should be file.write(value)
instead of file.write(val)
.
Upvotes: 1