I ended up writing a script in Python because I was unable to solve this using Bash, although both @JayCravens and @user1683793 provided good answers that I'll use in the future. I understand that Python is not native Unix/Linux, so this solution may not fit in this community. Nevertheless, since I was able to solve the problem, I thought it would be useful to post my solution.
In this case, I instantiate two zip file objects, one used as "permanent" storage (where the final zip file will be written from), and one used as temporary storage for individual files where I can measure the compressed size of the next file. I then add the next file to the permanent zip file if the combined size (permanent + temp) is less than my bound. This is not recursive, although it could be modified to be. Currently, I provide a DIRECTORY
and a file extension, then all files in DIRECTORY
with that file extension are looped over until complete.
import os
from pathlib import Path
import zipfile
MAX_ZIP_FILE_SIZE = 500e6 # bytes
DIRECTORY = Path("/home/me/my_directory")
FILE_EXTENSION = "csv"
archive_name = "archive" # file prefix, e.g., <archive_name>_1.zip
zip_file_number = 1 # zip file number, e.g., archive_<zip_file_number>.zip
my_zip = zipfile.ZipFile(
file=DIRECTORY.joinpath(f"{archive_name}_{zip_file_number}.zip"),
mode="w",
compression=zipfile.ZIP_DEFLATED,
compresslevel=6,
)
file_list = list(DIRECTORY.glob(f"*.{FILE_EXTENSION}"))
ii = 0
for file_number, file in enumerate(file_list, start=1):
if ii == 0:
my_zip.write(filename=file, arcname=file.name)
if os.path.getsize(my_zip.filename) >= MAX_ZIP_FILE_SIZE:
my_zip.close()
zip_file_number += 1
my_zip = zipfile.ZipFile(
file=DIRECTORY.joinpath(f"{archive_name}_{zip_file_number}.zip"),
mode="w",
compression=zipfile.ZIP_DEFLATED,
compresslevel=6,
)
ii = 0
else:
tmp = zipfile.ZipFile(
file=DIRECTORY.joinpath(f"{archive_name}_{zip_file_number + 1}.zip"),
mode="w",
compression=zipfile.ZIP_DEFLATED,
compresslevel=6,
)
tmp.write(file, arcname=file.name)
if (
os.path.getsize(my_zip.filename) + os.path.getsize(tmp.filename)
) >= MAX_ZIP_FILE_SIZE:
my_zip.close()
my_zip = tmp
zip_file_number += 1
else:
my_zip.write(filename=file, arcname=file.name)
ii += 1
print(f"Completed {file_number}/{len(file_list)}\t\t\t", end="\r")
try:
my_zip.close()
except Exception as e:
print(e)
try:
tmp.close()
except Exception as e:
print(e)
print("\n")