Carry の Blog Carry の Blog
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carry の Blog

好记性不如烂键盘
首页
  • Nginx
  • Prometheus
  • Iptables
  • Systemd
  • Firewalld
  • Docker
  • Sshd
  • DBA工作笔记
  • MySQL
  • Redis
  • TiDB
  • Elasticsearch
  • OpenClaw
  • Hermes Agent
  • Claude Code
  • MySQL8-SOP手册
  • MySQL实战45讲学习笔记
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • MySQL

    • MySQL 运维知识地图:从入门配置到高可用排障
    • MySQL8 配置文件 my.cnf 重要参数解读
    • MySQL 导出 CSV 中文乱码:字符集链路从头讲一遍
      • 1. 为什么导出的 CSV 会乱码
      • 2. 导出 CSV 的两种方式
      • 3. 解决中文乱码的两个关键点
      • 4. 坑
      • 5. 可复用要点
    • MySQL 角色管理
    • MySQL网络抓包审计
    • MySQL 性能压测:Sysbench 1.0 实战
    • MySQL Router 实现读写分离
    • Gh-ost重建表,清除表碎片率
    • MySQL MGR配合MySQL-router实现innodb-cluster
    • MySQL 快速分析binlog定位问题
    • MySQL执行计划分析
    • DBA常用SQL和命令整理备查
    • 单表数据同步方案选型:为什么不该用 mysqldump 做「实时同步」
    • MySQL的事务隔离级别
    • MySQL存储过程批量生成数据
    • MySQL insert on duplicate key update,replace into , insert ignore的理解
    • MySQL不同字符集之间的区别和选择
    • MySQL为什么有时候会选错索引
    • MySQL死锁问题
    • MySQL使用SQL语句查重去重
    • MySQLdump逻辑备份
    • MySQL 基于 GTID 主从复制:跳过异常事务的正确姿势
    • MySQL8快速克隆插件使用指南
    • MySQL8双1设置保障安全
    • MySQL锁
    • innodb cluster安装
    • OPTIMIZE TABLE 和 ANALYZE TABLE 的区别:用实测数据说话
    • MySQLReplicaSet 安装
    • 脚本实现MySQL ReplicaSet 高可用
    • MySQL 的 Left join、Right join 和 Inner join 的区别
  • Redis

  • Keydb

  • TiDB

  • MongoDB

  • Elasticsearch

  • Kafka

  • victoriametrics

  • BigData

  • Sqlserver

  • 数据库
  • MySQL
Carry の Blog
2022-03-10
目录

MySQL 导出 CSV 中文乱码:字符集链路从头讲一遍原创

版本说明

本文基于 MySQL 8.0 验证,SELECT ... INTO OUTFILE 和 secure_file_priv 机制自 5.x 起长期稳定,命令通用。

# 1. 为什么导出的 CSV 会乱码

MySQL 导出 CSV 中文乱码,本质是字符集在导出链路的某个环节被错误转换,而不是数据本身坏了。一次导出要经过"数据库存储字符集 → 客户端连接字符集 → 导出文件编码 → 打开文件的软件(Excel 等)默认编码"这条链路,任何一环不匹配都会花屏。定位思路应该是先确认数据在数据库里到底是不是正常的,再逐环检查导出路径,最后才是"文件本身没问题,但打开它的软件猜错了编码"这种情况。

# 2. 导出 CSV 的两种方式

方式一:mysql 命令行 + sed 拼接(适合快速导小表)

mysql -u root -p -e "select * from wordpress.wp_users" | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > /tmp/wp_users.csv
1

mysql -e 默认输出是以 \t(制表符)分隔字段的纯文本,本身并不是标准 CSV 格式,这条 sed 的作用是把制表符替换成 ",",再给每行首尾加上引号,拼成"看起来像"标准 CSV 的格式。这种方式的局限:如果字段内容本身就包含逗号、引号或换行符,简单的字符串替换无法正确转义,会把 CSV 结构搞乱——只适合字段内容干净、临时导个小表的场景。

