Как получить прогресс os.walk в Python?

У меня есть часть кода, который я использую для поиска исполняемых файлов игровых файлов и возвращаю каталоги. Я действительно хотел бы получить своего рода индикатор хода выполнения относительно как далеко вперед os.walk . Как я выполнил бы такую вещь?

Я пытался делать startpt = root.count(os.sep) и измеряя прочь этого, но это просто дает как глубоко os.walk находится в дереве каталогов.

def locate(filelist, root=os.curdir): #Find a list of files, return directories.
    for path, dirs, files in os.walk(os.path.abspath(root)):
        for filename in returnMatches(filelist, [k.lower() for k in files]):
            yield path + "\\"
12
задан SilentGhost 29 January 2010 в 19:00
поделиться

10 ответов

Я понял это.

Я использовал os.listdir для получения списка каталогов верхнего уровня, а затем использовал функцию .split на пути, который os.walk возвращал, возвращая каталог первого уровня, в котором он находится в данный момент.

Это оставило мне список каталогов верхнего уровня, в котором я мог найти индекс текущей директории os.walk, и сравнить возвращенный индекс с длиной списка, дав мне % полной;)

Это не дает мне гладкого прогресса, потому что уровень работы в каждой директории может варьироваться, но сглаживание индикатора прогресса меня не беспокоит. Но это можно легко сделать, расширив проверку пути глубже в структуру каталога.

Вот последний код из получения моего прогресса:

def locateGameDirs(filelist, root=os.curdir): #Find a list of files, return directories.
    toplevel = [folder for folder in os.listdir(root) if os.path.isdir(os.path.join(root, folder))] #List of top-level directories
    fileset = set(filelist)

    for path, dirs, files in os.walk(os.path.abspath(root)):

        curdir = path.split('\\')[1] #The directory os.walk is currently in.

        try: #Thrown here because there's a nonexistant(?) first entry.
            youarehere = toplevel.index(curdir)
            progress = int(((youarehere)/len(toplevel))*100)
        except:
            pass

        for filename in returnMatches(filelist, [k.lower() for k in files]):
            yield filename, path + "\\", progress

И прямо сейчас для отладки я делаю это дальше в коде:

    for wow in locateGameDirs(["wow.exe", "firefox.exe", "vlc.exe"], "C:\\"):
    print wow

Есть ли хороший маленький способ избавиться от этой попытки/исключения?; кажется, первая итерация пути ничего мне не дает...

4
ответ дан 2 December 2019 в 20:40
поделиться

Сделайте это в двух пропусках: сначала подсчитать, сколько общих файлов / папок на дереве, а затем во время второго прохода делают фактическую обработку.

2
ответ дан 2 December 2019 в 20:40
поделиться

Вам нужно знать общее количество файлов, чтобы сделать значимый индикатор прогресса.
Вы можете получить количество файлов, как это

len(list(os.walk(os.path.abspath(root))))

, но это займет некоторое время, и вам, вероятно, понадобится индикатор прогресса для этого ...

, чтобы найти количество файлов, которые действительно быстро вам нужна файловая система, которая Отслеживает количество файлов для вас.

Возможно, вы можете сохранить общую сумму от предыдущего запуска и использовать это как оценка

0
ответ дан 2 December 2019 в 20:40
поделиться

Как я уже сказал в комментарии, Шея бутылочки производительности, скорее всего, лежит за пределами функции функции . Ваш Returnmatches - довольно дорогостоящая функция. Я думаю, что вам будет лучше заменять его со следующим кодом:

def locate(filelist, root=os.curdir)
    fileset = set(filelist)            # if possible, pass the set instead of the list as a first argument
    for path, dirs, files in os.walk(os.path.abspath(root)):
            if any(file.lower() in fileset for file in files):
                yield path + '\\'

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

0
ответ дан 2 December 2019 в 20:40
поделиться

