с открытым внутри попробуйте - кроме блока, слишком много файлов открыто?

Проще говоря, я просматриваю все подпапки в определенном месте и собираю несколько чисел из трех разных файлов.

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, так как в некоторых случаях открываемый файл будет пустым, и, таким образом, добавление строки.split() приведет к ошибке индекса, поскольку список пуст.

Однако при запуске этого скрипта я получаю следующую ошибку: «OSError: [Errno 24] Too Many open files»

У меня сложилось впечатление, что идея оператора «с открытым ...» заключалась в том, что он позаботился о закрытии файла после использования? Ясно, что этого не происходит.

Итак, я прошу о двух вещах:

  1. Ответ на вопрос: "Правильно ли я понимаю слово open?"
  2. Как я могу исправить любую ошибку, вызывающую эту проблему?

(И да, я знаю, что код не совсем элегантный. Вся попытка, за исключением того, что это должен быть один объект, который повторно используется, но я исправлю это после выяснения этой ошибки)


person Daniel    schedule 20.02.2013    source источник
comment
Любопытно, поскольку вы знаете, что оператор with закрывает файл, почему вы в каждом случае явно закрываете его самостоятельно после этого?   -  person Daniel Roseman    schedule 20.02.2013
comment
Это была и моя мысль. Предложение: удалите вызовы close и попробуйте снова запустить код. Если он продолжает показывать ту же ошибку, как я подозреваю, то обновите код в своем вопросе соответствующим образом (т.е. удалите close()s). В противном случае отредактируйте свой вопрос, сказав, что удаление вызовов close устраняет проблему, и, возможно, кто-то сможет объяснить, почему.   -  person David Z    schedule 20.02.2013
comment
Ну, так как я получил слишком много ошибок открытия файлов, очевидно, что это не так. Поэтому я добавил это (раньше это было pass) в надежде, что ошибка возникла из-за исключения, в результате которого файл остался открытым.   -  person Daniel    schedule 20.02.2013
comment
Это не один из open здесь, который оставляет файлы незакрытыми, так как все они находятся в операторах with. Я не понимаю, как это возможно... Можете ли вы попытаться уменьшить его до чего-то, что мы тоже можем запустить? Например, с такими инструкциями, как создать 1000 каталогов с этими тремя файлами и запустить скрипт таким образом.   -  person Armin Rigo    schedule 20.02.2013


Ответы (2)


Попробуйте переместить 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 в вашем импорте, если вы используете то же имя.

person mbatchkarov    schedule 20.02.2013

«Слишком много открытых файлов» не имеет ничего общего с написанием семантически неправильного кода Python, и вы правильно используете with. Ключ — это часть вашей ошибки с надписью «OSError», которая относится к базовой операционной системе.

Когда вы вызываете open(), интерпретатор Python выполняет системный вызов. Детали системного вызова немного различаются в зависимости от используемой ОС, но в Linux этот вызов открыт(2). Ядро операционной системы будет обрабатывать системный вызов. Пока файл открыт, он имеет запись в таблице системных файлов и занимает ресурсы ОС — это фактически означает, что он «занимает место», пока он открыт. Таким образом, ОС имеет ограничение на количество файлов, которые можно открыть одновременно.

Ваша проблема в том, что пока вы вызываете open(), вы недостаточно быстро вызываете close(). В случае, если ваша структура каталогов требует, чтобы вы одновременно открывали много тысяч файлов, которые могут приблизиться к этому ограничению, его можно временно изменить (по крайней мере, в Linux, я менее знаком с другими ОС, поэтому я не хочу идти слишком много подробностей о том, как это сделать на разных платформах).

person aestrivex    schedule 20.02.2013