Return 文件句柄是用什么打开的?

Return file handles opened with with open?

我正在创建我想要接受压缩文件的软件。由于文件无处不在 read/written,我创建了一个用于打开文件的实用函数,它为我处理 opening/closing 一些压缩文件类型。

示例代码:

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

问题是,当使用这段代码时,文件句柄似乎在函数 returns 时关闭。我可以用 with open 做我想做的事,还是我需要自己处理关闭?

将此添加到上面的代码中以获得最小的非工作示例:

for line in return_file_handle(input_bed, "rb"):
    print line

创建一个 gzip 文本文件:

echo "hei\nder!" | gzip - > test.gz

错误信息:

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.

尝试将其作为生成器:

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

当你调用它时:

for line in return_file_handle("file.gz"):
    print(line.read())

或者使用 python's new yield from syntax:

组成一个生成器
def each_line(fh):
    for l in fh:
        yield from l

并调用它:

for each in each_line(return_file_handle(fh)):
    print(each)

文件在 for 循环结束时完全关闭。

您用于打开文件的样式会在块末尾自动将其关闭。这就是 with 打开文件的块样式的全部意义。

您想做的是:

gzipped_file_handle = gzip.open(input_file, open_mode)
return gzipped_file_handle

注意:您只需要注意在调用此函数后关闭文件即可。

我能想到的最好的方法是传递一个函数作为接受打开的 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)

避免使用,如果你想 return file_handle。因为file_handle会在with块执行完后自动关闭

您应该使用以下代码:

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

我会使用另一个上下文管理器

from contextlib import contextmanager

@contextmanager
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:
            yield gzipped_file_handle
    else:
        with open(input_file, open_mode) as normal_file:
            yield normal_file
    # Your file will be closed after this


with return_file_handle(file_name, mode) as f:
     pass