Qt cpp - 将 QString 写入文本文件的干净方法

Ale*_*Ale 4 c++ qstring qt iostream

我需要找到一个干净,快捷的方式写QString.csv文件中。我试过:

QString path= QCoreApplication::applicationDirPath() + QString("/myfile.csv");
QFile file(path);
QString mystring = "Hello, world!";    
if(!file.open(QIODevice::WriteOnly)){
        file.close();
    } else {
        QTextStream out(&file); out << mystring;
        file.close();
    }
Run Code Online (Sandbox Code Playgroud)

但它经常为我"???????"myfile.csv

Sch*_*eff 9

由于 Andrey 尚未做出反应,我将介入并提供有关 OP 问题的一些背景信息:

来自 Qt 文档。关于QString

即QString类提供了一个Unicode字符串。

QString存储 16 位QChar的字符串,其中每个QChar对应一个 Unicode 4.0 字符。(代码值大于 65535 的 Unicode 字符使用代理对存储,即两个连续的QChar。)

来自 Qt 文档。关于QTextStream::operator<<(const QString &string)

将字符串string写入流,并返回对QTextStream的引用。在将字符串写入流之前,首先使用指定的编解码器(默认编解码器为QTextCodec::codecForLocale())对字符串进行编码。

大约QTextStream在一般:

在内部,QTextStream使用基于 Unicode 的缓冲区,而QTextCodec由 QTextStream 使用以自动支持不同的字符集。默认情况下,QTextCodec::codecForLocale()用于读写,但您也可以通过调用setCodec()设置编解码器。还支持自动 Unicode 检测。启用此功能时(默认行为),QTextStream将检测 UTF-16 或 UTF-32 BOM(字节顺序标记)并在读取时切换到适当的 UTF 编解码器。QTextStream默认不写入 BOM,但您可以通过调用setGenerateByteOrderMark (true)启用此功能。

因此,"???????"可能Hello, World!UTF-16UTF-32编码,其中 OP 视图工具(输出"???????")无法检测到这种情况,甚至不支持这种编码。

Andrey Semenov的提示,改为:

file.write(mystring.toUtf8());
Run Code Online (Sandbox Code Playgroud)

所述转换QString内容以UTF-8 ,其

  • 由字节组成
  • 在前 127 个ASCII字符方面与ASCII相同。

QString::toUtf8()返回QByteArray;并且QTextStream::operator<<(const QByteArray&)很可能将这些字节写入不变。(这甚至没有在文档中提到。)

因此,Hello, World!仅由 ASCII 表中可用的字符组成(代码 < 127)。即使 OP 视图工具支持/期望Windows 1252,它也不会注意到这一点。(我假设无法检测/处理 UTF-16 或 UTF-32 的工具也可能无法检测/处理 UTF-8。)


顺便提一句。要找出"???????"实际编码是什么,myfile.csv可以使用十六进制视图工具查看。由于输入是已知的,编码可能可以从输出中推导出来。(例如,He0x48 0x65在ASCIIUTF-8,但0x48 0x00 0x65 0x00在UTF-16LE和0x00 0x48 0x00 0x65在UTF-16BE)。


我试图用MCVE重现这个问题。

testQTextStreamEncoding.cc

#include <QtWidgets>

int main(int, char**)
{
  const QString qString = "Hello, World!";
  const QString qPath("testQTextStreamEncoding.txt");
  QFile qFile(qPath);
  if (qFile.open(QIODevice::WriteOnly)) {
    QTextStream out(&qFile); out << qString;
    qFile.close();
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

testQTextStreamEncoding.pro

file.write(mystring.toUtf8());
Run Code Online (Sandbox Code Playgroud)

cygwin 上,我做了:

#include <QtWidgets>

int main(int, char**)
{
  const QString qString = "Hello, World!";
  const QString qPath("testQTextStreamEncoding.txt");
  QFile qFile(qPath);
  if (qFile.open(QIODevice::WriteOnly)) {
    QTextStream out(&qFile); out << qString;
    qFile.close();
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

因此,似乎我无法在我身边重现 OP 所描述的内容。我也用在VS2013编译运行的代码试了一下:

SOURCES = testQTextStreamEncoding.cc

QT += widgets
Run Code Online (Sandbox Code Playgroud)

(编译,在VS2013中运行)

$ qmake-qt5

$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQTextStreamEncoding.o testQTextStreamEncoding.cc
g++  -o testQTextStreamEncoding.exe testQTextStreamEncoding.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 

$ ./testQTextStreamEncoding

$ hexdump.exe -C testQTextStreamEncoding.txt
00000000  48 65 6c 6c 6f 2c 20 57  6f 72 6c 64 21           |Hello, World!|
0000000d

$
Run Code Online (Sandbox Code Playgroud)

再次,我无法复制。看看 OP 如何产生"???????"以及它实际包含的内容会很有趣。