现有涉及图片保存的系统中,图片通常存储在服务器文件系统,路径写在数据库里。
例如:
- 表 A 存图片路径
i.location - 表 B 存业务区县
q.qx - 业务需求:按区县把图片重新整理分目录
本文分享一个生产级 Python 脚本,可处理上万文件,支持断点续拷贝、去重、错误耐受。
环境准备
bash
yum install postgresql-devel gcc python3-devel -y
pip3 install psycopg2-binary
脚本完整代码(含注释解读)
python
import os
import psycopg2
import shutil
import sys
# PostgreSQL数据库配置
db_config = {
'host': '123.',
'user': '',
'password': '*?.',
'database': '',
'port': 5432
}
# 图片导出根目录
EXPORT_DIR = '/project/WYApp/photo_export'
def main():
# 用于记录已处理过的 path(用于扩展断点续传)
processed_paths = set()
try:
# 1. 建立数据库连接
connection = psycopg2.connect(**db_config)
cursor = connection.cursor()
# 2. SQL:使用 JOIN + DISTINCT 避免重复
query = """
SELECT DISTINCT i.location, q.qx
FROM wyfwimg i
INNER JOIN sde.jwbld_wy q ON i.fwid = q.uuid
WHERE q.qx IS NOT NULL AND i.location IS NOT NULL AND q.qx = '密云区'
ORDER BY q.qx, i.location
"""
cursor.execute(query)
results = cursor.fetchall()
print(f"去重后找到 {len(results)} 条图片记录")
# 用于统计
success_count = fail_count = skip_count = 0
# 3. 遍历每条记录
for location, qx in results:
try:
# ------区县字段清洗:过滤非法字符,避免目录报错
safe_qx = "".join(c for c in str(qx) if c.isalnum() or c in (' ', '-', '_')).rstrip()
# ------获取文件名
filename = os.path.basename(location)
# ------源文件路径
source_file = location
# 4. 源文件是否存在?(防止数据库脏数据)
if not os.path.exists(source_file):
fail_count += 1
print(f"✗ 源文件不存在: {source_file}")
continue
# ------目标目录 = 导出根目录 + 区县目录
target_dir = os.path.join(EXPORT_DIR, safe_qx)
os.makedirs(target_dir, exist_ok=True)
target_file = os.path.join(target_dir, filename)
# 5. 断点续拷贝:如果文件已存在则跳过
if os.path.exists(target_file):
skip_count += 1
print(f"⏭️ 已存在: {safe_qx}/{filename}")
continue
# 6. 复制文件(保留元信息:时间、权限等)
shutil.copy2(source_file, target_file)
success_count += 1
print(f"✅ 成功: {safe_qx}/{filename}")
except Exception as e:
fail_count += 1
print(f"❌ 处理失败: {location}, 错误: {e}")
print("\n===== 导出完成 =====")
print(f"✅ 成功复制: {success_count}")
print(f"⏭️ 跳过已有: {skip_count}")
print(f"❌ 失败: {fail_count}")
except Exception as e:
print(f"🚨 数据库连接失败: {e}")
sys.exit(1)
finally:
# ------确保资源释放
if 'connection' in locals():
cursor.close()
connection.close()
if __name__ == "__main__":
main()
代码关键功能说明 ✅
| Python 功能 | 描述 |
|---|---|
psycopg2.connect() |
连接 PostgreSQL 数据库 |
SQL DISTINCT + JOIN |
避免重复图片路径 |
字符串过滤 .isalnum() |
目录命名安全处理 |
os.path.exists() |
判断文件存在(防脏数据) |
os.makedirs(..., exist_ok=True) |
自动创建分类目录 |
shutil.copy2() |
完整复制文件,保留时间属性 |
| 断点续拷贝逻辑 | 文件存在自动跳过,支持长任务恢复 |
| 异常捕获 | 单张失败不影响整体执行 |
| 最终统计输出 | 一目了然执行效果 |
推荐运行方式(生产)
后台运行并保存日志:
bash
nohup python3 export_photos.py > export.log 2>&1 &
tail -f export.log
压缩导出目录:
bash
tar -czvf photo_export.tar.gz photo_export > /tmp/tar.txt 2>&1 &
tail -f /tmp/tar.txt
或者快速打包
bash
tar -cf shijingshan_photos.tar photo_export/
下载文件:
bash
scp user@ip:/project/WYApp/photo_export.tar.gz ./