文件与目录

下方课件区域方向键控制翻页,f 键全屏。

示例 1

用标准库 struct 解包一个 24 bits 无调色板的 BMP 文件头。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import struct

# 使用 r 读取 b 二进制 模式打开文件
with open('test.bmp', 'rb') as f:
    # 读取 14 字节的文件头
    bmp_file_header = f.read(14)

    # BMP 文件头
    # bm 对应 2 字节的标志'BM'
    # size 对应 4 字节无符号整型表示文件大小
    # r1 r2 对应 2 个宽度为 2 字节的保留位置
    # offset 对应 4 字节无符号整型表示图像数据的起始偏移
    bm, size, r1, r2, offset = struct.unpack('<2sIHHI', bmp_file_header)

    print(bm, size, offset)

    # 读取 40 字节的文件头
    bmp_info_header = f.read(40)

    # 不定长的信息头,一般为 40 字节
    # info_size 对应 4 字节无符号整型表示信息头大小
    # width 对应 4 字节有符号整型表示图像宽度
    # height 对应 4 字节有符号整型表示图像高度
    # planes 对应 2 字节无符号整型表示色彩层数,一般值为 1
    # bits 对应 2 字节无符号整型表示位深度,即用多少比特表示颜色
    # compression 对应 4 字节无符号整型表示压缩方式
    # data_size 对应 4 字节无符号整型表示图像数据大小 = width * height * bits
    # x_res 对应 4 字节有符号整型表示横向(x轴)分辨率(多少像素每米)
    # y_res 对应 4 字节有符号整型表示纵向(y轴)分辨率(多少像素每米)
    # clr_used 对应 4 字节无符号整型表示调色板颜色数量
    # clr_important 对应 4 字节无符号整型表示调色板重要颜色数量
    info_size, width, height, planes, bits, compression, data_size, x_res, y_res, clr_used, clr_important = struct.unpack(
        '<IiiHHIIiiII', bmp_info_header)

    print(compression, info_size, width, height, bits, data_size, clr_used)

示例 2

将某个目录中的文件(包括子目录下的文件)按照由大到小的顺序移动到一个新的目录,并且加上数字前缀。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import os


# 通过递归调用 os.listdir() 来实现目录遍历,得到一个包含所有文件的列表
def walk_dir(path):
    result = []

    for filename in os.listdir(path):
        file_path = os.path.join(path, filename)

        if os.path.isdir(file_path):
            result += walk_dir(file_path)

        if os.path.isfile(file_path):
            result.append(file_path)

    return result


root = input('请输入你要遍历的目录: ')

# 遍历用户指定的目录
files = walk_dir(root)

# 按文件大小由大到小命名的新目录
output_dir = input('请输入你要新建的目录: ')

# 新目录不存在时自动创建这个目录
if not os.path.exists(output_dir):
    os.mkdir(output_dir)

# 使用 os.stat() 获取文件大小
file_dict = {}
for file in files:
    st = os.stat(file)
    file_dict[file] = st.st_size

# 用 数据类型进阶 一节学过的方法排序
sorted_files = {
    k: v
    for k, v in sorted(file_dict.items(), key=lambda x: x[1], reverse=True)
}

# 按照由大到小的顺序,给文件名前面加上数字前缀并移动到新的目录
filename = 1
for file in sorted_files.keys():
    # 获取文件名的部分(不包括前面的路径)
    basename = os.path.basename(file)
    # 将文件名拆分成名字和后缀
    name, ext = os.path.splitext(basename)

    # 组合新的目录和新文件名
    new_basename = str(filename) + '_' + name + ext
    newfilename = os.path.join(output_dir, new_basename)

    # 调用 os.rename() 实现移动文件的效果
    os.rename(file, newfilename)

    filename += 1

另一种遍历目录的方法。

1
2
3
4
5
6
7
8
9
def walk_dir(path):
    result = []

    for root, dirs, files in os.walk(path):
        for file in files:
            filename = os.path.join(root, file)
            result.append(filename)

    return result

示例 3

上面的例子如果使用 pathlib 来实现,则为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pathlib import Path

root = input('请输入你要遍历的目录: ')

# 遍历用户指定的目录,如果想偷懒,可以用 Path.rglob('*')
# Path.rglob('*') 相当于自动给参数加上 '**/' 的 glob
files = Path(root).glob('**/*')

# 按文件大小由大到小命名的新目录
output_dir = input('请输入你要新建的目录: ')

Path(output_dir).mkdir(exist_ok=True)

# 使用 Path.stat() 获取文件大小
file_dict = {}
for file in files:
    if Path(file).is_file():
        st = Path(file).stat()
        file_dict[file] = st.st_size

# 用 数据类型进阶 一节学过的方法排序
sorted_files = {
    k: v
    for k, v in sorted(file_dict.items(), key=lambda x: x[1], reverse=True)
}

# 按照由大到小的顺序,给文件名前面加上数字前缀并移动到新的目录
filename = 1
for file in sorted_files.keys():
    old_file = Path(file)

    # 组合新的目录和新文件名
    new_basename = str(filename) + '_' + old_file.stem + old_file.suffix
    newfilename = Path(output_dir) / Path(new_basename)

    # 调用 Path.rename() 实现移动文件的效果
    old_file.rename(newfilename)

    filename += 1

作业-猫鼠游戏

详细要求参考作业仓库的 README.md 。