PHP使用iconv将UTF-16LE转UTF-8时输出乱码是什么原因?
转码异常的核心原因
UTF-16LE是双字节固定宽度编码,所有字符都占2个字节,换行符也对应0x0A 0x00两个字节。你使用PHP默认的逐行读取函数(比如fgets)时,函数会按单字节的0x0A作为换行分隔符切割内容,切割后的每行字节数大概率为奇数,破坏了UTF-16LE的字节对齐规则,转码函数拿到不符合编码规范的输入自然会输出乱码。
你把参数换成UTF-16后转码看起来稍正常,是因为UTF-16会自动检测大小端,但字节对齐的问题仍然存在,所以还是有乱码。
解决方法
方法1:全量读取转码后再拆分行(推荐,适合绝大多数场景)
先把整个文件内容全部读取完成后再转码,转码为UTF-8之后再按换行符拆分处理,示例代码如下:
// 读取完整的原始文件内容 $raw = file_get_contents('你的测试文件路径'); // 转码,加//IGNORE可跳过无法识别的字符避免转码中断 $utf8 = iconv('UTF-16LE', 'UTF-8//IGNORE', $raw); // 转码完成后再拆分逐行处理 $line_list = explode(PHP_EOL, $utf8); foreach ($line_list as $line) { echo $line . PHP_EOL; }
方法2:大文件逐块读取方案
如果文件体积过大无法一次性加载到内存,就需要手动处理字节对齐:每次读取偶数个字节,自行识别0x0D 0x00 0x0A 0x00(Windows换行)或0x0A 0x00(Unix换行)作为行分隔符,不要使用PHP内置的逐行读取函数。
额外注意事项
如果你的UTF-16LE文件带BOM(开头两个字节为0xFF 0xFE),全量读取转码时iconv会自动识别处理,不需要额外手动删除BOM。
内容的提问来源于stack exchange,提问作者Krzysztof Kaliszuk
相关产品推荐
相关产品推荐