Просто показать непреодолимый бар прогресса (то есть те, которые показывают BLOB, подпрыгивая назад и вперед или эффект парикмахера). Таким образом, пользователи знают, что программа делает что-то полезное, но не вводить их в заблуждение, что и для завершения и такого.

4
ответ дан 2 December 2019 в 20:40
поделиться

Можно заменить keyExp на StringBuilder. перераспределение последовательности в цикле, подобном этому, будет продолжать выделять больше памяти, поскольку последовательности являются неизменяемыми.

StringBuilder keyExp = new StringBuilder();
...
    keyExp.Append("|" + readerCSVExp[i - 1]) ;
... 

являются ли многие последовательности одинаковыми? вы можете попробовать интернировать их , тогда любые идентичные последовательности будут совместно использовать одну и ту же память, а не быть копиями...

rowExp[fieldCount] = String.Intern(rowNumExp.ToString()); 

// Dedup Expected               
string internedKey = (String.Intern(keyExp.ToString()));        
if (!(dictExp.ContainsKey(internedKey)))
{
   dictExp.Add(internedKey, rowExp);                        
}
else
{
   listDupExp.Add(rowExp);
}  

Я не уверен, как именно работает код, но... кроме того, я бы сказал, что вам не нужно держать rowExp в словаре, держать что-то еще, как число и записать rowExp обратно на диск в другом файле. Это, вероятно, сохранит вам больше памяти, так как это, кажется, массив последовательностей из файла, так что, вероятно, большой. Если вы записываете его в файл и сохраняете номер в файле его в, то вы можете вернуться к нему снова в будущем, если вам затем потребуется обработать. Если вы сохранили смещение в файле как значение в словаре, вы сможете быстро найти его снова. Может быть:).

-121--3348379-
  1. Исходные файлы могут быть в любой кодировке
  2. Необходимо сообщить компилятору кодировку исходных файлов (например, javac -encoding... ); иначе кодирование платформы принято
  3. В наборах из двух предметов файла класса, опечатки последовательности сохранены, как (изменено) UTF-8, но если вы не работаете с bytecode, это не имеет значения (см. спекуляция JVM )
  4. Последовательности на Яве - UTF-16, всегда (см. Явская языковая спекуляция )
  5. System.out PrintStream преобразует ваши последовательности от UTF-16 до байтов в системном кодировании до написания их к Примечания stdout

:

-121--251939-

Советую избегать обхода каталога. Вместо этого используйте индексированное приложение для быстрого поиска файлов. Интерфейс командной строки приложения можно использовать в подпроцессе и найти файлы практически мгновенно.

В Windows см. Все . В UNIX проверьте местоположение. Не уверен насчет Мака, но я уверен, что там тоже есть вариант.

0
ответ дан 2 December 2019 в 20:40
поделиться

