使用os.walk扫描文件夹增量更新sqlite3保留自定义数据及修复父节点bug
解决方案
1. C盘根目录父节点异常Bug修复
Bug根本原因
路径匹配逻辑不一致:
- 你存储到
folder_list的根目录路径是带尾部反斜杠的C:\\ - 匹配父节点时你对父路径做了
rstrip("\\")处理,变成了C:,和存储的C:\\无法匹配,导致匹配失败,父节点赋值异常 - 额外问题:你用字符串类型的node作为
folder_list的key,且每次遍历folder_list匹配父节点的效率极低,扫描大目录时卡顿严重
修复方案
- 统一路径格式:所有路径统一不带尾部反斜杠存储和匹配
- 重构
folder_list为路径到node的直接映射,匹配父节点O(1)完成,无需遍历 - 根目录单独处理,明确指定父节点为0,避免匹配异常
2. 增量更新保留自定义字段实现
实现逻辑
- 删掉
DROP TABLE IF EXISTS Windows10语句,不再每次重建表销毁原有数据 - 插入记录前先判断该路径是否已存在于数据库,仅插入不存在的新文件/文件夹记录,原有记录完全保留,自然不会覆盖你手动填写的
Beginner Info等自定义字段 - 程序启动时先从数据库读取已有路径和node的映射,同时读取当前最大node值,后续新记录从该值开始递增,避免node重复
3. 其他优化建议
- 增加权限异常捕获:扫描C盘时很多系统目录无访问权限,增加异常捕获避免程序中途崩溃
- 用
os.path模块处理路径拼接、拆分,避免手动处理反斜杠的格式错误 - 取消冗余的打印语句,扫描大目录时打印会严重拖慢速度
- 可增加文件修改时间校验,后续可以识别已修改的文件做更新(如果需要的话)
修复后完整代码
import os import sqlite3 def init_db(): conn = sqlite3.connect('Win10.db') # 仅当表不存在时创建,不会破坏原有数据 conn.execute('''CREATE TABLE IF NOT EXISTS Windows10 ("Node" INTEGER NOT NULL, "Filename" TEXT, "Path" TEXT NOT NULL UNIQUE, "Beginner Info" TEXT DEFAULT 'Info', "Intermediate Info" TEXT DEFAULT 'Info', "Advanced Info" TEXT DEFAULT 'Info', "Tags" TEXT DEFAULT 'separated by whitespace tags', "Parent" INTEGER NOT NULL, "isFolder" INTEGER DEFAULT NULL, "fileExt" TEXT DEFAULT NULL, PRIMARY KEY("Node") )''') # 读取已有路径和node的映射,以及当前最大node值 path_node_map = {} cursor = conn.execute("SELECT Path, Node FROM Windows10") for row in cursor: path_node_map[row[0]] = row[1] max_node = conn.execute("SELECT IFNULL(MAX(Node), 0) FROM Windows10").fetchone()[0] conn.commit() return conn, path_node_map, max_node def scan_and_sync(root_path="C:\\"): conn, path_node_map, current_node = init_db() print("数据库初始化完成,当前最大Node值:", current_node) root_path = os.path.normpath(root_path) # 先处理根目录 if root_path not in path_node_map: current_node += 1 root_filename = os.path.basename(root_path) + "\\" conn.execute('''INSERT INTO Windows10 (Filename, Path, Parent, fileExt, isFolder) VALUES (?, ?, ?, ?, ?)''', (root_filename, root_path, 0, "", 1)) path_node_map[root_path] = current_node print("已添加根目录:", root_path) # 遍历目录树 for dirpath, dirnames, filenames in os.walk(root_path): dirpath = os.path.normpath(dirpath) # 跳过已存在的目录 if dirpath not in path_node_map: # 找父目录node parent_path = os.path.dirname(dirpath) parent_node = path_node_map.get(parent_path, 0) current_node +=1 dir_filename = os.path.basename(dirpath) + "\\" try: conn.execute('''INSERT INTO Windows10 (Filename, Path, Parent, fileExt, isFolder) VALUES (?, ?, ?, ?, ?)''', (dir_filename, dirpath, parent_node, "", 1)) path_node_map[dirpath] = current_node except sqlite3.IntegrityError: # 并发插入冲突,跳过 continue # 处理当前目录下的文件 parent_node = path_node_map[dirpath] for filename in filenames: file_path = os.path.normpath(os.path.join(dirpath, filename)) if file_path in path_node_map: continue # 获取后缀 file_ext = os.path.splitext(filename)[1].lstrip(".") current_node +=1 try: conn.execute('''INSERT INTO Windows10 (Filename, Path, Parent, fileExt, isFolder) VALUES (?, ?, ?, ?, ?)''', (filename, file_path, parent_node, file_ext, 0)) path_node_map[file_path] = current_node except sqlite3.IntegrityError: continue conn.commit() print("同步完成") conn.close() if __name__ == "__main__": # 可以修改扫描路径,比如扫描D盘就传"D:\\" scan_and_sync("C:\\")
内容的提问来源于stack exchange,提问作者user16505976
相关产品推荐
相关产品推荐

