Python + PostgreSQL 批量图片分发脚本:分类、去重、断点续拷贝

现有涉及图片保存的系统中,图片通常存储在服务器文件系统,路径写在数据库里。

例如:

  • 表 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 ./

相关推荐
进击的明明13 小时前
当AI开始“边想边干”:深入聊聊ReAct,以及如何用Python手搓一个简单Agent
python·面试·agent
这个DBA有点耶14 小时前
从症状到根因:数据库监控指标的分层方法与静态/动态阈值策略
数据库·mysql·代码规范
全栈弄潮儿14 小时前
Python实战第8期:函数
后端·python·编程语言
SelectDB14 小时前
时间旅行与快照能力速查:Doris 侧三条落地路径
大数据·数据库·数据分析
SelectDB15 小时前
云数仓成本结构拆解速查:五层计费 vs Doris / 托管形态
大数据·数据库·数据分析
SelectDB15 小时前
什么场景能承接与建议保留:Doris vs Snowflake 边界速查
大数据·数据库·数据分析
卷无止境16 小时前
暗流与破局:AI时代的代码安全审查工具全景指南
后端·python
这个DBA有点耶17 小时前
DELETE没删多少数据,表却越来越大——InnoDB删除空洞与页合并失效的根因
数据库·mysql·代码规范
对象存储与RustFS18 小时前
网盘限速逼你开会员?用 RustFS 自己搭一个不限速的“私人网盘
服务器·后端·docker