Сводка «что знать» о кодировании строк на Java:

  • Экземпляр String в памяти представляет собой последовательность из 16-разрядных «единиц кода», которые Java обрабатывает как значения char . Концептуально эти кодовые единицы кодируют последовательность «кодовых точек», где кодовой точкой является «число, приписываемое данному символу согласно стандарту Юникода». Кодовые точки варьируются от 0 до чуть более одного миллиона, хотя до сих пор было определено только 100 тысяч или около того. Кодовые точки от 0 до 65535 кодируются в одну кодовую единицу, в то время как другие кодовые точки используют две кодовые единицы. Этот процесс называется UTF-16 (иначе UCS-2). Существует несколько тонкостей (некоторые кодовые точки являются недействительными, например 65535, и имеется диапазон из 2048 кодовых точек в первом 65536, зарезервированных точно для кодирования других кодовых точек).
  • Кодовые страницы и т.п. не влияют на то, как Java хранит последовательности в ОЗУ. Вот почему «Юникод» начинается с «Uni». Пока вы не выполняете операции ввода-вывода со своими последовательностями, вы находитесь в мире Юникода, где все используют одно и то же сопоставление символов с кодовыми точками.
  • Наборы символов вступают в действие при кодировании последовательностей в байты или декодировании последовательностей из байтов. Если явно не указано, Java будет использовать набор символов по умолчанию, который зависит от «языка» пользователя, нечеткого агрегированного представления о том, что заставляет компьютер в Японии говорить по-японски. При печати последовательности с помощью System.out.println () JVM преобразует последовательность в то, для чего эти символы подходят, что часто означает преобразование их в байты с помощью набора символов, который зависит от текущего языка (или того, что JVM угадал из текущего языка).
  • Одно приложение Java является компилятором Java. Компилятор Java должен интерпретировать содержимое исходных файлов, которые на системном уровне представляют собой просто кучу байтов. Затем компилятор Java выбирает набор символов по умолчанию и делает это в зависимости от текущего языкового стандарта, как это делает Java, потому что компилятор Java сам написан на Java. Компилятор Java ( javac ) принимает флаг командной строки ( -кодирование ), который можно использовать для переопределения выбора по умолчанию.
  • Компилятор Java создает файлы классов, не зависящие от языка. Строковые литералы попадают в те файлы классов с кодировкой (рода) UTF-8, независимо от набора символов, который компилятор Java использовал для интерпретации исходных файлов. Языковой стандарт в системе, на которой работает компилятор Java, влияет на интерпретацию исходного кода, но как только компилятор Java поймет, что последовательность содержит кодовый пункт номер 6, тогда эта кодовая точка будет проходить в файлы классов, и никто другой. Обратите внимание, что кодовые точки от 0 до 127 имеют одинаковую кодировку в UTF-8, CP-1252 и ISO-8859-1, поэтому то, что вы получаете, неудивительно.
  • Даже при этом экземпляры Последовательностей не зависят от какого-либо вида кодирования, если они остаются в ОЗУ,некоторые операции, которые можно выполнить со последовательностями, зависят от языка. Это не вопрос кодирования; но языковой стандарт также определяет «язык», и так бывает, что понятия верхнего и нижнего регистра зависят от используемого языка. Обычный подозреваемый вызывает «unicode». toUpperCase () : это дает «UNICODE» за исключением того, что текущий языковой стандарт является турецким, в этом случае вы получаете «UNİCODE» I » имеет точку). Основное предположение здесь состоит в том, что если текущий языковой стандарт является турецким, то данные, которыми управляет приложение, вероятно, являются турецким текстом; лично я считаю это предположение в лучшем случае сомнительным. Но так оно и есть.

На практике кодировки следует указывать явно в коде, по крайней мере большую часть времени. Не вызывайте String.getBytes () , вызовите String.getBytes («UTF-8») . Использование кодировки, зависящей от языкового стандарта по умолчанию, хорошо, когда она применяется к некоторым данным, обмениваемым с пользователем, таким как конфигурационный файл или сообщение для немедленного отображения; но в других местах, по возможности, избегайте методов, зависящих от языка.

Среди других языковых компонентов Java имеются календари. Есть весь часовой пояс бизнес, который зависит от «часового пояса», который должен относиться к географическому положению компьютера (а это не часть «языковой» stricto sensu...). Также бесчисленные явские приложения таинственно проваливаются при беге в Бангкоке, потому что на тайском языке Ява по умолчанию соответствует буддийскому календарю, согласно которому текущий год - 2553.

Как правило, предполагайте, что Мир обширен (он есть!) и сохраняйте вещи общие (не делайте ничего, что зависит от шарсета до самого последнего момента, когда необходимо фактически выполнить ввод-вывод).

-121--2251940-

Я не связан с атласским ни в каком пути, но я бы честно предложил вам попробовать Dragon Slayer Quest .

Почему?

Поскольку с лицензиями Starter за 60 долларов США вы получите следующие инструменты:

  • Проверенные в отрасли
  • Полностью интегрированные
  • Полностью поддерживаемые
  • Очень хорошо документированы
  • Высокоразъемные

Вам потребуются:

  • Небольшой подключенный сервер (что-то наподобие двухъядерного с 2GB памятью и достаточным объемом свободного места на жестком диске для хранения файлов и вложений), может быть легко, что ваш старый ПК подходит для роли
  • Ubuntu Server, SVN выходит из коробки, если я правильно помню, если нет, это пакет, который просто установить
  • Работа на этапах поиска

Вы получите:

  • JIRA : Управление проблемами
  • GreenHopper : добавление для гибкой разработки на основе JIRA
  • Слияние : Wiki (документация, поддержка проекта и обмен знаниями)
  • Fisheye : Просмотр источников на стероидах
  • Bamboo : Инструмент непрерывной интеграции
  • Crowd : полная поддержка SSO для вышеперечисленных инструментов
  • и футболка, если вы ее протянете.

Так что не ждите, просто идите.

-121--4213491-

Ну, это было весело. Вот еще один глупый способ сделать это, но как и все остальное, он только вычисляет правильный прогресс для однородных путей.

import os, sys, time

def calc_progress(progress, root, dirs):
    prog_start, prog_end, prog_slice = 0.0, 1.0, 1.0

    current_progress = 0.0
    parent_path, current_name = os.path.split(root)
    data = progress.get(parent_path)
    if data:
        prog_start, prog_end, subdirs = data
        i = subdirs.index(current_name)
        prog_slice = (prog_end - prog_start) / len(subdirs)
        current_progress = prog_slice * i + prog_start

        if i == (len(subdirs) - 1):
            del progress[parent_path]

    if dirs:
        progress[root] = (current_progress, current_progress+prog_slice, dirs)

    return current_progress

def walk(start_root):
    progress = {}
    print 'Starting with {start_root}'.format(**locals())

    for root, dirs, files in os.walk(start_root):
        print '{0}: {1:%}'.format(root[len(start_root)+1:], calc_progress(progress, root, dirs))
0
ответ дан 2 December 2019 в 20:40
поделиться

Одна оптимизация, которую вы могли бы сделать - вы конвертируете список файлов в набор при каждом вызове returnMatches, даже если он никогда не изменяется. переместите преобразование в начало функции 'locate' и передавайте набор при каждой итерации.

0
ответ дан 2 December 2019 в 20:40
поделиться

Думая нестандартно... что если вы сделали это на основе размера:

  • Используйте subprocess, чтобы запустить 'du -sb' и получить total_size вашего корневого каталога
  • Во время прогулки проверьте размер каждого файла и декрементируйте от вашего total_size (давая вам размер rest_size)
  • pct_complete = (total_size - remaining_size)/total_size

Thoughts?

-aj

.
0
ответ дан 2 December 2019 в 20:40
поделиться

Это зависит!

Если файлы и каталоги распределены более или менее равномерно, вы можете показать грубый процесс, предположив, что каждый каталог верхнего уровня будет занимать одинаковое количество времени. Но если они распределены неравномерно, дешево об этом не узнать. Вы должны либо заранее приблизительно знать, насколько заполнен каждый каталог, либо вам нужно дважды пройти через os.walk (но это полезно только в том случае, если ваша фактическая обработка занимает намного больше времени, чем сама os.walk).

То есть: скажем, у вас есть 4 каталога верхнего уровня, каждый из которых содержит 4 файла. Если вы предполагаете, что каждый каталог верхнего уровня занимает 25% прогресса, а каждый файл занимает еще 25% прогресса для этого каталога, вы можете показать хороший индикатор прогресса.Но если окажется, что последний подкаталог содержит намного больше файлов, чем первые несколько, ваш индикатор прогресса достигнет 75%, прежде чем вы узнаете об этом. Вы не можете исправить это, если сам файл os.walk является узким местом (а не вашей обработкой) и это произвольное дерево каталогов (не то, где вы заранее знаете, сколько времени займет каждое поддерево).

И, конечно, при условии, что стоимость здесь примерно одинакова для каждого файла ...

5
ответ дан 2 December 2019 в 20:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: