有一个上传过程,读取文件并使用 sqlldr 将数据上传到数据库。我在 sqlldr 中处理文件时遇到无效号码问题。发现该文件是UTF-16格式,然后在notepad++中转换为UTF-8格式,它开始正常工作。现在我正在尝试系统地转换它,如下所示。
iconv -f UTF-16 -t UTF-8 file_name >output_file_name
该文件可能具有不同的编码,因此我想在转换之前找到该文件的编码,然后根据该编码进行转换。例如使用 file 命令仅从下面读取 UTF-16,然后在 -f 选项中使用它。
bash-4.2$ file "/FILE_UPLOADS/Relationship (4).txt"
/FILE_UPLOADS/Relationship (4).txt: Little-endian UTF-16 Unicode text, with CRLF line terminators
我怎么做?
答案1
vim
能够自动检测一些文件编码并转换为 UTF-8,因此您可以尝试使用以下ex
模式处理文件:
vim --clean -E -s -c 'argdo set fileencoding=utf-8 nobomb | update' -c q -- *.txt
我们update
也只重写在此过程中修改过的文件。
答案2
您可以使用file -i
,它将返回文件的 MIME 编码。
就像是:
iconv -f `file -i $file|grep -Po 'charset=\K.*'` -t UTF-8 $file > $file_converted
另一种方法是使用更专用的工具,例如:
https://gitlab.freedesktop.org/uchardet/uchardet
那么命令就变得更加简单了
iconv -f `uchardet $file` -t UTF-8 $file > $file_converted
但你需要安装它。
答案3
什么时候file
说Little-endian UTF-16 Unicode 文本或与--mime-encoding
UTF-16LE,这意味着该文件以 UTF-16 编码,并带有 BOM,表明该文件采用小端字节序。
file
无法检测没有 BOM 的 UTF-16 文本文件(小端或大端)。
对于 UTF-16 文本,它需要前两个字节为 0xff、0xfe(小端)或 0xfe 0xff(大端),然后检查前 64KiB 数据的其余部分是否像文本(仅查找文本文件中不需要的 UTF-16 编码的 ASCII 控制字符)。
为了iconv
,utf-16le
表示小端 UTF-16没有BOM,而 utf-16 表示带有 BOM 的 utf-16,无论是大端还是小端。
所以如果你使用的输出file -b --mime-encoding
作为从charset in iconv
,您最终会在输出中得到 UTF-8 编码的 BOM。
在这里,您可能想要类似的东西:
encoding=$(file -b --mime-encoding - < "$file") &&
case $encoding in
(utf-16[bl]e) iconv -f UTF-16 < "$file" -t UTF-8 > "$newfile";;
(us-ascii | utf-8) ;; # already utf-8
(*) printf >&2 '%s\n' "don't know what to do with a $encoding encoding"
esac
如果这些是 Microsoft 文件(如 CRLF 所示),您可能需要dos2unix
使用iconv
. dos2unix
(至少当前版本)应该能够检测 UTF-16 并转换为语言环境的字符集(LC_ALL=C.UTF-8 dos2unix
如果您希望输出为 UTF-8,无论语言环境如何,请运行它)并将 CRLF 更改为 LF 并修复其他怪癖在微软的文件中。