Don't save empty file - python

I create a new text file with f = open('file.txt', 'w'). Then, as I go about to get stuff to write on it, there is a problem and I need to exit without actually writing anything.
However, the file is still created, but empty. Is there a way to keep the file from being saved in case nothing is going to be written on it, or do I have to explicitly delete it in case something goes wrong?

You can use atexit to simulate this behavior, but there's probably a Better Way out there somewhere.
import atexit
def safety_trigger():
try:
os.remove(FILENAME)
except FileNotFoundError:
pass
atexit.register(safety_trigger)
with open(FILENAME,'w') as f:
# do your
# file operations
atexit.unregister(safety_trigger)
This way when your script starts, you set it to automatically delete FILENAME when it ends. Once you're done writing to the file, you tell your script NOT to automatically delete FILENAME when it ends.

You could simply prepare the information for writing first and only perform the saving and such if it makes it through preparation without a hitch.
info_to_write = ""
try:
info_to_write += "something!"
# etc...
if something_went_wrong:
raise Exception
with open("file.txt","w") as f:
f.write(info_to_write)
catch:
print "Nothing written, no file created"

Related

Refresh variable when reading from a txt file

I have a file in my python folder called data.txt and i have another file read.py trying to read text from data.txt but when i change something in data.txt my read doesn't show anything new i put
Something else i tried wasn't working and i found something that read, but when i changed it to something that was actually meaningful it didn't print the new text.
Can someone explain why it doesn't refresh, or what i need to do to fix it?
with open("data.txt") as f:
file_content = f.read().rstrip("\n")
print(file_content)
First and foremost, strings are immutable in Python - once you use file.read(), that returned object cannot change.
That being said, you must re-read the file at any given point the file contents may change.
For example
read.py
def get_contents(filepath):
with open(filepath) as f:
return f.read().rstrip("\n")
main.py
from read import get_contents
import time
print(get_contents("data.txt"))
time.sleep(30)
# .. change file somehow
print(get_contents("data.txt"))
Now, you could setup an infinite loop that watches the file's last modification timestamp from the OS, then always have the latest changes, but that seems like a waste of resources unless you have a specific need for that (e.g. tailing a log file), however there are arguably better tools for that
It was unclear from your question if you do the read once or multiple times. So here are steps to do:
Make sure you call the read function repeatedly with a certain interval
Check if you actually save file after modification
Make sure there are no file usage conflicts
So here is a description of each step:
When you read a file the way you shared it gets closed, meaning it is read only once, you need to read it multiple times if you want to see changes, so make it with some kind of interval in another thread or async or whatever suits your application best.
This step is obvious, remember to hit ctrl+c
It may happen that a single file is being accessed by multiple processes, for example your editor and the script, now to prevent errors try the following code:
def read_file(file_name: str):
while True:
try:
with open(file_name) as f:
return f.read().rstrip("\n")
except IOError:
pass

Printing results from my code to .txt doesn´t work anymore

I am trying to print some of the results of my algorithm (score) to a .txt file to have that data for further analysis. Here, the algorithm shall create the file and then open it to write the number down. Then I thought about closing it again.
My problem here is, that I don´t even find the file. If I create one by my own, and only try to write the number, that doesn´t work as well.
This is for the analysis of Reinforcement Learning for a robot. The scores are symbolizing Q-values and are important for further analysis. Score is here a random number.
if __name__ == '__main__':
open('try.txt', 'w+').close()
for e in range(agent.load_episode + 1, EPISODES):
...
for t in range(agent.episode_step):
...
if done:
...
saveFile = open('try.txt','w')
saveFile.write(str(score))
saveFile.close()
From the first part I try to create a new file called try.txt (I only create the file once). Them after, I open the file, write something and close it again. When the next Q-value is calculated, the file is opened again.
Should the file contain only the last calculated value, all the values (possibly each in new line) from single run, or even values through separate runs? Nevertheless, this, a bit modified, snipped might be what you are looking for:
if __name__ == '__main__':
with open('try.txt', 'w') as saveFile: # change to 'a' if you want the results to be stored between runs
for e in range(agent.load_episode + 1, EPISODES):
...
for t in range(agent.episode_step):
...
if done:
...
# saveFile.truncate() uncommenting this means that the file only stores the latest value
saveFile.write(str(score) + '\n') # write each result to new line
saveFile.flush() # this line makes the results accessible from file as soon as they are calculated
In python with is the preferred method of opening files, as it takes care of closing it at the right moment. When opening file in 'w' mode the caret inside the file is placed at the beginning of file and if a file had any data in it, it gets erased.
The 'a' mode appends to file. You may want to take a look at this.
Now I believe that you wanted to open and close the file on and on, as to have the data accessible as soon as the iteration is finished. That is what saveFile.flush() is for. Please let me know if this helps you!
To better control where the file gets created take use of os module:
import os
directory = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(directory, 'try.txt')
# print(file_path)
with open(file_path, 'w') as saveFile:
Try changing saveFile = open('try.txt', 'w') to with open('try.txt', 'a+') as saveFile:

