• 22703阅读
  • 12回复

[提问]QTextStream 读文件乱码(已解决)! [复制链接]

上一主题 下一主题
离线aoxuehan
 

只看楼主 倒序阅读 楼主  发表于: 2010-01-10
— 本帖被 XChinux 从 Qt基础编程 移动到本区(2013-04-01) —
什么方法都试过了 main函数设置编码也设置了:
    QTextCodec *codec = QTextCodec::codecForName("GBK");    //这里换成GB2312啊, System啊都试过了。不行
    QTextCodec::setCodecForLocale(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForTr(codec);    
QTextSteam也设置了:
    QFile file("index.txt");
    file.open(QIODevice::ReadOnly);
    QTextStream inputStream(&file);
    QTextCodec *codec=QTextCodec::codecForName("GBK");
    inputStream.setCodec(codec);

还是不行。读出来的东西 还是乱码。

我读的文件是一个网页的源代码。  因为在做个爬虫。。
3g.sina.com.cn的源码。

因为QHttp的get() 方法第二个参数是个QIODevice*    能不能直接保存到一个QString里面啊??
[ 此帖被aoxuehan在2010-01-11 09:48重新编辑 ]
常梦想自己是地主家的少爷
整天游手好闲,不学无术
没事儿带着一帮狗奴才在大街上调戏良家妇女。
离线benbenmajia

只看该作者 1楼 发表于: 2010-01-11
可能是相互之间转换的格式不对,你输出这些东西看看,转换之前和转换之后
安然.....
离线aoxuehan

只看该作者 2楼 发表于: 2010-01-11
搞定了。
方法如下:

  1. QTextCodec *codec = QTextCodec::codecForName("System");    //这里换成GB2312啊, System啊都试过了。不行
  2.     QTextCodec::setCodecForLocale(codec);
  3.     QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
  4.     QTextCodec::setCodecForTr(codec);  


这样就可以了。  我分开设置的。如果全部设置成UTF-8的话,那么程序内置的一些汉字全部显示为乱码。

然后再后面用textstream读的时候,设置如下:
  1. QTextCodec *codec=QTextCodec::codecForName("UTF-8");
  2. in.setCodec(codec);
  3. QString line;
  4. line = codec->fromUnicode(in.readLine())
常梦想自己是地主家的少爷
整天游手好闲,不学无术
没事儿带着一帮狗奴才在大街上调戏良家妇女。
离线golo
只看该作者 3楼 发表于: 2010-01-27
我在读取源文件的时候也遇到了这个问题,

要是这样
    QTextStream textStream(file);
    QTextCodec *codec=QTextCodec::codecForName("utf8");
    textStream.setCodec(codec);

文件ww.nddaily.com_.download.txt 能正确读取,但是ww.126.com_.download.txt 的中文部分却乱码

  要是这样
     QTextStream textStream(file);
    //QTextCodec *codec=QTextCodec::codecForName("utf8");
    //textStream.setCodec(codec);

则反过来,文件ww.126.com_.download.txt能正确读取,但是ww.nddaily.com_.download.txt的中文部分却乱码。

总之就是一部分文件中文显示正确了,另一些文件中文就显示方框或者乱码。用楼主的方法也无法解决,难道是各个网站所使用的编码不一样导致问题发生?
离线XChinux

只看该作者 4楼 发表于: 2010-01-27
对于简体中文网站,各网站使用的编码无非要么是GBK类的,要么是UTF-8类的。
接收网站内容的时候不用管它是哪个编码的,直接保存到文件中即可。
在读取文件的时候为了正确显示汉字确实需要判断是哪个编码的。下面是读取文件的代码:

这样:
QFile file("yourfilepath");


if (!file.open(QIODevice::Text | QIODevice::ReadOnly))
{
   ....
   return;
}
QTextStream in(&file);
in.setCodec("GBK");   // 或者设置为in.setCodec("UTF-8");
QString strHtml = in.readAll();
file.close();


另外,对于QHttp类的get()方法的第二个参数,可以直接将内容读到QIODevice实例中。
可以用QBuffer有(是从QIODevice派生出来的)。
这样读取完毕后就能读取QBuffer对象内容了,代码和上面的一样:

QBuffer  buf;
if (!buf.open(QIODevice::Text | QIODevice::ReadOnly))
{
   ....
   return;
}
QTextStream in(&buf);
in.setCodec("GBK");   // 或者设置为in.setCodec("UTF-8");
QString strHtml = in.readAll();
buf.close();
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
离线golo
只看该作者 5楼 发表于: 2010-01-28
问题解决了,多谢版主和楼主。

问题是这样的,调用在有些情况下调用QTextCodec类的 fromUnicode方法会失败,
一般情况下bool    canEncode ( const QString & s ) const返回false的时候就会失败。

出现问题的代码如下
QTextCodec *codec=QTextCodec::codecForName(charsetCode.toAscii());
in.setCodec(codec);
QString line;
line = codec->fromUnicode(in.readLine())

修正后的代码是
QTextCodec *codec=QTextCodec::codecForName(charsetCode.toAscii());
in.setCodec(codec);
QString line;
line.append(in.readLine());
离线golo
只看该作者 6楼 发表于: 2010-02-08
最近在遇到的字符编码问题一直未能彻底解决。


    QFile f("test.txt");
    if(!f.open(QIODevice::WriteOnly  | QIODevice::Text ))
    {
      return;
    }
  
    QTextStream textStream(&f);
    QTextCodec *codec = QTextCodec::codecForName(“utf8”));

    textStream.setCodec(codec);
    textStream << html;

