2

У меня есть каталог, содержащий около 500 тыс. Файлов, и я хочу разделить их на файлы t tar.

Говоря формально, давайте назовем файлы file_0, ..., file_{N-1} , где N около 500k. Я хочу создать t архивированных файлов каждый из которых содержит T=N/t файлы, где я-я деготь файл содержит

file_(i*N), ..., file_((i+1)*N - 1),    i in {0, ..., t-1}

Какой эффективный способ сделать это? Я собирался написать скрипт Python, который просто перебирает N файлов и делит их на t папок, а затем вызывает tar в каждой, но это кажется очень неоптимальным. У меня много ядер на сервере, и я чувствую, что это должно происходить параллельно.

2 ответа2

4

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

  1. Создайте большой список файлов, например, [ [f0..f0-1], [fn..f2n-1]..]
  2. Используйте ThreadPoolExecutor чтобы съесть этот список со всеми многочисленными нитями, которые есть на вашем компьютере. Это может выглядеть так:
import os
import sys
from concurrent.futures import ThreadPoolExecutor
import subprocess
import itertools
import math


def main(p, num_tar_files):
    files = list(split_files_in(p, num_tar_files))
    tar_up = tar_up_fn(p)
    with ThreadPoolExecutor(len(files)) as executor:
        archives = list(executor.map(tar_up, itertools.count(), files))
        print("\n {} archives generated".format(len(archives)))


def split_files_in(p, num_slices):
    files = sorted(os.listdir(p))
    N = len(files)
    T = int(math.ceil(N / num_slices))  # means last .tar might contain <T files
    for i in range(0, N, T):
        yield files[i:i+T]


def tar_up_fn(p):
    def tar_up(i, files):
        _, dir_name = os.path.split(p)
        tar_file_name = "{}_{:05d}.tar".format(dir_name, i)
        print('Tarring {}'.format(tar_file_name))
        subprocess.call(["tar", "-cf", tar_file_name] + files, cwd=p)
        return tar_file_name
    return tar_up


if __name__ == '__main__':
    main(sys.argv[1], int(sys.argv[2]))
0

используя zsh для создания списков для tar

Надеюсь, я понял, что ты пытаешься сделать. t=731 было просто число, которое я выбрал из воздуха. Взломать по мере необходимости. Следующее создает несколько файлов с t именами файлов или последним файлом с оставшимися именами файлов, если они не равны t .

Var=(*(.)) # glob files in current directory
VarSorted=(${(on)Var})  # numeric sort
fn=1  # Tar list file number
t=731  # Number of files in each tar file
for (( i = 1 ; i <= ${#VarSorted} ; i = i + t ))
do
  print -l -- ${VarSorted[$i,$i+$t-1]} > /tmp/tar_file_list_${(l:5::0:)fn}
  (( fn++ ))
done

Используйте команду tar -t или --files-from(краткая / длинная форма) для генерации каждого файла tar. Это тоже может быть в сценарии.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .