欢迎光临
我们一直在努力

mysqldump导出中文乱码

以前做项目时遇到的,分享一下个人经验

命令

mysqldump -u root -p {DATABASE_NAME} > db.sql

终端

powershell 5.1

问题

中文出现乱码,如正确版本为:

`gender` enum('男','女') NOT NULL,

乱码:

`gender` enum('鐢?,'濂?) NOT NULL,

导入错误原因分析

mysqldump输出UTF-8字节流(utf8mb4,由数据库配置决定),但总之不输出也无法输入UTF-16。

powershell的重定向操作默认使用UTF-16,可通过Format-Hex命令检查。不论是否能看到乱码,用这种方式导入都大概率报错。参见 charset-connection、mysqldump。

对于ASCII字符,以【S】为例,UTF-8的字符【S】被编码为53,UTF-16的字符【S】则会被编码为53 00,mysql导入时会认为这是53和00即【S】 【nul】而抛出:

ASCII '\\0' appeared in the statement, but this is not allowed unless option –binary-mode is enabled and mysql is run in non-interactive mode. Set –binary-mode to 1 if ASCII '\\0' is expected. Query: '?-'.

解决方案

  • mysqldump -u root -p {DATABASE_NAME} –result-file=db.sql(官方推荐做法)
  • 用cmd.exe而非powershell导出sql文件
  • 将powershell重定向修改为输出UTF-8(不推荐)
  • 乱码原因分析

    事实上,【'鐢?】并非【'男'】从UTF-8强行转换到UTF-16的结果,官方文档中的UTF-16仅解释了导入失败的原因,而没有解释乱码的原因。

    首先检查相关字段的编码值,python脚本如下:

    ch = ""

    for enc in [
    "utf-8",
    "utf-16le",
    "utf-16be",
    "utf-16",
    "gb2312",
    "gbk",
    ]:
    try:
    b = ch.encode(enc)
    print(enc, b.hex(" "))
    except:
    pass

    输出:


    utf-8 e7 94 b7
    utf-16le 37 75
    utf-16be 75 37
    utf-16 ff fe 37 75
    gb2312 c4 d0
    gbk c4 d0


    utf-8 e9 90 a2
    utf-16le 22 94
    utf-16be 94 22
    utf-16 ff fe 22 94
    gbk e7 94


    utf-8 e5 a5 b3
    utf-16le 73 59
    utf-16be 59 73
    utf-16 ff fe 73 59
    gb2312 c5 ae
    gbk c5 ae


    utf-8 e6 bf 82
    utf-16le c2 6f
    utf-16be 6f c2
    utf-16 ff fe c2 6f
    gb2312 e5 a5
    gbk e5 a5

     通过Format-Hex命令检查输出sql文件的内容,为简化输出我们只保留【'鐢?,'濂?】的结果:

    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

    00000000 FF FE 27 00 22 94 3F 00 2C 00 27 00 C2 6F 3F 00 .þ'."”?.,.'.Âo?.
    00000010 0D 00 0A 00 ….

    结果确实如官方文档所说是UTF-16编码。【'鐢?,'濂?】中乱码对应的字节码分别为22 94 3F 00和C2 6F 3F 00,这对应的是【鐢】和【濂】的UTF-16 LE编码。这表明乱码并非→UTF-16这一步产生的,→UTF-16这个步骤忠实地将字符【鐢】的编码转换到UTF-16了。乱码发生在更早的步骤。

    注意到字符【男】【女】的UTF-8和字符【鐢】【濂】的GBK存在重叠子串,这表明操作过程中存在某个步骤将mysqldump的字节流以GBK编码输出。通过[Console]::OutputEncoding检查:

    BodyName : gb2312
    EncodingName : 简体中文(GB2312)
    HeaderName : gb2312
    WebName : gb2312
    WindowsCodePage : 936
    IsBrowserDisplay : True
    IsBrowserSave : True
    IsMailNewsDisplay : True
    IsMailNewsSave : True
    IsSingleByte : False
    EncoderFallback : System.Text.InternalEncoderBestFitFallback
    DecoderFallback : System.Text.InternalDecoderBestFitFallback
    IsReadOnly : False
    CodePage : 936

    Console.OutputEncoding用于获取或设置控制台用于写入输出的编码,默认代码页由系统区域设置确定,为936。当powershell接收来自mysqldump的字节流后,需要通过代码页将字节转换为unicode进行输出,这个过程中依赖代码页936,对原本UTF-8编码生成的字节流发生了错误转换。如果只是不想看到乱码,解决方法为:

    [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)

    即使如此,仍面临UTF-8→UTF-16的00解析问题,所以依然建议采用前述解决方案。

    总结

    解析流程:UTF-8→{codepage}→UTF-16。

    导入失败原因:UTF-8→UTF-16出现mysql不接受的字符。

    乱码原因:powershell 5.1默认配置下codepage为936,UTF-8→GBK输出错误。

    赞(0)
    未经允许不得转载:171主机测评 » mysqldump导出中文乱码
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址