html是网页的源代码,QString类型的,在内存中是正确的,写到文件之后就变成乱码了。
测试的网站是:http://www.unmultimedia.org/arabic/radio/index.html 阿拉伯文的,utf8编码
离线golo
只看该作者 7楼 发表于: 2010-02-08
找到一篇字符编码类的文档,贴在这里


字符编码

如果非要评个计算机初学者最头晕概念的话,估计字符编码可以排到前十,比马尔可夫链之类的理论性概念都要晕。为什么呢?因为这东西课本上不会讲,也没有什么理论,只能靠自己体会出来。我比较笨一点,晕了好几年,到了今年终于明白了怎么一回事,现在记在这边,免得再忘了。
首先定义只在本文中出现的两个基础概念:
1.字节组。每8个位(bit)是为一个字节,多个字节成为一个字节组。
2.文字串。现实语言的最小单位称为文字。一个英文字母就是一个文字,一个汉字也是一个文字,一个空格也是文字。
这两个概念是我生造的,主要是为了避免和现有的一大堆术语混起来。
文字串不能理解成字符串。倒是像圆这样的数学概念,比较抽象一些,只存在于头脑里。可以把文字串写在纸上,也可以记在计算机里,还可以读出来。字节组就是文字串在计算机中的表现形式。想一想,在纸上圆可以用一个公式来表达,也可以用一个图形来表达,还可以用文字描述它。文字串也一样,可以表述为多种字节组。众所周知,计算机只能处理数字,所以为了描述文字,最简单的方法就是把文字列出来,每个文字用一个数字表示。不同的国家有不同的方法来做这件事,比如美国人和英国人只有字母,还有一些符号,总共排了256个文字,叫做ascii码。中国的文字就比较多了 ,那个康熙大字典据说有40万,所以中国人排了gb2312标准,big5,gbk、还有gb18030,里面包含的文字总数各不相同。后面几个名词很熟悉吧。
3.把文字串表述成字节组的方法就叫做字符编码。
显然,美国人的ascii码是不能表示中国文字的,因为它只能表示256个文字。诚然,中国的标准可以表示美国人的文字,但是却不能表示阿拉伯字符和其它一些像型文字。后来大家意识到这个问题是文化交流的障碍,于是就在一起制定了一个unicode标准。简而言之,unicode标准就是穷尽这个世界上所有的文字,给每个文字编一个数字。 和gb2312,gbk等一样,其实unicode也只是一种编码标准,只不过它能够表示所有的文字。从此,如果一个计算机系统想要支持多种语言文字,只要简单地支持unicode就可以了。在这种系统里,我们可以认为文字串就是unicocde字节组,unicode字节组就是文字串。
虽然解决了编码不能相互表示的大问题,但是还有一个麻烦没有解决。就像前文所说的,所谓编码就是给文字编一个数字。在每个编码里,数字与文字是一一对应的,但是在不同的编码标准里呢?不同的编码标准可能包含相同的文字,比如big5里的公和gbk里的公就是同一个文字,但是被编了不同的数字。这时候,同一个文字对应了不同的数字。再者,同一个数字是否代表着同一个文字呢?显然不是的,不然,两种编码标准就只有包含文字多少的区别了,或者每个文字在两个编码对应了相同的数字,那这还是两个编码标准吗?
我经常感叹,要是这个世界上只有unicode这种编码标准那该多好啊,我们就不用操心这些问题了。可惜事实不是这样子的,以前的标准仍然盛行,特别是windows仍然使用旧的标准。在中文简体的windows上,用记事本写的文本文件仍然是gbk编码的。想要在一个使用unicode的浏览器上显示出文字来仍然不行,不同的编码环境从文件里读取的数字不会变,但是却表示了不同的文字。怎么办呢?很容易想到的办法是读取文件内容的时候把gbk编码转成unicode编码。仔细想一想,这应该是没问题的,因为gbk包含的文字只是unicode包含的文字的一部分而已,从gbk转成unicode应该是没问题的。反之,从unicode转成gbk却不一定可以。
还有一种情况是两种编码标准差不多,只是每个文字在两种编码标准里对应的数字不一样。比如gbk和cjk,两种编码标准都包含了大量的中文简体文字和繁体文字,但是两种编码是不一样的。一个gbk的文本文件想拿到只支持cjk的环境里阅读要怎么办呢?也要在读取文件的时候从gbk编码转成cjk编码。目前一般采用先把gbk转成unicode,然后再从unicode转成cjk的间接做法。这可不可行呢?前面我们已经知道了,gbk转成unicode是可以的,但是unicode的文字转成cjk却不一定可以。不过这并不是什么大问题,因为如果真的不能从unicode转到cjk的话,说明那个文字cjk根本不能表示,直接从gbk转成cjk肯定也不可以。与直接从gbk转成cjk相比,间接的转码多了一个步骤,不过形式上比较统一,只要每种编码都编写一段与unicode相互转换的程序,就可以进行任意编码的相互转换。这个世界存在太多的编码标准,想要每两种可以转换的编码都可以相互转换需要的转换程序太多,试想想一个多边形的每两点相互连接。
再进一步地考虑,虽然编码是一样的,但是数字转换成字节组的方式可不可以有多种方式呢?答案是,可以的。最典型的是unicode编码。unicode编了很多个文字,个数总是在增加,目前(2008年7月)是100713个文字。把文字串转换成unicode字节组最简单的办法就是每个文字用三个字节来表示,因为100713这个数字最少需要三个字节才能表示。不过实际上通常采用的是utf-8方案。其中,最常使用的128个英文字母用一个字节来表示,而中文使用三个字节(注,我经常以为是两个字节,不过那是其它字符)来表示。还可以使用utf-16方案,其中英文和中文都使用两个字节来表示,而其它字符采用四个字节。还有一种utf-32方案,所有的文字都用四个字节来表示。大多数软件在内存中使用utf-16来表示文字,而在硬盘文件或者网络数据流中使用utf-8。前者字节数比较固定,比较容易处理,而后者比较节约空间。
讲到这里,相信大家对字符编码已经了解得差不多了吧。我们再来理论联系实际。
首先看看python对于字符编码的处理。应该说python是*nix派系语言里对字符编码处理得比较好的了。它内建了对unicode的支持。python2.x版本里有两种类型的字符串,一种称为str类型,实际上可以理解为字节组。还有一种是unicode类型,实际上是utf-16的字节组,我们可以理解为文字串。
“中文” —> 这是str类型
u”中文” —-> 这是unicode类型
从文件、终端、网络数据流或者其它外部输入中读取的都是str类型字节组,而且向文件、终端、网络也只能输出str类型的字节组。unicode类型的文字串在输出到文件的过程中会自动转换成ascii编码,输出到终端的过程中会自动转换成系统默认的编码(简体中文windows为gbk)。str类型与unicode类型可以使用decode和encode两个方法互相转换,比如在简体中文windows的命令行界面里:
“中文”.decode(’gbk’) == u”中文”
u”中文”.encode(’gbk’) == “中文”
想要从文件里读取gbk编码的数据然后使用utf-8编码发送到网络上可以这样:
buf=file(filename,”r”).read()
mysocket.send(buf.decode(’gbk’).encode(’utf-8′))
很显然,unicode文字串没有decode()方法,而str字节组没有encode()方法。
值得注意的是,python经常会在输出的时候自动把unicode文字串转换成str字节组,而在字符串连接的时候把str字节组转换成unicode文字串。其中有些规律我还不大懂,哪位大虾指导一下。
在以后版本的python里,表示方法略有不同:
“中文” —> 这是一个unicode字符串
b”中文” —> 这是一个str(python3k叫做bytes)类型的字节组
接下来再以java为例。与python相比,java对于unicode的支持更胜一筹,因为存储在java程序文件或者数据文件里的字符串都是以utf-16保存的,并且输入输出时,java能做更多的自动转换(比如列出一个文件夹里所有的文件)。不过基本原理跟python是一样的,它也有两种类型,一种是byte[]类型,这是字节组。还有是String类型,这是unicode文字串。它们也是可以相互转换的:
String(”中文”).getBytes(”utf-8″) —-> 将unicode文字串转成utf-8字节组
new String(new byte[]{228, 184, 173, 230, 150, 135},”utf-8″) —–>将utf-8字节组转成unicode文字串
java还用输入输出专门提供了自动转换编码的类。InputStream和OutputStream专门用于输入输出byte[]字节组,而Reader和Writer专门用于输入输出unicode文字串。
最后,再说明一下Qt对于字符编码的处理。 c和c++对于unicode的支持是比较差,幸好qt为此下了番苦功,整体来说还过得去。qt对于字符编码的处理基本上与java类型。QByteArray(或者char[])类型是字节组,而QString是unicode文字串。它们之间的关系是这样的:
char[] data=char[6]{228, 184, 173, 230, 150, 135};
QTextCodec::codecForName(”utf-8″).toUnicode(data,6) —-> 将utf-8字节组转成unicode文字串
QTextCodec::codecForname(”utf-8″).fromUnicode(QString(”中文”)) —-> 将unicode文字串转成utf-8字节组
qt会自动地将c的char[]转换成unicode文字串。比如上文的QString(”中文”)。还有tr()函数,以及C++的隐式类型转换。自动转换使用的默认编码通常在QApplication构造后进行初始化,比如:
#ifdef Q_CC_MSVC
QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale()); //utf-8? QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); //utf-8?
#elif Q_CC_GNU
QTextCodec::setCodecForCStrings(QTextCodec::codecForName(”gbk”)); //与文件的编码同
QTextCodec::setCodecForTr(QTextCodec::codecForName(”gbk”)); //与文件的编码同
#endif
看起来很麻烦的样子,像java程序里”中文”就可以直接表示unicode文字串了,而qt还需要tr()转换一下。不过,幸好从utf-8字节组转换成unicode文字串还是比较简单的:
QString::fromUtf8(data); —-> 将utf-8字节组转成unicode文字串
tr(”中文”).toUtf8(); —-> 将unicode文字串转成utf-8字节组
如有不对,还请大牛们指正
离线golo
只看该作者 8楼 发表于: 2010-02-08
引用第5楼golo于2010-01-28 20:47发表的  :
问题解决了,多谢版主和楼主。
问题是这样的,调用在有些情况下调用QTextCodec类的 fromUnicode方法会失败,
一般情况下bool    canEncode ( const QString & s ) const返回false的时候就会失败。
.......


