大容量ファイルを分割するためにバイトを直接分割するのは安全ですか?

大容量ファイルを分割するためにバイトを直接分割するのは安全ですか?

私の場合、大きなファイルはmyBigFile.tar.gz52GBの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_pa​​thは次のようになります。

./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

任意のバイトポイントでバイナリファイルを分割できます。

テキストファイルを分割すると、任意のバイトポイントで分割できますが、マルチバイトUnicode文字の途中で分割される可能性が高くなります。ただし、内容を解釈する前にファイルをリンクしても問題ありません。 (また、内容を処理する前にバイナリの一部を連結する必要があるので違いはありません。)

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独自の命名規則を使用して2 GBの部分に分割する方法です。

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

おすすめ記事