대용량 파일을 분할하기 위해 바이트를 직접 분할하는 것이 안전합니까?

대용량 파일을 분할하기 위해 바이트를 직접 분할하는 것이 안전합니까?

내 경우 큰 파일은 myBigFile.tar.gz크기가 52GB인 tar.gz였으며 이를 2GB 크기의 청크로 분할하여 27개의 부분 파일을 갖게 되었습니다.

제가 처음부터 작성한 코드는 다음과 같습니다.

from time import sleep
from glob import glob
import filecmp
import os

CHUNK_SIZE = 2097152000  # bytes
# CHUNK_SIZE = 1000000  # bytes
# CHUNK_SIZE = 2  # bytes

ORIGINAL_FILE_DIR = './data/original'
SPLITTED_FILE_DIR = './data/splitted'
JOINED_FILE_DIR = './data/joined'


def get_original_filepath(filename):
  return f'{ORIGINAL_FILE_DIR}/{filename}'


def get_splitted_filepath(filename, overwrite=False):
  partspath = f'{SPLITTED_FILE_DIR}/{filename}.parts'
  if overwrite:
    try:
      os.rmdir(partspath)
    except Exception as e:
      print(e)
    try:
      os.mkdir(partspath)
    except Exception as e:
      print(e)
  return partspath


def get_joined_filepath(filename):
  return f'{JOINED_FILE_DIR}/{filename}'


def get_part_extension(part, pad_num=8):
  if isinstance(part, int):
    return f'{part:0{pad_num}d}.part'
  elif isinstance(part, str):
    return f'{part}.part'
  else:
    raise Exception('Unknown typeof <part>', type(part))


def get_part_filename(filename, part, pad_num=8):
  part_extension = get_part_extension(part, pad_num)
  return f'{filename}.{part_extension}'


def get_file_size(filepath):
  return os.path.getsize(filepath)


def get_number_of_chunks(total_size, chunk_size):
  return total_size // chunk_size + (total_size % chunk_size > 0)


def is_directory_empty(directory_path):
  try:
    # Get the list of files and directories in the specified path
    files = os.listdir(directory_path)

    # Check if there are any files in the list
    if len(files) == 0:
      return True
    else:
      return False
  except:
    # Handle the case when the directory does not exist
    return True


def split_file(filename, chunk_size=CHUNK_SIZE):
  original_path = get_original_filepath(filename)
  if get_file_size(original_path) == 0:
    print(Exception('E: Original file not found!'))
  splitted_path = get_splitted_filepath(filename, overwrite=True)
  with open(original_path, 'rb') as readfile:
    number_of_chunks = get_number_of_chunks(get_file_size(original_path),
                                            chunk_size)
    for part in range(number_of_chunks):
      chunk = readfile.read(chunk_size)
      part_filename = get_part_filename(filename, part,
                                        len(str(number_of_chunks)))
      with open(f'{splitted_path}/{part_filename}', 'wb') as writefile:
        writefile.write(chunk)


def join_file(filename):
  splitted_path = get_splitted_filepath(filename)
  joined_path = get_joined_filepath(filename)
  if is_directory_empty(splitted_path):
    print(Exception('E: Splitted file not found!'))
  part = '*'  # wilcard
  part_filename = get_part_filename(filename, part)
  partfiles = [
      os.path.normpath(fn) for fn in glob(f'{splitted_path}/{part_filename}')
  ]
  with open(joined_path, 'ab') as appendfile:
    for partfile in partfiles:
      with open(partfile, 'rb') as readfile:
        appendfile.write(readfile.read())


def compare_file(filename):
  # Specify the paths of the two files
  file1_path = get_original_filepath(filename)
  file2_path = get_joined_filepath(filename)

  return f'{filename} is identical.' if filecmp.cmp(
      file1_path, file2_path) else f'{filename} is not identical.'


filename = 'myBigFile.tar.gz'

split_file(filename)
join_file(filename)
print(compare_file(filename))

따라서 Splitted_path는 다음과 같습니다.

./data/myBigFile.tar.gz.parts/myBigFile.tar.gz.00.part
./data/myBigFile.tar.gz.parts/myBigFile.tar.gz.01.part
...
./data/myBigFile.tar.gz.parts/myBigFile.tar.gz.25.part

tar, zip 또는 기타 아카이버와 같은 Unix 유틸리티를 사용할 수 있다는 것을 알고 있습니다.

CHUNK_SIZE가 작은 작은 파일에서도 테스트했는데 문제 없이 파일에 결합되었습니다.

답변1

임의의 바이트 지점에서 바이너리 파일을 분할할 수 있습니다.

텍스트 파일을 분할하는 경우 임의의 바이트 지점에서 분할할 수 있지만 멀티바이트 유니코드 문자 중간에서 분할될 가능성이 높습니다. 그러나 내용을 해석하기 전에 파일을 연결하면 문제가 되지 않습니다. (또한 내용을 처리하기 전에 바이너리의 일부를 연결해야 하므로 차이가 없습니다.)

Python 코드에서와 같이 가변 비트 출력 조각을 사용한다는 것은 cat myBigFile.tar.gz.*.part간단한 콘텐츠를 사용하여 원본 콘텐츠를 재구성할 수 없다는 것을 의미합니다. (26개 부품의 경우 1, 10, 11, 12… 19, 2, 20, 21… 26, 3, 4, 5, 6, 7, 8, 9의 순서로 표시됩니다.)

다음은 myBigFile.tar.gz사용자 고유의 명명 규칙을 사용하여 2GB 부분으로 분할하는 방법입니다.

split --bytes=2G --numeric-suffixes=1 --suffix-length=2 --additional-suffix=.part myBigFile.tar.gz myBigFile.tar.gz.

man split명령줄 스위치에 대한 자세한 내용은 리소스를 참조하세요.

출력 파일 예:

myBigFile.tar.gz.01.part
myBigFile.tar.gz.02.part
myBigFile.tar.gz.03.part

이러한 파일이 있으면 간단한 명령과 셸 와일드카드를 사용하여 원본 파일을 재구성할 수 있습니다.

cat myBigFile.tar.gz.??.part >myBigFile.tar.gz

관련 정보