方式二:SELECT ... INTO OUTFILE(推荐,MySQL 原生支持转义)

SELECT * INTO OUTFILE '/data/db/mysql3306/filedir/a.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM wordpress.wp_users;
1
2
3
4
5

OPTIONALLY ENCLOSED BY '"' 表示只有需要转义的字段(含逗号、引号、换行等特殊字符)才会被引号包裹,比 sed 拼接更符合标准 CSV 规范。这个方式受 secure_file_priv 参数限制,导出路径必须落在这个参数指定的目录内:

[mysqld]
secure_file_priv = /data/db/mysql3306/filedir
1
2

为什么会有这个限制:INTO OUTFILE 是由 mysqld 进程本身在服务端写文件,如果不限制目录,恶意用户理论上可以通过这条语句往服务器任意路径写文件(比如覆盖系统文件),secure_file_priv 就是为了收窄这个攻击面。如果没设置该参数,默认导出目录通常是 /var/lib/mysql-files/(或未设置则整个功能被禁用),可以按需改成 /tmp/ 或其他专用目录,但生产环境不建议设为空(允许任意路径)。

# 3. 解决中文乱码的两个关键点

第一,确认导出时的字符集:如果表本身用的是 utf8mb4,但客户端连接字符集是 latin1 或其他不匹配的编码,导出过程中就会发生一次隐式的字符集转换,直接导致乱码。用命令行导出前确认连接字符集:

mysql -u root -p --default-character-set=utf8mb4 -e "select * from wordpress.wp_users" > /tmp/wp_users.csv
1

第二,给 CSV 文件加 UTF-8 BOM 头:即使字符集链路本身没问题,Excel(尤其是 Windows 版)在没有 BOM(Byte Order Mark)标记的情况下,打开 UTF-8 编码的 CSV 文件时经常会按本地默认编码(GBK 等)猜测,导致中文显示成乱码——这不是文件坏了,是 Excel 猜错了编码。给文件开头插入 UTF-8 BOM(EF BB BF 三个字节)可以让 Excel 正确识别:

sed -i '1s/^/\xEF\xBB\xBF/' /tmp/wp_users.csv
1

验证:用 file 命令确认文件已带 BOM:

file /tmp/wp_users.csv
# 输出应包含: UTF-8 Unicode (with BOM) text
1
2

再用 Excel 或 vim(:set bomb 后看开头)打开确认中文正常显示。

# 4. 坑

  • BOM 头是 Excel 这类 Windows 软件的"习惯性猜测"问题,如果 CSV 是给 Python pandas/csv 模块这类程序化读取,加 BOM 反而可能导致读取时首列字段名前多出一个不可见字符(),程序化消费场景通常不需要加 BOM,按目标消费方决定要不要加。
  • SELECT INTO OUTFILE 导出的文件属主是 mysqld 运行用户(通常是 mysql),如果需要用其他用户读取/传输,注意后续权限调整。
  • secure_file_priv 一旦在配置文件里设定,只能通过重启 MySQL 实例修改,不支持运行时动态调整(SET GLOBAL 不生效),规划导出目录时提前想清楚。

# 5. 可复用要点

  1. 乱码排查按链路分层:数据库存储字符集 → 连接字符集 → 文件编码 → 打开软件的编码猜测,逐环确认而不是瞎试。
  2. 生产环境批量导出优先用 SELECT INTO OUTFILE,字段转义更规范;命令行 sed 拼接只适合字段干净的小表快速导出。
  3. 加 UTF-8 BOM 是"取悦 Excel"的手段,程序化读取场景要按消费方需求决定是否需要。
#MySQL
上次更新: 7/29/2026

← MySQL8 配置文件 my.cnf 重要参数解读 MySQL 角色管理→

最近更新
01
Nginx 运维知识地图:从配置基础到反向代理实战 原创
07-29
02
MySQL 运维知识地图:从入门配置到高可用排障 原创
07-29
03
单表数据同步方案选型:为什么不该用 mysqldump 做「实时同步」 原创
07-29
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式