Tarfile.TarFile.add: примеры (PYTHON)

Метод TarFile.add для работы с tar-архивами в Python
Раздел: Архивы, Создание архивов
tarfile.TarFile.add(name, arcname, recursive, filter): None

Описание функции tarfile.TarFile.add

Метод add() принадлежит классу TarFile модуля tarfile. Его применяют для добавления файла или каталога в открытый tar-архив. Это основной способ наполнения архивов содержимым.

Метод используют, когда требуется программно создать или обновить tar-архив, упаковав в него выбранные данные. Поддерживаются все распространенные форматы архивов: gzip, bzip2, xz.

Аргументы метода

  • name (строка, обязательный): путь к файлу или каталогу в файловой системе, который необходимо добавить.
  • arcname (строка, необязательный): альтернативное имя, под которым объект будет сохранен в архиве. Если не указано, используется name.
  • recursive (булевый, необязательный, по умолчанию True): если True и добавляется каталог, то все его содержимое включается в архив рекурсивно. При значении False каталог добавляется пустым.
  • filter (функция, необязательный): функция, применяемая к каждому добавляемому объекту TarInfo для его модификации или фильтрации. Если функция возвращает None, объект исключается из архива.

Возвращаемое значение

Метод не возвращает значений (None). Его результат - изменение состояния объекта архива, к которому его применили.

Примеры использования функции add

Базовый пример добавления одного файла.

import tarfile

with tarfile.open('archive.tar', 'w') as tar:
    tar.add('document.txt')
    print('Файл добавлен')
Файл добавлен

Добавление файла с переименованием внутри архива.

import tarfile

with tarfile.open('archive.tar', 'w') as tar:
    tar.add('data.csv', arcname='backup/data.csv')
    print('Файл добавлен как backup/data.csv')
Файл добавлен как backup/data.csv

Добавление каталога без рекурсивного обхода.

import tarfile

with tarfile.open('archive.tar', 'w') as tar:
    tar.add('my_folder', recursive=False)
    print('Пустая папка добавлена')
Пустая папка добавлена

Использование фильтра для исключения файлов по расширению.

import tarfile

def filter_exclude_py(tarinfo):
    if tarinfo.name.endswith('.py'):
        return None
    return tarinfo

with tarfile.open('archive.tar', 'w') as tar:
    tar.add('project_folder', filter=filter_exclude_py)
    print('Добавлены все файлы, кроме .py')
Добавлены все файлы, кроме .py

Похожие функции в Python

  • tarfile.TarFile.addfile(tarinfo, fileobj=None): добавляет в архив информацию о файле (TarInfo) и, опционально, данные из файлового объекта. Этот метод подходит, когда требуется предварительно настроить метаданные (права доступа, время модификации) или добавить данные из потока, а не из файла на диске.
  • shutil.make_archive(base_name, format, root_dir, ...): высокоуровневая функция для создания архивов различных форматов (zip, tar, gztar и др.). Ее применение удобно для быстрого создания стандартных архивов без тонкой настройки, в то время как TarFile.add дает полный контроль над процессом.

Альтернативы в других языках программирования

PHP: Класс PharData. Отличается интеграцией с форматом Phar, но умеет работать и с обычными tar-архивами.

$phar = new PharData('archive.tar');
$phar->addFile('/path/to/file.txt', 'internal/path.txt');
echo 'Файл добавлен.\n';
Файл добавлен.

JavaScript (Node.js): Библиотека tar. Работа асинхронная, основана на потоках.

const tar = require('tar');
tar.c(
  {gzip: true, file: 'archive.tar.gz'},
  ['file1.txt', 'folder']
).then(() => console.log('Архив создан'));
Архив создан

Java: Библиотека Apache Commons Compress. Требует более многословного кода для создания архива по сравнению с Python.

import org.apache.commons.compress.archivers.tar.*;
import java.io.*;

TarArchiveEntry entry = new TarArchiveEntry("file.txt");
entry.setSize(new File("file.txt").length());
tarOutput.putArchiveEntry(entry);
// ... копирование данных файла
tarOutput.closeArchiveEntry();

Golang: Пакет archive/tar. Работа ведется через создание заголовков (Header) и последовательную запись данных.

file, _ := os.Open("data.txt")
info, _ := file.Stat()
hdr, _ := tar.FileInfoHeader(info, "")
tw.WriteHeader(hdr)
io.Copy(tw, file)

Типичные ошибки при использовании

Попытка добавить несуществующий файл или каталог.

import tarfile

try:
    with tarfile.open('archive.tar', 'w') as tar:
        tar.add('non_existent_file.txt')
except FileNotFoundError as e:
    print(f'Ошибка: {e}')
Ошибка: [Errno 2] No such file or directory: 'non_existent_file.txt'

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

import tarfile

# Сначала создаем архив
with tarfile.open('archive.tar', 'w') as tar:
    tar.add('file1.txt')

# Пытаемся добавить в архив, открытый для чтения
try:
    with tarfile.open('archive.tar', 'r') as tar:
        tar.add('file2.txt')
except tarfile.ReadError as e:
    print(f'Ошибка: {e}')
Ошибка: cannot write to a read-only archive

Ошибки, связанные с правами доступа при чтении исходного файла.

import tarfile
import os

# Создаем файл без прав на чтение
with open('secret.txt', 'w') as f:
    f.write('data')
os.chmod('secret.txt', 0o000) # Убираем все права

try:
    with tarfile.open('archive.tar', 'w') as tar:
        tar.add('secret.txt')
except PermissionError as e:
    print(f'Ошибка доступа: {e}')
finally:
    os.chmod('secret.txt', 0o644) # Возвращаем права
    os.remove('secret.txt')
Ошибка доступа: [Errno 13] Permission denied: 'secret.txt'

Изменения в последних версиях Python

В Python 3.8 был добавлен ключевой параметр filter. До его введения для фильтрации или модификации добавляемых файлов приходилось использовать более сложные обходные пути, например, предварительный сбор списка файлов и их индивидуальное добавление через TarFile.gettarinfo и TarFile.addfile с модификацией объектов TarInfo.

Начиная с версии Python 3.12, параметр filter стал рекомендуемым способом фильтрации, в то время как устаревший параметр exclude (который присутствовал в похожей функции tarfile.create) был окончательно удален.

Расширенные примеры использования

Добавление только файлов с определенными расширениями, игнорируя все остальные.

Пример python
import tarfile
import os

def filter_only_images(tarinfo):
    if tarinfo.isreg() and tarinfo.name.endswith(('.png', '.jpg', '.jpeg')):
        return tarinfo
    return None

with tarfile.open('images.tar', 'w') as tar:
    tar.add('photos_folder', filter=filter_only_images)
    members = tar.getmembers()
    print(f'Добавлено файлов: {len(members)}')
    for m in members:
        print(f'  - {m.name}')
Добавлено файлов: 3
  - photos_folder/cat.jpg
  - photos_folder/dog.png
  - photos_folder/scenery.jpeg

Изменение владельца и прав доступа для файлов при добавлении в архив.

Пример python
import tarfile

def set_root_owner(tarinfo):
    tarinfo.uid = 0
    tarinfo.gid = 0
    tarinfo.uname = 'root'
    tarinfo.gname = 'root'
    tarinfo.mode = 0o644  # Стандартные права на чтение/запись
    return tarinfo

with tarfile.open('system_backup.tar', 'w') as tar:
    tar.add('configs/app.conf', filter=set_root_owner)
    info = tar.getmember('configs/app.conf')
    print(f'Владелец в архиве: {info.uname}:{info.gname}')
    print(f'Права в архиве: {oct(info.mode)}')
Владелец в архиве: root:root
Права в архиве: 0o644

Рекурсивное добавление каталога с исключением скрытых файлов и папок (начинающихся с точки).

Пример python
import tarfile
import os

def exclude_hidden(tarinfo):
    base_name = os.path.basename(tarinfo.name)
    if base_name.startswith('.'):
        return None
    return tarinfo

with tarfile.open('project.tar.gz', 'w:gz') as tar:
    tar.add('my_project', filter=exclude_hidden)
    names = tar.getnames()
    print('Добавленные объекты:')
    for name in sorted(names):
        if '/.' not in name:  # Проверка, что внутри путей тоже нет скрытых
            print(f'  {name}')
Добавленные объекты:
  my_project
  my_project/LICENSE
  my_project/README.md
  my_project/src
  my_project/src/main.py

Создание архива с сохранением символических ссылок как ссылок, а не как файлов, на которые они указывают.

Пример python
import tarfile
import os

# Создаем тестовую структуру
os.makedirs('test_dir', exist_ok=True)
with open('test_dir/real_file.txt', 'w') as f:
    f.write('content')
os.symlink('real_file.txt', 'test_dir/link.txt')

with tarfile.open('with_links.tar', 'w') as tar:
    # По умолчанию filter=None, ссылки добавляются как ссылки
    tar.add('test_dir')
    for member in tar.getmembers():
        print(f'{member.name} - islink: {member.islnk() or member.issym()}')

# Уборка
import shutil
shutil.rmtree('test_dir')
test_dir - islink: False
test_dir/real_file.txt - islink: False
test_dir/link.txt - islink: True

питон tarfile.TarFile.add function comments

En
Tarfile.TarFile.add Add file to TAR archive