I'm creating software where I want to accept compressed files. Since files are read/written everywhere, I created a utility function for opening files, that handles opening/closing for me, for some compressed filetypes.
Example code:
def return_file_handle(input_file, open_mode="r"):
""" Handles compressed and uncompressed files. Accepts open modes r/w/w+ """
if input_file.endswith(".gz")
with gzip.open(input_file, open_mode) as gzipped_file_handle:
return gzipped_file_handle
The problem is, when using this code, the file handle seems to close when the function returns. I it possible to do what I want with with open
or do I need to handle closing myself?
Add this to the code above to get a minimal non-working example:
for line in return_file_handle(input_bed, "rb"):
print line
Create a gzipped textfile with:
echo "hei\nder!" | gzip - > test.gz
Error message:
Traceback (most recent call last):
File "check_bed_against_blacklist.py", line 26, in <module>
check_bed_against_blacklist("test.gz", "bla")
File "check_bed_against_blacklist.py", line 15, in check_bed_against_blacklist
for line in return_file_handle(input_bed, "r"):
ValueError: I/O operation on closed file.
Using a with open() statement will automatically close a file once the block has completed. Not only will using a context manager free you from having to remember to close files manually, but it will also make it much easier for others reading your code to see precisely how the program is using the file.
Opening Files in Python Python has a built-in open() function to open a file. This function returns a file object, also called a handle, as it is used to read or modify the file accordingly.
The normal return value from open is a non-negative integer file descriptor. In the case of an error, a value of -1 is returned instead. In addition to the usual file name errors (see File Name Errors), the following errno error conditions are defined for this function: EACCES.
Within the block of code opened by “with”, our file is open, and can be read from freely. However, once Python exits from the “with” block, the file is automatically closed.
Try it as a generator:
def return_file_handle(input_file, open_mode="r"):
"""
Handles compressed and uncompressed files. Accepts open modes r/w/w+
"""
# compressed
if input_file.endswith(".gz"):
with gzip.open(input_file, open_mode) as gzipped_file_handle:
yield gzipped_file_handle
else:
with open(input_file, open_mode) as normal_fh:
yield normal_fh
When you call it:
for line in return_file_handle("file.gz"):
print(line.read())
Or composing a generator using python's new yield from
syntax:
def each_line(fh):
for l in fh:
yield from l
And calling it:
for each in each_line(return_file_handle(fh)):
print(each)
with the file cleanly closing at the end of the for loop.
The best way I can think of is passing a function as parameter which accept opened fd:
def work(fd):
for line in fd:
print line
def work_with_file_handle(input_file, func, open_mode="r"):
if input_file.endswith(".gz")
with gzip.open(input_file, open_mode) as gzipped_file_handle:
func(gzipped_file_handle)
work_with_file_handle('xxx.gz', work)
Avoid with, if you want to return the file_handle. Because file_handle will be automatically closed when with block is finished executing.
Following code is what you should be using:
import gzip
def return_file_handle(input_file, open_mode="rb"):
if input_file.endswith(".gz"):
gzipped_file_handle = gzip.open(input_file, open_mode)
return gzipped_file_handle
for line in return_file_handle('file.txt.gz', "r"):
print line
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With