Python 3: Open file in read mode without raising an exception? [duplicate] - python

This question already has answers here:
How do I check whether a file exists without exceptions?
(40 answers)
Closed 1 year ago.
I am trying to write a block of code which opens a new file every time a Python3 script is run.
I am constructing the filename using an incrementing number.
For example, the following are some examples of valid filenames which should be produced:
output_0.csv
output_1.csv
output_2.csv
output_3.csv
On the next run of the script, the next filename to be used should be output_4.csv.
In C/C++ I would do this in the following way:
Enter an infinite loop
Try to open the first filename, in "read" mode
If the file is open, increment the filename number and repeat
If the file is not open, break out of the loop and re-open the file in "write" mode
This doesn't seem to work in Python 3, as opening a non-existing file in read mode causes an exception to be raised.
One possible solution might be to move the open file code block inside a try-catch block. But this doesn't seem like a particularly elegant solution.
Here is what I tried so far in code
# open a file to store output data
filename_base = "output"
filename_ext = "csv"
filename_number = 0
while True:
filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
with open(filename_full, "r") as f:
if f.closed:
print(f"Writing data to {filename_full}")
break
else:
print(f"File {filename_full} exists")
filename_number += 1
with open(filename_full, "w") as f:
pass
As explained above this code crashes when trying to open a file which does not exist in "read" mode.

Using pathlib you can check with Path.is_file() which returns True when it encounters a file or a symbolic link to a file.
from pathlib import Path
filename_base = "output"
filename_ext = "csv"
filename_number = 0
filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
p = Path(filename_full)
while p.is_file() or p.is_dir():
filename_number += 1
p = Path(f"{filename_base}_{filename_number}.{filename_ext}")
This loop should exit when the file isn’t there so you can open it for writing.

you can check if a file exists prior using
os.path.exists(filename)

You could use the OS module to check if the file path is a file, and then open it:
import os
file_path = './file.csv'
if(os.path.isfile(file_path)):
with open(file_path, "r") as f:

This should work:
filename_base = "output"
filename_ext = "csv"
filename_number = 0
while True:
filename_full = f"{filename_base}_{filename_number}.{filename_ext}"
try:
with open(filename_full, "r") as f:
print(f"File {filename_full} exists")
filename_number += 1
except FileNotFoundError:
print("Creating new file")
open(filename_full, 'w');
break;

You might os.path.exists to check if file already exists for example
import os
print(os.path.exists("output_0.csv"))
or harness fact that your names
output_0.csv
output_1.csv
output_2.csv
output_3.csv
are so regular, exploit glob.glob like so
import glob
existing = glob.glob("output_*.csv")
print(existing) # list of existing files

Related

Why does this Python script to replace text in files break the last file? [duplicate]

This question already has answers here:
Is close() necessary when using iterator on a Python file object [duplicate]
(8 answers)
Closed 1 year ago.
Source
import os, re
directory = os.listdir('C:/foofolder8')
os.chdir('C:/foofolder8')
for file in directory:
open_file = open(file,'r')
read_file = open_file.read()
regex = re.compile('jersey')
read_file = regex.sub('york', read_file)
write_file = open(file, 'w')
write_file.write(read_file)
The script replaces "jersey" in all the files in C:/foofolder8 with "york". I tried it with three files in the folder and it works. The source notes though that "you may find an error in the last file", which I'm indeed encountering - all text in the last file is simply deleted.
Why does the script break for the last file? The fact that only the last file breaks makes it seem like there's something wrong with the for loop, but I don't see what could be wrong. Calling directory shows there are three files in the directory as well, which is correct.
Try:
import os, re
directory = os.listdir('C:/foofolder8')
os.chdir('C:/foofolder8')
for file in directory:
with open(file,'r') as open_file:
read_file = open_file.read()
regex = re.compile('jersey')
read_file = regex.sub('york', read_file)
with open (file, 'w') as write_file:
write_file.write(read_file)

How to check if a file's window is closed/open Python?

