hzfile 0.1.0
一个用于学习的模块，用于自定义的'.hz'格式文件的生成和读取。
License: MIT License
Requires Python: >=3.5
Keywords: hz,.hz,hz file

# hzfile

这是一个练习二进制读写时写的模块，比较简易。

### 功能

1. 把一个目录下诸多文件打包合并成一个<.hz>文件，无加密，无压缩。

2. 把<.hz>文件内打包合并的文件原样提取出来，但不包含目录结构，可以全部提取，也可以按文件名提取。

### 思路

1. 先设计一个<.hz>文件的格式规范，尽可能地把打包提取时会遇到的问题考虑进去。
2. 编写代码，按设计的规范使用二进制方式读写<.hz>文件，借助<struct>模块对整数和二进制字节码进行转换操作。

### 格式规范

|                      |       储存的数据       |             储存的数据             | 储存单元的类型  | 储存单元的数量 |   总占用字节数   |
| :------------------: | :--------------------: | :--------------------------------: | :-------------: | :------------: | :--------------: |
|   **文件头部信息**   |      文件格式标识      |                                    |  unsigned char  |       16       |        16        |
|                      |     类型空间占用表     | 四个类型的空间占用大小(B, H, I, Q) |  unsigned char  |       4        |        4         |
|                      |      格式版本信息      |                                    | unsigned short  |       4        |      H * 4       |
|                      |      预留空白字节      |                                    |       NA        |       NA       |       255        |
|                      |    被合并的文件总数    |                                    |  unsigned int   |       1        |      I * 1       |
| **被合并的单个文件** |        文件大小        |                                    |  unsigned int   |       1        |      I * 1       |
|                      |       文件名长度       |                                    |  unsigned int   |       1        |      I * 1       |
|                      | 文件名字节串(包含'\0') |                                    | unsigned char * |       1        | <文件名长度>的值 |
|          …           |                        |                                    |                 |                |                  |
| **被合并的文件数据** |   被合并的文件字节码   |                                    |                 |                |                  |
|          …           |                        |                                    |                 |                |                  |

### 代码思路

1. <hzfile>模块中包含一个类<class HzFile>，类实例化时需要一个文件路径参数，当文件存在时，读取文件头部信息保存到类属性中。当文件不存在时，用默认的文件头部信息创建一个<.hz>文件。
2. 当读取一个已存在的<.hz>文件时，不可对文件进行写操作(比如用<merge>方法打包新的文件)，只能对其进行读操作(比如用<extractall>方法提取所有文件)。
3. 当创建一个不存在的<.hz>文件时，可以进行写操作(比如用<merge>方法打包新的文件)，写操作后，只可进行读操作，不再允许写操作。
4. 限制写操作是因为设计格式规范时没考虑好(踩到的第一个坑)，导致每次新的写操作都要对<.hz>文件全部读写一遍，浪费性能。

### 模块使用

1. 安装模块，win平台：`py -m pip install -U hzfile`
2. 编写使用代码

```python
# coding: utf-8

from hzfile import HzFile

hzf = HzFile(r"./myfile.hz")
# r"./myfile.hz" 指向一个不存在的文件
# 后缀名是什么无关紧要，读取时是以文件头的文件格式标识判断格式是否正确的

hzf.merge(r"./pictures", recursion=False, bigok=False)
# 参数1是一个目录路径，表示将该路径下的所有文件打包进myfile.hz文件
# 参数recursion表示是否递归搜索参数1目录下的子目录
# 参数bigok表示在当参数1下的文件大于4G时是否直接跳过，True表示直接跳过，False表示抛出Exception异常。
# 因为格式规范设计之初考虑性能问题，仅用一个unsigned int保存文件的大小信息(字节)，也就是能表示大约4G大小。

print(hzf.fbom())
# 打印<myfile.hz>文件内所包含的文件的信息。
# 返回值格式为[(文件大小, 文件名字节串含'\0'长度， 文件名字符串), ...]

print(hzf.fcnt())
# 打印<myfile.hz>文件内包含的文件数量

print(hzf.fver())
# 打印<myfile.hz>创建时使用的格式规范版本，是[a,b,c,d]形式，abcd均>=0, <=255。

print(hzf.ftypesize())
# 接受5个值：B, H, I, Q, None
# 返回<myfile.hz>创建时使用的各类型数据的占用空间大小

hzf.extract(["a.txt", "b.jpg", "c.mp4"],  dirpath=r"./files1", overwrite=False)
# 按文件名提取文件
# 第一个参数是要提取的文件名列表
# 第二个参数dirpath是一个目录路径，可以是已存在或不存在的路径，提取出的文件将被保存到这个目录
# 第三个参数overwrite是是否覆盖同名文件，这个参数仅针对提取文件前dirpath中已存在的文件
# 对于<myfile.hz>中的同名文件，提取时会以<xxx_1.x>的形式重命名文件，不会被覆盖
# 打包时的文件目录结构不会被打包，也就是说，无论打包多少层的目录内的文件，提取时都只会以一层目录(dirpath)保存

hzf.extractall(dirpath=r"./files2", overwrite=False)
# 提取所有文件，参数同<extract>方法的最后两个参数

```