os.remove() in windows gives "[Error 32] being used by another process"

I know this question has been asked before quiet a lot on SO and elsewhere too. I still couldn't get it done. And im sorry if my English is bad
Removing file in linux was much more simpler. Just os.remove(my_file) did the job, But in windows it gives
os.remove(my_file)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process: (file-name)
my code :
line_count = open(my_file, mode='r') #
t_lines = len(line_count.readlines()) # For total no of lines
outfile = open(dec_file, mode='w')
with open(my_file, mode='r') as contents:
p_line = 1
line_infile = contents.readline()[4:]
while line_infile:
dec_of_line = baseconvert(line_infile.rstrip(),base16,base10)
if p_line == t_lines:
dec_of_line += str(len(line_infile)).zfill(2)
outfile.write(dec_of_line + "\r\n")
else:
outfile.write(dec_of_line + "\r\n")
p_line += 1
line_infile = contents.readline()[4:]
outfile.close()
os.remove(my_file)
Here my_file is a variable that contains complete path structure of a file. Like wise dec_file also contains path, but to a new file. And the file im trying to remove is the file that's being used under read mode. Need some help please.
my try's :
Tried closing the file my_file.close(). The corresponding error i got was AttributeError: 'str' object has no attribute 'close'. I knew, when a file is in
read mode it automatically closes when it comes to the end of the
file. But still i gave it a try
Also tried by os.close(my_file) as per https://stackoverflow.com/a/1470388/3869739. i got error as TypeError: an integer is required
Or, am i getting this error just because i have opened the file
twice (for counting the line and to read the file content),..?
Pythonic way of reading from or writing to a file is by using a with context.
To read a file:
with open("/path/to/file") as f:
contents = f.read()
#Inside the block, the file is still open
# Outside `with` here, f.close() is automatically called.
To write:
with open("/path/to/file", "w") as f:
print>>f, "Goodbye world"
# Outside `with` here, f.close() is automatically called.
Now, if there's no other process reading or writing to the file, and assuming you have all the permission you should be able to close the file. There is a very good chance that there's a resource leak (file handle not being closed), because of which Windows will not allow you to delete a file. Solution is to use with.
Further, to clarify on few other points:
Its the garbage collector that causes the closure of the stream when the object is destroyed. The file is not auto-closed upon complete reading. That wouldn't make sense if the programmer wanted to rewind, would it?
os.close(..) internally calls the C-API close(..) that takes an integer file descriptor. Not string as you passed.

Try opening a file as an archive, otherwise read as a regular file

