Python — рекурсивный сбор информации о файле приводит к ошибке памяти

#python #recursion

#python #рекурсия

Вопрос:

Я пишу скрипт для рекурсии по всем каталогам и подкаталогам начальной папки, но я сталкиваюсь с ошибками памяти (ошибка есть MemoryError ). Я предполагаю, что, возможно, мой data_dicts список становится слишком большим, но я не уверен. Любые советы будут оценены.

 import os

# example data dictionary
data_dict = {
    'filename': 'data.csv',
    'folder':   'R:/',
    'size':     300000
}

def get_file_sizes_folder(data_dicts, starting_folder):
# Given a list of file information dictionaries and a folder, iterate over the files
# in the folder to get their information and append it to the list. 
# Also recurse through subdirectories
    for entry in os.scandir(starting_folder):
        if not entry.name.startswith('.'):
            if entry.is_file():
                size = entry.stat().st_size
                filename = entry.name
                folder = os.path.dirname(entry.path)
                temp_dict = {'filename': filename, 'size': size, 'folder': folder}
                data_dicts.append(temp_dict.copy())
            else:
                print(entry.path)
                data_dicts.extend(get_file_sizes_folder(data_dicts, entry.path))

    return data_dicts

d = get_file_sizes_folder([], 'R:/')    
  

Комментарии:

1. почему вы не используете os.walk ?

Ответ №1:

Вы не должны указывать data_dicts в качестве аргумента свою функцию get_file_sizes_folder() . Это приведет к появлению множества дубликатов ваших записей со скоростью, которая, вероятно, почти факториальная. Неудивительно, что на вашем компьютере очень быстро заканчивается память!

Вместо этого используйте только starting_folder в качестве аргумента и просто создайте новый список data_dicts в первой строке вашей функции, например:

 def get_file_sizes_folder(starting_folder):
# Given a list of file information dictionaries and a folder, iterate over the files
# in the folder to get their information and append it to the list. 
# Also recurse through subdirectories
    data_dicts = []
    for entry in os.scandir(starting_folder):
        if not entry.name.startswith('.'):
            if entry.is_file():
                size = entry.stat().st_size
                filename = entry.name
                folder = os.path.dirname(entry.path)
                temp_dict = {'filename': filename, 'size': size, 'folder': folder}
                data_dicts.append(temp_dict)
            else:
                print(entry.path)
                data_dicts.extend(get_file_sizes_folder(entry.path))

    return data_dicts
  

Ответ №2:

Вы вообще не должны выполнять рекурсию. Использование os.walk

Пример:

 def get_file_sizes_folder(starting_folder):
    data_dicts = list()
    for root, _, files in os.walk(starting_folder):
        data_dicts.extend({
            'filename': f, 
            'size': os.path.getsize(os.path.join(root, f)),
            'folder': root,
        } for f in files)

    return data_dicts

d = get_file_sizes_folder('R:/')
  

Комментарии:

1. Спасибо. Однако у меня есть несколько вопросов. Вы указываете _ в качестве параметра, но я не вижу, чтобы вы его использовали. Кроме того, я заметил, что вы используете какое-то понимание списка, но у вас нет заключающих скобок, например: [{} for f in files] . Не могли бы вы, пожалуйста, объяснить это?

2. Это _ потому, что мне не нужен folders параметр команды. Принято использовать подчеркивание для нежелательных / неиспользуемых параметров. Понимание списка — это не понимание списка, это выражение генератора. Я рекомендую вам протестировать его и убедиться, что поведение является ожидаемым.