How can I check when a file window is closed? I tried this:
import time
import os
path = input()
os.startfile(request)
try:
file_path = open(path, 'rb')
except Exception:
done = True
while done:
if file_path.closed:
done = False
time.sleep(SLEEP_TIME)
So the file starts before I start checking if the file is closed. Then, I open the file again, and because its open already, an exception should pop up, where I'm looping until the file is closed. I don't know whether the indication I made is right or not.
Please help!!! I'm desperate!!!
You can't use file_path in the except: block, because the variable isn't assigned if open() raises an exception.
You should put the loop around the try/except, not inside the except.
while True:
try:
file_path = open(path, 'rb')
break
except:
time.sleep(SLEEP_TIME)
It will open the file only once, and if the file is already open it will use the already opened fie
import time
import os
path = 'bescom-17-apr.pdf'
try:
with open(path, "r") as file:
print("opened file")
except IOError:
print("file not found")

Delete a file after reading

In my code, user uploads file which is saved on server and read using the server path. I'm trying to delete the file from that path after I'm done reading it. But it gives me following error instead:
An error occurred while reading file. [WinError 32] The process cannot access the file because it is being used by another process
I'm reading file using with, and I've tried f.close() and also f.closed but its the same error every time.
This is my code:
f = open(filePath)
with f:
line = f.readline().strip()
tempLst = line.split(fileSeparator)
if(len(lstHeader) != len(tempLst)):
headerErrorMsg = "invalid headers"
hjsonObj["Line No."] = 1
hjsonObj["Error Detail"] = headerErrorMsg
data['lstErrorData'].append(hjsonObj)
data["status"] = True
f.closed
return data
f.closed
after this code I call the remove function:
os.remove(filePath)
Edit: using with open(filePath) as f: and then trying to remove the file gives the same error.
Instead of:
f.closed
You need to say:
f.close()
closed is just a boolean property on the file object to indicate if the file is actually closed.
close() is method on the file object that actually closes the file.
Side note: attempting a file delete after closing a file handle is not 100% reliable. The file might still be getting scanned by the virus scanner or indexer. Or some other system hook is holding on to the file reference, etc... If the delete fails, wait a second and try again.
Use below code:
import os
os.startfile('your_file.py')
To delete after completion:
os.remove('your_file.py')
This
import os
path = 'path/to/file'
with open(path) as f:
for l in f:
print l,
os.remove(path)
should work, with statement will automatically close the file after the nested block of code
if it fails, File could be in use by some external factor. you can use Redo pattern.
while True:
try:
os.remove(path)
break
except:
time.sleep(1)
There is probably an application that is opening the file; check and close the application before executing your code:
os.remove(file_path)
Delete files that are not used by another application.

Error when trying to read and write multiple files

I modified the code based on the comments from experts in this thread. Now the script reads and writes all the individual files. The script reiterates, highlight and write the output. The current issue is, after highlighting the last instance of the search item, the script removes all the remaining contents after the last search instance in the output of each file.
Here is the modified code:
import os
import sys
import re
source = raw_input("Enter the source files path:")
listfiles = os.listdir(source)
for f in listfiles:
filepath = source+'\\'+f
infile = open(filepath, 'r+')
source_content = infile.read()
color = ('red')
regex = re.compile(r"(\b be \b)|(\b by \b)|(\b user \b)|(\bmay\b)|(\bmight\b)|(\bwill\b)|(\b's\b)|(\bdon't\b)|(\bdoesn't\b)|(\bwon't\b)|(\bsupport\b)|(\bcan't\b)|(\bkill\b)|(\betc\b)|(\b NA \b)|(\bfollow\b)|(\bhang\b)|(\bbelow\b)", re.I)
i = 0; output = ""
for m in regex.finditer(source_content):
output += "".join([source_content[i:m.start()],
"<strong><span style='color:%s'>" % color[0:],
source_content[m.start():m.end()],
"</span></strong>"])
i = m.end()
outfile = open(filepath, 'w+')
outfile.seek(0)
outfile.write(output)
print "\nProcess Completed!\n"
infile.close()
outfile.close()
raw_input()
The error message tells you what the error is:
No such file or directory: 'sample1.html'
Make sure the file exists. Or do a try statement to give it a default behavior.
The reason why you get that error is because the python script doesn't have any knowledge about where the files are located that you want to open.
You have to provide the file path to open it as I have done below. I have simply concatenated the source file path+'\\'+filename and saved the result in a variable named as filepath. Now simply use this variable to open a file in open().
import os
import sys
source = raw_input("Enter the source files path:")
listfiles = os.listdir(source)
for f in listfiles:
filepath = source+'\\'+f # This is the file path
infile = open(filepath, 'r')
Also there are couple of other problems with your code, if you want to open the file for both reading and writing then you have to use r+ mode. More over in case of Windows if you open a file using r+ mode then you may have to use file.seek() before file.write() to avoid an other issue. You can read the reason for using the file.seek() here.

