在Qt中创建UTF-8文件

21

我正在尝试在Qt中创建一个UTF-8编码的文件。

#include <QtCore>

int main()
{
    QString unicodeString = "Some Unicode string";
    QFile fileOut("D:\\Temp\\qt_unicode.txt");
    if (!fileOut.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return -1;
    }

    QTextStream streamFileOut(&fileOut);
    streamFileOut.setCodec("UTF-8");
    streamFileOut << unicodeString;
    streamFileOut.flush();

    fileOut.close();

    return 0;
}

我认为默认情况下QString是Unicode的,当我将输出流的编解码器设置为UTF-8时,我的文件将是UTF-8格式。但事实并非如此,它是ANSI格式。 我做错了什么?我的字符串有问题吗?你能修改我的代码以创建UTF-8文件吗? 接下来我要读取ANSI文件并将其保存为UTF-8文件,因此我将需要对每个读取的字符串执行转换,但现在,我想从一个文件开始。 谢谢。


1
你应该使用QString::fromUtf8()将字符串字面值转换为字符串。此外,一些编译器在源文件中使用非ASCII编码时会出现问题(如MSVC)。因此,您可以尝试通过QInputDialog等方式输入字符串来解决问题。我还建议在遇到此类问题时定义QT_NO_CAST_FROM_ASCII和QT_NO_CAST_TO_ASCII。它禁用了隐式转换,从而使情况更加清晰明了。 - Frank Osterfeld
https://dev59.com/q4nca4cB1Zd3GeqP-2_i - trante
3个回答

19

2022年的修改:以下内容适用于Qt 4。从Qt 5开始,默认使用UTF-8,因此本回答不适用于最新的Qt版本。

您的代码是完全正确的。我唯一怀疑的部分是这个:

QString unicodeString = "Some Unicode string";

它看起来可疑的原因在于,默认情况下QString在从C风格字符串字面量构造时使用Latin1编码。因此,如果您只打算使用带重音的拉丁字符,那么您可能没问题,但如果使用其他任何字符(如西里尔文、中文、日文、希伯来文等),那么它将无法正确工作。处理此问题的最佳方法是将源代码编码为UTF-8,并执行以下操作:

QString unicodeString = QString::fromUtf8("Some Unicode string");

这将适用于任何可能的语言。使用QObject::trUtf8()甚至更好,因为它提供了很多国际化能力。

编辑

虽然生成正确的UTF-8文件是正确的,但如果您希望Notepad将您的文件识别为UTF-8,则需要进行不同的操作。 您需要在其中放置BOM。 它可以像另一个答案中建议的那样完成,或者这里是另一种方法:

streamFileOut.setGenerateByteOrderMark(true);

1
我不建议将C++源代码保存为UTF-8格式 :) - Piotr Dobrogost
1
@Piotr,为什么?UTF-8(无BOM)是一种与US-ASCII完全兼容并支持任何语言的编码方式。否则,你如何在某些本地语言中使用字符字面量,而不必诉诸于QTextStream :: setCodecForCStrings(),这可能会导致很多问题? - Sergei Tachenov
1
@Ondrej,注意有些软件可能不喜欢BOM,特别是那些一开始就没有支持Unicode的软件。即使没有BOM也仍然有效的UTF-8,所以你是否要放置BOM取决于你打算如何使用生成的文件。最终决定取决于你。 - Sergei Tachenov
1
BOM对于UTF-8文件没有意义,这是微软的专有名词。 - koan
1
@CJBrew,说得好。虽然这不是我的本意,但即使英语不是我的母语,我认为在2011年我已经足够好地注意到了这一点。我会尝试用更礼貌的方式重新表述。 - Sergei Tachenov
显示剩余7条评论

11

我使用QT创建UTF-8无BOM的txt编码的经验如下:

file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out.setCodec("UTF-8"); // ...
vcfline = ctn; //assign some utf-8 characters
out.setGenerateByteOrderMark(false);
out << vcfline; //.....
file.close();

文件将以UTF-8编码而没有BOM。


如果你从文件中读取,为输入和输出文件流设置编解码器。 - S.M.Mousavi

7
不要忘记UTF-8编码将把ASCII字符编码为一个字节。只有特殊或带重音符号的字符才会被编码为多个字节(从2到6个字节)。
这意味着只要您有ASCII字符(这是您的unicodeString的情况),文件将只包含8个字节的字符。因此,您可以获得与ASCII的向后兼容性:

UTF-8可以表示Unicode字符集中的每个字符,但与它们不同,具有与ASCII向后兼容的优点。

要检查代码是否正常工作,您应该在您的unicode中添加一些带重音符号的字符。
我已经使用带重音符号的字符测试了您的代码,它运行良好。
如果您想在文件开头加上BOM,您可以先添加BOM字符(QChar(QChar::ByteOrderMark))。

谢谢Jerome,你帮我解决了一个BOM的问题。文件其实是OK的,只是缺少了BOM。我使用了Sergey的方法将它添加到流中,但是非常感谢你的帮助。 - Ondrej Vencovsky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接