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

相关推荐
codists1 小时前
2025年11月文章一览
python
生而为虫1 小时前
31.Python语言进阶
python·scrapy·django·flask·fastapi·pygame·tornado
i***11861 小时前
Django视图与URLs路由详解
数据库·django·sqlite
言之。1 小时前
Claude Code 实用开发手册
python
计算机毕设小月哥1 小时前
【Hadoop+Spark+python毕设】中国租房信息可视化分析系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
2***c4351 小时前
Redis——使用 python 操作 redis 之从 hmse 迁移到 hset
数据库·redis·python
2***d8851 小时前
redis的启动方式
数据库·redis·bootstrap
j***57682 小时前
【MySQL】mysqldump使用方法
数据库·mysql·oracle
企鹅侠客2 小时前
Linux性能调优 详解磁盘工作流程及性能指标
linux·运维·服务器·性能调优