Рекурсивное копирование файлов с прогрессом

#python #file-io #copy #progress-bar #pyqt4

#python #file-io #Копировать #индикатор выполнения #pyqt4

Вопрос:

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

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

Прямо сейчас я использую PyQt4, и мой код выглядит следующим образом:

 self.status('Counting files...')
self.count = int(check_output(['-c', 'find /opt/linux/work/root-image/ -type f | wc -l'], stderr = PIPE, shell = True))

self.status('Copying files...')

i = 0

for root, dirs, files in os.walk('/opt/linux/work/root-image/'):
  for file in files:
    i  = 1
    f = os.path.join(root, file)

    try:
      os.system('mkdir -p /tmp/foo'   os.path.split(f)[0])
    except:
      pass

    os.system('cp '   f   ' /tmp/foo'   f)

    if i % 100 == 0:
      self.emit(SIGNAL('progress(int)'), int(100.0 * float(i) / float(self.count)))

self.status('Done...')
  

Это довольно неэффективно из-за индикатора выполнения. Изображение целиком 2.1GB , и сценарию требуется действительно много времени, чтобы скопировать файлы. Намного длиннее простого cp -r .

Есть ли какой-либо эффективный способ сделать это? Для панелей выполнения копирования одного файла все, что вы делаете, это читаете небольшие фрагменты за раз, но я понятия не имею, как это сделать для каталога с 91,489 файлами.

Любая помощь была бы полезна. Спасибо!

Ответ №1:

Вы могли бы попробовать использовать shutil.copy для копирования файлов вместо вызова ОС с помощью os.system (что создает отдельный процесс). Вы также можете использовать os.mkdir для создания новых каталогов. Однако вы уверены, что это происходит медленно из-за индикатора выполнения, а не из-за чего-то еще?

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

1. Излучение сигнала довольно сильно замедляет работу. Но я попробую эти изменения, возможно, на этот раз процессы действительно замедляют работу.

2. Если у вас 91489 файлов и вы запускаете сигнал после каждых 100 файлов, то это всего лишь 914 выбросов сигнала или около того — это не должно быть проблемой. Это намного быстрее, если вы закомментируете self.emit часть в цикле for и скопируете файлы один за другим, используя os.system как указано выше?

3. Сейчас я тестирую это. Кажется, застрял на неработающих символических ссылках (которые работают, если корневой каталог был исходным, но это не работает в хост-системе).

4. Очевидно, вам приходится обрабатывать такие угловые случаи самостоятельно, т. Е. заранее проверяя, является ли файл неработающей символической ссылкой ( os.path.exists должен вернуться False ), а затем создавая символическую ссылку вручную с помощью os.symlink .

5.Символические ссылки работают, если корневая папка / является папкой, из которой я копирую, поскольку папка, из которой я копирую, является FS Linux. Python не любит неработающие символические ссылки, поэтому, я думаю, мне придется cp их вручную…