• 对大文件压缩包分割和恢复的方法_python


    1.前言

            某次需要将大的压缩包分割传输,并恢复。找到了一段有用的python程序

            这个软件包可以压缩和分割大文件。它从一个根目录开始,遍历子目录,并扫描其中的每个文件。如果某个文件的大小超过了阈值大小,那么它们会被压缩和分割成多个归档文件,每个归档文件的最大大小为分区大小。压缩/分割适用于任何文件扩展名。

    举例:

    对于目录

    1. $ tree --du -h ~/MyFolder
    2. └── [415M] My Datasets
    3. │ ├── [6.3K] Readme.txt
    4. │   └── [415M] Data on Leaf-Tailed Gecko
    5. │   ├── [ 35M] DatasetA.zip
    6. │   ├── [ 90M] DatasetB.zip
    7. │   ├── [130M] DatasetC.zip
    8. │    └── [160M] Books
    9. │    ├── [ 15M] RegularBook.pdf
    10. │    └── [145M] BookWithPictures.pdf
    11. └── [818M] Video Conference Meetings
    12. ├── [817M] Discussion_on_Fermi_Paradox.mp4
    13. └── [1.1M] Notes_on_Discussion.pdf

    使用

    $ python3 src/main.py  --root_dir ~/MyFolder

    目录变成

    1. $ tree --du -h ~/MyFolder
    2. └── [371M] My Datasets
    3. │ ├── [6.3K] Readme.txt
    4. │   └── [371M] Data on Leaf-Tailed Gecko
    5. │   ├── [ 35M] DatasetA.zip
    6. │   ├── [ 90M] DatasetB.zip
    7. │   ├── [ 95M] DatasetC.zip.7z.001
    8. │   ├── [ 18M] DatasetC.zip.7z.002
    9. │    └── [133M] Books
    10. │    ├── [ 15M] RegularBook.pdf
    11. │    ├── [ 95M] BookWithPictures.pdf.7z.001
    12. │    └── [ 23M] BookWithPictures.pdf.7z.002
    13. └── [794M] Video Conference Meetings
    14. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.001
    15. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.002
    16. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.003
    17. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.004
    18. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.005
    19. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.006
    20. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.007
    21. ├── [ 95M] Discussion_on_Fermi_Paradox.mp4.7z.008
    22. ├── [ 33M] Discussion_on_Fermi_Paradox.mp4.7z.009
    23. └── [1.1M] Notes_on_Discussion.pdf

    使用

    $ python3 src/reverse.py  --root_dir ~/MyFolder

    则恢复到原始文件。

    2.环境准备

    2.1 python3

            本地已经安装 Python 3.x.x.

    2.2 7z库文件下载安装

            虽然在src/main.py中遍历目录是串行的,但是通过7z压缩/分割每个文件在默认情况下是并行的。
            使用src/reverse.py进行反转完全是串行的。

    3.分割

    用于分割大文件的代码main.py如下:

    1. import sys # 导入sys模块,用于退出程序
    2. import os # 导入os模块,用于文件和目录操作
    3. import shutil # 导入shutil模块,用于文件操作
    4. import subprocess # 导入subprocess模块,用于执行shell命令
    5. import argparse # 导入argparse模块,用于解析命令行参数
    6. def parse_arguments():
    7. # 解析命令行参数
    8. parser = argparse.ArgumentParser(description='GitHub-ForceLargeFiles')
    9. parser.add_argument('--root_dir', type=str, default=os.getcwd(),
    10. help="Root directory to start traversing. Defaults to current working directory.")
    11. parser.add_argument('--delete_original', type=bool, default=True,
    12. help="Do you want to delete the original (large) file after compressing to archives?")
    13. parser.add_argument('--partition_ext', type=str, default="7z", choices=["7z", "xz", "bzip2", "gzip", "tar", "zip", "wim"],
    14. help="Extension of the partitions. Recommended: 7z due to compression ratio and inter-OS compatibility.")
    15. parser.add_argument('--cmds_into_7z', type=str, default="a",
    16. help="Commands to pass in to 7z.")
    17. parser.add_argument('--threshold_size', type=int, default=100,
    18. help="Max threshold of the original file size to split into archive. I.e. files with sizes below this arg are ignored.")
    19. parser.add_argument('--threshold_size_unit', type=str, default='m', choices=['b', 'k', 'm', 'g'],
    20. help="Unit of the threshold size specified (bytes, kilobytes, megabytes, gigabytes).")
    21. parser.add_argument('--partition_size', type=int, default=95,
    22. help="Max size of an individual archive. May result in actual partition size to be higher than this value due to disk formatting. In that case, reduce this arg value.")
    23. parser.add_argument('--partition_size_unit', type=str, default='m', choices=['b', 'k', 'm', 'g'],
    24. help="Unit of the partition size specified (bytes, kilobytes, megabytes, gigabytes).")
    25. args = parser.parse_args()
    26. return args
    27. def check_7z_install():
    28. # 检查是否安装了7z,如果没有安装则退出程序
    29. if shutil.which("7z"):
    30. return True
    31. else:
    32. sys.exit("ABORTED. You do not have 7z properly installed at this time. Make sure it is added to PATH.")
    33. def is_over_threshold(f_full_dir, args):
    34. # 判断文件是否超过阈值大小
    35. size_dict = {
    36. "b": 1e-0,
    37. "k": 1e-3,
    38. "m": 1e-6,
    39. "g": 1e-9
    40. }
    41. return os.stat(f_full_dir).st_size * size_dict[args.threshold_size_unit] >= args.threshold_size
    42. def traverse_root_dir(args):
    43. # 遍历指定目录下的文件,并进行压缩
    44. for root, _, files in os.walk(args.root_dir):
    45. for f in files:
    46. f_full_dir = os.path.join(root, f)
    47. if is_over_threshold(f_full_dir, args):
    48. f_full_dir_noext, ext = os.path.splitext(f_full_dir)
    49. # 使用7z命令进行压缩
    50. prc = subprocess.run(["7z", "-v" + str(args.partition_size) + args.partition_size_unit, args.cmds_into_7z,
    51. f_full_dir_noext + "." + ext[1:] + "." + args.partition_ext, f_full_dir])
    52. if args.delete_original and prc.returncode == 0:
    53. os.remove(f_full_dir)
    54. if __name__ == '__main__':
    55. check_7z_install() # 检查是否安装了7z
    56. traverse_root_dir(parse_arguments()) # 压缩文件

    这段代码会从root_dir开始遍历所有子目录,并将所有超过100MB的文件压缩为最大大小约为95MB的较小存档文件。默认选项是在压缩后删除原始(大)文件,但可以关闭此选项。

    执行记录

    1. D:\tmp\git_di>python main.py --root_dir "D:\tmp\git_di"
    2. 7-Zip 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
    3. Scanning the drive:
    4. 1 file, 3329165073 bytes (3175 MiB)
    5. Creating archive: D:\tmp\git_di\testfile.zip.7z
    6. Add new data to archive: 1 file, 3329165073 bytes (3175 MiB)
    7. Files read from disk: 1
    8. Archive size: 3304152719 bytes (3152 MiB)
    9. Volumes: 34
    10. Everything is Ok

    可以当前目录下生成了多个压缩包分块(testfile.zip.7z.001, testfile.zip.7z.002 ......)

    4.恢复

    用于恢复大文件的代码reverse.py 如下:

    1. import sys # 导入sys模块,用于退出程序
    2. import os # 导入os模块,用于文件和目录操作
    3. import shutil # 导入shutil模块,用于文件操作
    4. import subprocess # 导入subprocess模块,用于执行shell命令
    5. import argparse # 导入argparse模块,用于解析命令行参数
    6. def parse_arguments():
    7. # 解析命令行参数
    8. parser = argparse.ArgumentParser(description='GitHub-ForceLargeFiles_reverse')
    9. parser.add_argument('--root_dir', type=str, default=os.getcwd(),
    10. help="Root directory to start traversing. Defaults to current working directory.")
    11. parser.add_argument('--delete_partitions', type=bool, default=True,
    12. help="Do you want to delete the partition archives after extracting the original files?")
    13. args = parser.parse_args()
    14. return args
    15. def check_7z_install():
    16. # 检查是否安装了7z,如果没有安装则退出程序
    17. if shutil.which("7z"):
    18. return True
    19. else:
    20. sys.exit("ABORTED. You do not have 7z properly installed at this time. Make sure it is added to PATH.")
    21. def is_partition(f_full_dir):
    22. # 判断文件是否是分卷文件
    23. return any(f_full_dir.endswith(ext) for ext in
    24. [".7z.001", ".xz.001", ".bzip2.001", ".gzip.001", ".tar.001", ".zip.001", ".wim.001"])
    25. def reverse_root_dir(args):
    26. # 遍历指定目录下的文件,并进行解压
    27. for root, _, files in os.walk(args.root_dir):
    28. for f in files:
    29. f_full_dir = os.path.join(root, f)
    30. if is_partition(f_full_dir):
    31. # 使用7z解压文件
    32. prc = subprocess.run(["7z", "e", f_full_dir, "-o" + root])
    33. if args.delete_partitions and prc.returncode == 0:
    34. f_noext, _ = os.path.splitext(f)
    35. os.chdir(root)
    36. os.system("rm" + " \"" + f_noext + "\"*")
    37. if __name__ == '__main__':
    38. check_7z_install() # 检查是否安装了7z
    39. reverse_root_dir(parse_arguments()) # 解压分卷文件

    测试

    将压缩包分块(testfile.zip.7z.001, testfile.zip.7z.002 ......)放置与目录 D:\tmp\git_di 下,reverse.py 也放在同级目录下。

    执行记录

    1. D:\tmp\git_di>python reverse.py --root_dir "D:\tmp\git_di"
    2. 7-Zip 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
    3. Scanning the drive for archives:
    4. 1 file, 99614720 bytes (95 MiB)
    5. Extracting archive: D:\tmp\git_di\testfile.zip.7z.001
    6. --
    7. Path = D:\tmp\git_di\testfile.zip.7z.001
    8. Type = Split
    9. Physical Size = 99614720
    10. Volumes = 34
    11. Total Physical Size = 3304152719
    12. ----
    13. Path = testfile.zip.7z
    14. Size = 3304152719
    15. --
    16. Path = testfile.zip.7z
    17. Type = 7z
    18. Physical Size = 3304152719
    19. Headers Size = 162
    20. Method = LZMA2:24
    21. Solid = -
    22. Blocks = 1
    23. Everything is Ok
    24. Size: 3329165073
    25. Compressed: 3304152719
    26. 'rm' 不是内部或外部命令,也不是可运行的程序
    27. 或批处理文件。

    可以看到新生成了文件 testfile.zip。

    5.最后

    参考github链接

    https://github.com/sisl/GitHub-ForceLargeFiles

    over.

  • 相关阅读:
    mybatis-plus 统一管理创建时间、更新时间、创建人与更新人
    Spring依赖注入之@autowire注解详解
    python调用接口脚本
    Python魔法方法
    探索 Redis 与 MySQL 的双写问题
    SpringAMQP
    Unity UI制作
    利用C++开发一个迷你的英文单词录入和测试小程序-升级版本
    啤酒和烧烤
    docker安装rabbitmq和redis详解
  • 原文地址:https://blog.csdn.net/qq_33163046/article/details/132918242