Writing to a new file if it doesn't exist, and appending to a file if it does

I have a program which writes a user's highscore to a text file. The file is named by the user when they choose a playername.
If the file with that specific username already exists, then the program should append to the file (so that you can see more than one highscore). And if a file with that username doesn't exist (for example, if the user is new), it should create a new file and write to it.
Here's the relevant, so far not working, code:
try:
with open(player): #player is the varible storing the username input
with open(player, 'a') as highscore:
highscore.write("Username:", player)
except IOError:
with open(player + ".txt", 'w') as highscore:
highscore.write("Username:", player)
The above code creates a new file if it doesn't exist, and writes to it. If it exists, nothing has been appended when I check the file, and I get no errors.
Have you tried mode 'a+'?
with open(filename, 'a+') as f:
f.write(...)
Note however that f.tell() will return 0 in Python 2.x. See https://bugs.python.org/issue22651 for details.
It's not clear to me exactly where the high-score that you're interested in is stored, but the code below should be what you need to check if the file exists and append to it if desired. I prefer this method to the "try/except".
import os
player = 'bob'
filename = player+'.txt'
if os.path.exists(filename):
append_write = 'a' # append if already exists
else:
append_write = 'w' # make a new file if not
highscore = open(filename,append_write)
highscore.write("Username: " + player + '\n')
highscore.close()
Just open it in 'a' mode:
a Open for writing. The file is created if it does not exist. The stream is positioned at the end of the file.
with open(filename, 'a') as f:
f.write(...)
To see whether you're writing to a new file, check the stream position. If it's zero, either the file was empty or it is a new file.
with open('somefile.txt', 'a') as f:
if f.tell() == 0:
print('a new file or the file was empty')
f.write('The header\n')
else:
print('file existed, appending')
f.write('Some data\n')
If you're still using Python 2, to work around the bug, either add f.seek(0, os.SEEK_END) right after open or use io.open instead.
Notice that if the file's parent folder doesn't exist you'll get the same error:
IOError: [Errno 2] No such file or directory:
Below is another solution which handles this case:
(*) I used sys.stdout and print instead of f.write just to show another use case
# Make sure the file's folder exist - Create folder if doesn't exist
folder_path = 'path/to/'+folder_name+'/'
if not os.path.exists(folder_path):
os.makedirs(folder_path)
print_to_log_file(folder_path, "Some File" ,"Some Content")
Where the internal print_to_log_file just take care of the file level:
# If you're not familiar with sys.stdout - just ignore it below (just a use case example)
def print_to_log_file(folder_path ,file_name ,content_to_write):
#1) Save a reference to the original standard output
original_stdout = sys.stdout
#2) Choose the mode
write_append_mode = 'a' #Append mode
file_path = folder_path + file_name
if (if not os.path.exists(file_path) ):
write_append_mode = 'w' # Write mode
#3) Perform action on file
with open(file_path, write_append_mode) as f:
sys.stdout = f # Change the standard output to the file we created.
print(file_path, content_to_write)
sys.stdout = original_stdout # Reset the standard output to its original value
Consider the following states:
'w' --> Write to existing file
'w+' --> Write to file, Create it if doesn't exist
'a' --> Append to file
'a+' --> Append to file, Create it if doesn't exist
In your case I would use a different approach and just use 'a' and 'a+'.
Using the pathlib module (python's object-oriented filesystem paths)
Just for kicks, this is perhaps the latest pythonic version of the solution.
from pathlib import Path
path = Path(f'{player}.txt')
path.touch() # default exists_ok=True
with path.open('a') as highscore:
highscore.write(f'Username:{player}')

Categories

Resources