postgresql win11 下面导出的 sql 文件乱码问题 utf16 to gbk - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
sbmzhcn
V2EX    程序员

postgresql win11 下面导出的 sql 文件乱码问题 utf16 to gbk

  •  
  •   sbmzhcn 347 天前 2093 次点击
    这是一个创建于 347 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当时不太会用 postgresql 在 windows 下面的 powershell 直接导出为 sql 文件,没看里面的内容,最近需要恢复数据发现内容中中文全是乱码,英文是正常的。

    尝试了很多方法后,发现文件是 utf16 编码的Little-endian UTF-16 Unicode text, with very long lines, with CRLF line terminators

    使用下面的命令可以导出为 gbk 编码,部分中文可以还原,但还是有相当多的字符无法还原

    iconv -f UTF-16 -t GBK < export.sql > out.sql 

    涉及到相关问题的,只有这个文章有所说明 https://www.cnblogs.com/xyb930826/p/4657462.html

    尝试了其中 C 代码,仍然是有相同的问题,有些编码无法转换成功

    使用 python 重写了代码,实现后,仍然是部分中文无法解码成功

    def read_map(): map_value = {} try: with open("UnicodeToGBK.txt", "r") as f: for line in f: utf_str, gbk_str = line.strip().split() utf_id = int(utf_str, 16) gbk_id = int(gbk_str, 16) map_value[utf_id] = gbk_id except IOError: print("Error reading mapping file!") return None return map_value def convert_utf16_to_gbk1(input_file, output_file): map_value = read_map() if map_value is None: print("Convert Failed!") return try: with open(input_file, "rb") as f_in, open(output_file, "wb") as f_out: # 跳过 BOM bom = f_in.read(2) if bom != b'\xff\xfe': f_in.seek(0) while True: ch = f_in.read(1) cl = f_in.read(1) if not ch or not cl: break ch = ord(ch) cl = ord(cl) if ch > 0x7f and cl == 0x00: ch2 = ord(f_in.read(1)) cl2 = ord(f_in.read(1)) f_out.write(bytes([ch, ch2])) elif ch <= 0x7f and cl == 0x00: f_out.write(bytes([ch])) else: utf = cl * 256 + ch gbk = map_value.get(utf, 0) f_out.write(bytes([gbk // 256, gbk % 256])) except IOError: print("Error processing files!") return print("Conversion completed successfully!") def convert_utf16_to_gbk(input_file, output_file): map_value = read_map() if map_value is None: print("Convert Failed!") return try: with open(input_file, "rb") as f_in, open(output_file, "wb") as f_out: # 跳过 BOM bom = f_in.read(2) if bom != b'\xff\xfe': f_in.seek(0) while True: low_byte = f_in.read(1) high_byte = f_in.read(1) if not low_byte or not high_byte: break low_byte = ord(low_byte) high_byte = ord(high_byte) # 正确处理小端序 UTF-16 utf = (high_byte << 8) | low_byte if utf in map_value: gbk = map_value[utf] f_out.write(bytes([gbk // 256, gbk % 256])) elif utf <= 0x7f: # ASCII 字符 f_out.write(bytes([utf])) else: # 处理未映射的字符 print(f"Unable to convert UTF-16 character: U+{utf:04X}", chr(utf)) # hex_str = f"\\u{utf:04X}" # f_out.write(hex_str.encode('ascii')) # f_out.write(bytes.fromhex("E046E160")) # 或者选择其他替代字符 except IOError: print("Error processing files!") return print("Conversion completed successfully!") if __name__ == "__main__": convert_utf16_to_gbk("export.sql", "out.sql") 

    比如 UnicodeToGBK.txt 的对应关系如下

    90C5 DBA4 90C6 E042 90C7 DBA8 90C8 E043 90C9 E044 90CA BDBC 90CB E045 90CC E046 90CD E047 90CE C0C9 90CF DBA3 90D0 DBA6 90D1 D6A3 

    错误的字节

    Unable to convert UTF-16 character: U+E046 Unable to convert UTF-16 character: U+E160 Unable to convert UTF-16 character: U+E1E2 Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E0A5 Unable to convert UTF-16 character: U+E195 Unable to convert UTF-16 character: U+E218 Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E1EC Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E1BC Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E11E Unable to convert UTF-16 character: U+E1C0 Unable to convert UTF-16 character: U+E57D Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E21A Unable to convert UTF-16 character: U+E6E7 Unable to convert UTF-16 character: U+E11C Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E11C Unable to convert UTF-16 character: U+20AC Unable to convert UTF-16 character: U+E6E7 

    论坛上技术人员较多,有没有遇到过相关问题,不吝赐教

    14 条回复    2024-11-02 18:14:27 +08:00
    ntedshen
        1
    ntedshen  
       347 天前   1
    ps 里用输出重定向导出 sql 。。。
    乱码才是正常情况,因为是 ps 转换的 utf16le 而不是 pg 转换的。。。

    话说默认不该是 utf8 么。。。
    中文字符集怎么会有 20ac 欧元符号,然后 e000-f8ff 是私有段,可以在一些 iconfont 里看到。。。
    sleepm
        2
    sleepm  
       347 天前
    那就换访问方式导出
    用 dbeaver
    或者 从另一个 linux 主机远程访问数据库,导出
    顺便推荐个工具,虽然不是我写的
    https://github.com/xo/usql
    sleepm
        3
    sleepm  
       347 天前
    yinmin
        4
    yinmin  
       347 天前
    你应该用 cmd 命令提示符,而不是 powershell 导出 sql
    hez2010
        5
    hez2010  
       347 天前 via Android
    PowerShell 在 7.3 版本之前会把输出编码为 UTF16-LE 文本后输出,可能是这个原因导致你导出的 sql 出了编码问题,这个问题在 7.4 开始得到了修复,7.4 以后不额外转换编码而是直接写入数据。
    Windows 自带的 PowerShell 还是 5.x 版本自然还是未修复之前的行为。
    yinmin
        6
    yinmin  
       347 天前
    #5 正解。Windows 自带 PowerShell 5.1 ,重定向二进制数据会导致数据损坏。使用最新的 PowerShell 7.4 导致中文正常。 因此,需要使用 cmd.exe 和 PowerShell 7.4 才行。

    https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-7.4 的内容:从本机命令重定向二进制数据
    从 PowerShell 7.4 开始,PowerShell 将原生命令的 stdout 流重定向到文件时,或者将字节流数据通过管道传输到原生命令的 stdin 流时,保留字节流数据。

    https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_redirection?view=powershell-5.1 的内容: 重定向二进制数据
    PowerShell 不支持重定向二进制数据。 如果重定向字节流数据,PowerShell 会将数据视为字符串。 此重定向会导致数据损坏。
    adoal
        7
    adoal  
       347 天前
    除了前面友们说的 PowerShell 问题,另外问一下 OP ,你为啥执着于转成 GBK ?如果 UTF-16 里的内容是对的,转到 UTF-8 不好么? GBK 的字符集比较小,从基于 Unicode 的编码转过来有转丢的很正常。
    bthulu
        8
    bthulu  
       346 天前
    可以先恢复到 utf16 编码的数据库里, 再重新导出一遍
    jackmod
        9
    jackmod  
       346 天前
    我依然不懂 pg 这么个新东西为什么不在一切环境下把所有东西默认设定成 utf8 。
    已经被默认使用客户端控制台编码这个骚决定坑过好多次了。
    zjsxwc
        10
    zjsxwc  
       346 天前
    数据库运维不建议使用 windows 系统,一大原因就是这种编码问题。
    mingl0280
        11
    mingl0280  
       346 天前
    如果是全文件都是 UTF-16 ,直接 Notepad++打开转码就行。
    sbmzhcn
        12
    sbmzhcn  
    OP
       341 天前
    这个问题怎么产生的我也不太清楚,各种方法都试了,绝对不是随便转码就能成功的,我也找到一些高手尝试解决,无法搞定,目前是转为 gb18030 是效果最好的,几乎 90%的字符是可以转换成功的,但其它任何编码都不行。
    sbmzhcn
        13
    sbmzhcn  
    OP
       341 天前
    @hez2010 Windows 终端 版本: 1.20.11781.0 这个损坏了,是不是 没有办法修复了。
    sbmzhcn
        14
    sbmzhcn  
    OP
       341 天前
    终端版本是这个 $psversiontable
    Name Value
    ---- -----
    PSVersion 5.1.22621.4249
    PSEdition Desktop
    PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
    BuildVersion 10.0.22621.4249
    CLRVersion 4.0.30319.42000
    WSManStackVersion 3.0
    PSRemotingProtocolVersion 2.3
    SerializationVersion 1.1.0.1
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     860 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:33 PVG 05:33 LAX 14:33 JFK 17:33
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86