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

相关推荐
YOU OU1 小时前
Redis基础常识与命令
数据库·redis·缓存
Scott9999HH2 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
二十雨辰3 小时前
[爬虫]-Urllib
爬虫·python
Database_Cool_4 小时前
OLTP 和 OLAP 区别详解:分析型数据库和事务型数据库怎么选(附阿里云 AnalyticDB MySQL 选型指南)
数据库·mysql·阿里云
爱写代码的阿森4 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_4 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
玉鸯5 小时前
Agent Hook:在概率推理之上,为 Agent 叠加确定性控制
python·langchain·agent
姜太小白5 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql