Почему не создаётся архив, если на входе более одного пути?
Я написал код который делает резервную копию выбранной папки. Этот код принимает путь к каталогу, который нужно заархивировать в выбранном месте.
Если программа принимает только один путь, то она работает успешно, создаётся архив с папкой, в папке все файлы, но если программа будет принимать более 1 пути, то создаётся пустой архив без папок и файлов.
Как решить эту проблему?
import os
import time
import zipfile
# 1. Файлы и каталоги, которые необходимо скопировать, собираются в список.
source = ['C:\\Code']
# Заметьте, что для имён, содержащих пробелы, необходимо использовать
# двойные кавычки внутри строки.
# 2. Резервные копии должны храниться в основном каталоге резерва.
target_dir = 'C:\\Sasha' # Подставьте ваш путь.
# 3. Файлы помещаются в zip-архив.
# 4. Текущая дата служит именем подкаталога в основном каталоге
today = target_dir + os.sep + time.strftime('%Y%m%d')
# Текущее время служит именем zip-архива
now = time.strftime('%H%M%S')
# Запрашиваем комментарий пользователя для имени файла
comment = input('Введите комментарий --> ')
if len(comment) == 0: # проверяем, введён ли комментарий
target = today + os.sep + now + '.zip'
else:
target = today + os.sep + now + '_' + \
comment.replace(' ', '_') + '.zip'
# Создаём каталог, если его ещё нет
if not os.path.exists(today):
os.mkdir(today) # создание каталога
print('Каталог успешно создан', today)
# 5. Используем команду "zip" для помещения файлов в zip-архив
zip_file = zipfile.ZipFile(target, 'w')
for root, dirs, files in os.walk(''.join(source)):
for file in files:
zip_file.write(os.path.join(root, file))
# Закрываем архив
zip_file.close()
Ответы (2 шт):
Не нужно делать join(), Вы в одну строку все соедините, которую потом os.walk не поймет. Для этого можно воспользоваться решением через стандартную библиотеку itertools: itertools.chain.from_iterable(os.walk(s) for s in source).
Еще такой момент. Создавать zip-архив лучше через with. Тогда не придется отдельно его закрывать. Ну и код будет чище.
Ну и последнее) Собирать путь удобнее через os.path.join().
import itertools
import os
import time
import zipfile
# 1. Файлы и каталоги, которые необходимо скопировать, собираются в список.
source = ['C:\\Code']
# Заметьте, что для имён, содержащих пробелы, необходимо использовать
# двойные кавычки внутри строки.
# 2. Резервные копии должны храниться в основном каталоге резерва.
target_dir = 'C:\\Sasha' # Подставьте ваш путь.
# 3. Файлы помещаются в zip-архив.
# 4. Текущая дата служит именем подкаталога в основном каталоге
today = os.path.join(target_dir, time.strftime('%Y%m%d'))
# Текущее время служит именем zip-архива
now = time.strftime('%H%M%S')
# Запрашиваем комментарий пользователя для имени файла
comment = input('Введите комментарий --> ')
if len(comment) == 0: # проверяем, введён ли комментарий
target = today + os.sep + now + '.zip'
else:
target = today + os.sep + now + '_' + \
comment.replace(' ', '_') + '.zip'
# Создаём каталог, если его ещё нет
if not os.path.exists(today):
os.mkdir(today) # создание каталога
print('Каталог успешно создан', today)
# 5. Используем команду "zip" для помещения файлов в zip-архив
with zipfile.ZipFile(target, 'w') as zip_file:
for root, dirs, files in itertools.chain.from_iterable(os.walk(s) for s in source):
for file in files:
zip_file.write(os.path.join(root, file))
Вам уже объяснили в чем причина ошибки в комментарии под вопросом и в соседнем ответе.
Я бы посоветовал оформлять операции в функции или в классы. И постарайтесь выносить запрос пользователя на ввод за пределы функции. Кроме того, в современных версиях Python при работе с путями и именами файлов предпочтение отдается встроенному модулю - pathlib.
Вот пример функции для создания резервных копий указанных директорий:
import time
from pathlib import Path
from typing import Union, List
path_type = Union[Path, str]
target_dir = Path("C:\\Sasha")
def bkp_dirs(
source_dirs: Union[List[path_type], path_type],
target_filename: path_type
) -> None:
if not isinstance(source_dirs, list):
source_dirs = [source_dirs]
target_filename = Path(target_filename)
target_filename.parent.mkdir(parents=True, exist_ok=True)
zip_file = zipfile.ZipFile(target_filename, 'w')
for d in source_dirs:
for f in Path(d).glob("**/*"):
zip_file.write(f)
zip_file.close()
пример использования:
comment = input('Введите комментарий --> ')
target = target_dir \
/ time.strftime('%Y%m%d') \
/ f"{time.strftime('%H%M%S')}{comment.replace(' ', '_')}.zip"
source_dirs = ['C:\\Code']
bkp_dirs(source_dirs, target)