【问题标题】:with open inside try - except block, too many files open?在尝试中打开 - 除了块,打开的文件太多?
【发布时间】:2013-02-05 20:02:18
【问题描述】:

很简单,我在特定位置的所有子文件夹中循环,并从三个不同的文件中收集一些数字。

def GrepData():
import glob as glob
import os as os

os.chdir('RUNS')
RUNSDir = os.getcwd()
Directories = glob.glob('*.*')
ObjVal = []
ParVal = []
AADVal = []

for dir in Directories:
    os.chdir(dir)
    (X,Y) = dir.split(sep='+')
    AADPath = glob.glob('Aad.out')
    ObjPath = glob.glob('fobj.out')
    ParPath = glob.glob('Par.out')

    try:
        with open(os.path.join(os.getcwd(),ObjPath[0])) as ObjFile:
            for line in ObjFile:
                ObjVal.append(list([X,Y,line.split()[0]]))
        ObjFile.close()
    except(IndexError):
        ObjFile.close()

    try:
        with open(os.path.join(os.getcwd(),ParPath[0])) as ParFile:
            for line in ParFile:
                ParVal.append(list([X,Y,line.split()[0]]))
        ParFile.close()
    except(IndexError):
        ParFile.close()
    try:
        with open(os.path.join(os.getcwd(),AADPath[0])) as AADFile:
            for line in AADFile:
                AADVal.append(list([X,Y,line.split()[0]]))
        AADFile.close()
    except(IndexError):
        AADFile.close()
    os.chdir(RUNSDir)

每个文件打开命令都放在 try - except 块中,因为在少数情况下打开的文件将为空,因此附加 line.split() 将导致索引错误,因为列表为空.

但是,当运行此脚本时,我收到以下错误:“OSError: [Errno 24] Too Many open files”

我的印象是“with open...”语句的想法是它负责在使用后关闭文件?显然,这并没有发生。

所以我要的是两件事:

  1. 回答:“我对 with open 的理解正确吗?”
  2. 如何纠正导致此问题的任何错误?

(是的,我知道代码并不完全优雅。整个尝试 - 除了应该是一个可重复使用的对象 - 但我会在找出这个错误后修复它)

【问题讨论】:

  • 很好奇,既然您知道with 语句会关闭文件,为什么您在每种情况下都在之后自己显式关闭它?
  • 这也是我的想法。建议:删除close 调用并再次尝试运行代码。如果它继续显示相同的错误,我怀疑它应该,然后相应地更新您问题中的代码(即删除close()s)。否则,请编辑您的问题,说删除 close 调用可以解决问题,也许有人能够解释原因。
  • 好吧 - 因为我收到了太多文件打开错误,显然不是。所以我补充说(曾经是通过),希望错误是由于导致文件保持打开状态的异常。
  • 这里不是open 之一,它不会关闭文件,因为它们都在with 语句中。我不明白这怎么可能......你能试着把它减少到我们也可以运行的东西吗?例如“用这三个文件创建 1000 个目录,然后像这样运行脚本”这样的指令。

标签: python file exception with-statement


【解决方案1】:

尝试将您的try-except 移动到with 中,如下所示:

with open(os.path.join(os.getcwd(),ObjPath[0])) as ObjFile:
    for line in ObjFile:
        try:
            ObjVal.append(list([X,Y,line.split()[0]]))
        except(IndexError): 
           pass

注意:无需手动关闭文件,这是with 的用途。此外,如果您使用相同的名称,则无需在导入中使用 as os

【讨论】:

    【解决方案2】:

    “打开的文件太多”与编写语义不正确的 python 代码无关,您正确使用了with。关键是错误中显示“OSError”的部分,它指的是底层操作系统。

    当你调用 open() 时,python 解释器会执行一个系统调用。系统调用的详细信息会因您使用的操作系统而有所不同,但在 linux 上,此调用是 open(2)。操作系统内核将处理系统调用。当文件打开时,它在系统文件表中有一个条目并占用操作系统资源 - 这实际上意味着它在打开时“占用空间”。因此,操作系统对可以在任何时候打开的文件数量有限制。

    您的问题是,当您调用 open() 时,您调用 close() 的速度不够快。如果您的目录结构要求您一次打开数千个可能接近此上限的文件,则可以暂时更改它(至少在 linux 上,我对其他操作系统不太熟悉,所以我不想去关于如何跨平台执行此操作的太多细节)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      • 2016-10-14
      • 1970-01-01
      相关资源
      最近更新 更多