I am trying to process a list of files, where each may be a regular text file OR a bz2 archive.
How can I use try-except blocks most efficiently to attempt to open each file in the appropriate format? I would rather not check the file's extension, as this cannot always be relied upon (and is not very EAFP).
Currently I am doing:
def data_generator(*corpora):
def parse_lines(fobj):
for line in fobj:
# Do lots of processing.
# ...
# Many lines here omitted.
yield ('lots', 'of', 'data')
for corpus in corpora:
try:
with bz2.BZ2File(corpus, mode='r') as f:
for data in parse_lines(f):
yield data
except IOError:
with codecs.open(corpus, encoding='utf-8') as f:
for data in parse_lines(f):
yield data
I think the repeated for data in parse_lines(f): ... code looks superfluous, but I can't think of a way to get rid of it. Is there any way to reduce the previous, or is there another way to try to "smart open" a file?
Edit: Optional followup
What would be an appropriate way to scale up the number of formats checked? As an example, the program 7zip allows you to right-click on any file and attempt to open it as an archive (any that 7zip supports). With the current try-except block strategy, it seems like you would start getting nested in blocks pretty quickly even after just a few formats, like:
try:
f = ...
except IOError:
try:
f = ...
except IOError:
try:
...
If it's really just the duplicate loops that have got you concerned, you could move f out of the scope of the try-catch block, then put a single copy of the loop after everything's said and done:
try:
f = bz2.BZ2File(corpus, mode='r')
except IOError:
f = codecs.open(corpus, encoding='utf-8')
for data in parse_lines(f):
yield data
f.close()
Although I'd look into only opening the file once, checking for the BZ2 header (the characters BZ as the first two bytes), and using that to decide whether to continue reading it as plaintext, or pass the data into a bz2.BZ2Decompressor instance.

Check to see if file exists is failing

Here is my code:
# header.py
def add_header(filename):
header = '"""\nName of Project"""'
try:
f = open(filename, 'w')
except IOError:
print "Sorry could not open file, please check path"
else:
with f:
f.seek(0,0)
f.write(header)
print "Header added to", filename
if __name__ == "__main__":
filename = raw_input("Please provide path to file: ")
add_header(filename)
When I run this script (by doing python header.py), even when I provide a filename which does not exist it does not return the messages in the function. It returns nothing even when I replace the print statements with return statements. How would I show the messages in the function?
I believe you are always creating the file. Therefore, you won't see a file not there exception. It does not hurt to put a write or file open write under try except, because you might not have privileges to create the file.
I have found with statements like try except and else to test those at the Python command line, which is a very excellent place to work out cockpit error, and I'm very experienced at generating a lot of cockpit error while proving out a concept.
The fact you're using try except is very good. I just have to go review what happens when a logic flow goes through one of them. The command line is a good place to do that.
The correct course of action here is to try and read the file, if it works, read the data, then write to the file with the new data.
Writing to a file will create the file if it doesn't exist, and overwrite existing contents.
I'd also note you are using the with statement in an odd manner, consider:
try:
with open(filename, 'w') as f:
f.seek(0,0)
f.write(header)
print("Header added to", filename)
except IOError:
print("Sorry could not open file, please check path")
This way is more readable.
To see how to do this the best way possible, see user1313312's answer. My method works but isn't the best way, I'll leave it up for my explanation.
Old answer:
Now, to solve your problem, you really want to do something like this:
def add_header(filename):
header = '"""\nName of Project"""'
try:
with open(filename, 'r') as f:
data = f.read()
with open(filename, 'w') as f:
f.write(header+"\n"+data)
print("Header added to"+filename)
except IOError:
print("Sorry could not open file, please check path")
if __name__ == "__main__":
filename = raw_input("Please provide path to file: ")
add_header(filename)
As we only have the choices of writing to a file (overwriting the existing contents) and appending (at the end) we need to construct a way to prepend data. We can do this by reading the contents (which handily checks the file exists at the same time) and then writing the header followed by the contents (here I added a newline for readability).
This is a slightly modified version of Lattywares solution. Since it is not possible to append data to the beginning of a file, the whole content is read and the file is written anew including your header. By opening the file in read/write mode we can do both operations with the same file handler without releasing it. This should provide some protection against race conditions.
try:
with open(filename, 'r+') as f:
data = f.read()
f.seek(0,0)
f.write(header)
f.write(data)
#f.truncate() is not needed here as the file will always grow
print("Header added to", filename)
except IOError:
print("Sorry, could not open file for reading/writing")
this script opens a file in "w" mode (write mode),which means once the file dose not exist,it will be created. So No IOError.

Categories

Resources