使用这种方法在读取http://www.google.cn/ig/china?source=g_cn&hl=zh-CN出现乱码
离线yashika

只看该作者 9楼 发表于: 2010-05-17
头痛,我也遇到了同样的问题
就是在使用QHttp的过程中,获取网页的源代码的时候,怎么知道目标网页是什么编码呢?如果和我自己指定的QTextCodec编码不匹配的话,就是乱码了.我知道非IEEE官方组织有一个关于编码识别的项目,我想知道Qt集成了目标文本编码识别没有?比如下面就是异步返回的代码:
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
        QString httpstr(codec->toUnicode(http.readAll()));
        ui->plainTextEdit->appendPlainText(httpstr);
比如我请求sina.com.cn, 这个网站是gb2312的,我使用的是utf-8解码, 就会出现乱码.怎么自动识别呢?
离线luoyes

只看该作者 10楼 发表于: 2010-05-19
收藏了
离线maidisula

只看该作者 11楼 发表于: 2012-08-09
回 4楼(XChinux) 的帖子
那要怎样判断文件的编码呢?
离线XChinux

只看该作者 12楼 发表于: 2012-10-24
前面不是有人说了原理了么,就那样,不能保证百分之百正确.
二笔 openSUSE Vim N9 BB10 XChinux@163.com 网易博客 腾讯微博
承接C++/Qt、Qt UI界面、PHP及预算报销系统开发业务
快速回复
限100 字节
 
上一个 下一个