インターネットが十分に高速になり、比較的大きなサイズのファイルの受け渡しも気軽に行われるようになってきた。動画や画像、AI関連のデータなど数ギガを超えるファイルが送られてくることもある。しかし、ネットワークによってはダウンロード中にエラーになりダウンロードできないこともある。そこで、今回は巨大ファイルを分割するプログラムを作ってみよう。
巨大ファイルの分割もPythonにお任せ
最近ではファイルの受け渡しをする際、OneDriveやGoogleDrive、Dropboxなどのクラウドストレージを経由することが多いだろう。こうしたサービスを使うと巨大なファイルでも、比較的スムーズに受け渡しが可能だ。しかも、ファイルのURLをメールなどで送信した後で、誤送信に気付いたとしても、すぐに共有を停止することもできるので利便性が良い。
筆者も多くのデータをこうしたクラウドストレージ経由で日々やり取りしている。ところが、ある日、自宅のネットワークの調子が悪く、何度試しても途中でダウンロードが止まってしまうという状況に陥ってしまった。そこで、思いついたのが、巨大なファイルを小さなファイルに分割してダウンロードして、最後に結合するという手法だ。多少ネットワークの調子が悪いとしても、ファイルを小さく分割すれば、比較的スムーズにダウンロードができる。
それで、巨大なファイルを分割するツールは、既にいろいろあるのだが、Pythonを使うことで比較的簡単に作成できる。さっそくファイル分割ツールを作ってみよう。
ファイル結合はバッチファイルを使うことができる
なお、ファイルの分割自体はPythonを使うことになるのだが、ファイルの結合はWindowsの標準機能であるバッチファイルを使う事ができる。例えば、ファイル「01.bin」と「02.bin」と「03.bin」を結合して「output.mp4」に保存したければ、次のようなバッチファイルを作れば良い。
rem バッチファイル
copy /b 01.bin + 02.bin + 03.bin output.mp4 > nul
バッチファイルが良い点は、Pythonをインストールしてなくても、バッチファイルをダブルクリックするだけで実行できる点にある。
このように、ファイルの結合処理は簡単であるため、今回作るPythonのプログラムでは、ファイルを分割するのと同時に、ファイルを結合するバッチファイルも同時に生成する仕組みにしてみよう。
ファイル分割を行うプログラム
以下のプログラムがファイル分割、および、ファイル結合バッチファイルを書き出すプログラムだ。「split_file.py」という名前で保存しよう。
import os
# ファイルを分割する関数 --- (*1)
def split_file(file_path, chunk_size):
# ファイルを開く --- (*2)
with open(file_path, 'rb') as f:
fileno = 0
chunk = f.read(chunk_size) # 分割サイズ分読み込む --- (*3)
while chunk:
# 出力ファイル名を決める --- (*4)
output_filename = f"{file_path}.parts_{fileno:02d}.bin"
print(f"[出力{fileno}] {output_filename}")
# 分割ファイルを出力 --- (*5)
with open(output_filename, 'wb') as output:
output.write(chunk)
fileno += 1
chunk = f.read(chunk_size)
# Windows用にバッチファイルを生成する --- (*6)
basename = os.path.basename(file_path)
with open(file_path + '.bat', 'wt', encoding='shift_jis') as bat:
files = [f'{basename}.parts_{no:02d}.bin' for no in range(0, fileno)]
files_str = ' + '.join(files)
bat.write(f'copy /b {files_str} out_{basename} > nul')
if __name__ == "__main__":
# 分割を実行 --- (*7)
input_file_path = 'test.mp3'
chunk_size = 1 * 1024 * 1024 # 1MBを指定
split_file(input_file_path, chunk_size) # 分割実行
最初にプログラムの解説をしよう。
(*1)ではファイルを分割する関数split_fileを定義する。引数には、入力ファイル名と分割サイズを指定する。
(*2)では入力ファイルをバイナリモードで読み込み、(*3)で繰り返し分割サイズずつ読み込む。(*4)では分割先のファイル名を決定し、(*5)で分割ファイルを書き出す。
そして、(*6)では、結合のためのバッチファイルを生成する処理を記述している。先ほど紹介した「copy /b (結合対象ファイル) (出力ファイル) > nul」というコマンドを書き出している。
最後に(*7)で入力ファイル名と分割サイズを指定して、(*1)で定義した関数を呼ぶ。
なお、ここでは、「test.mp3」というファイルを1MBごとに分割するという指定がなされている。そのため、実際に自分のファイルを分割したいときは(*7)以降の部分を書き換えて実行しよう。
プログラムを実行するには、PowerShellなどのターミナルで次のコマンドを実行する。
cd <プログラムを配置したフォルダのパス>
python split_file.py
すると、次のように「test.mp3」が分割されて、「test.mp3.parts_00.bin」「test.mp3.parts_01.bin」…というファイルと「test.mp3.bat」という結合用のバッチファイルが生成される。
そして、出力されたバッチファイル「test.mp3.bat」をダブルクリックすることでファイルの結合が行われる。
実際に、分割したファイルを配布する際は、バッチファイルと「(元ファイル名).parts_*.bin」という分割ファイルを配布すれば良い。
ただし、ネットワーク越しにバッチファイルを配布した場合、次の画像のように、WindowsのDefenderによるセキュリティ保護機能が働くため、そのままでは実行できない。ファイルを実行するには「詳細情報」をクリックし、その後「実行」を押す必要がある。
改造してみた
なお、分割ツールを作っていたら思った以上に楽しくなってしまったので、上記プログラムを改造して、Windowsのバッチファイル用だけでなく、macOS/Linux用のシェルスクリプトを生成する機能も追加した。そして、コマンドラインでファイル名や分割サイズを指定できるようにもしてみた。完全版をこちらにアップしてみたので、気になる人は見てみて欲しい。