QByteArray 通过 QDataStream 的读写 //先上测试代码: #include #include #include int main() { QByteArray dstByteArray; QString strRead; QDataStream writeToByteArray(&dstByteArray, QIODevice::ReadWrite); QFile fConsol; // 打开控制台输出 fConsol.open(stdout, QIODevice::WriteOnly); QTextStream writeTextConsol(&fConsol); // 向 dstByteArray 中写入一个字符串 writeToByteArray << QString("test"); // 然后再从里面读出来 writeToByteArray >> strRead ; // 显示刚刚的读取结果 writeTextConsol << strRead; return 0; } 我期望的结果当然是把刚写入的字符串 "test" 读出来然后再显示到控制台上,但是结果却意外: 如图,结果什么也没有,为什么呢????? 查下 qt 的文档,看了 QDataStream 的构造函数介绍: QDataStream::QDataStream ( QByteArray * a, QIODevice::OpenMode mode ) Constructs a data stream that operates on a byte array, a. The mode describes how the device is to be used. Alternatively, you can use QDataStream (const QByteArray &) if you just want to read from a byte array. Since QByteArray is not a QI ODevice subclass, internally a QBuffer is created to wrap the byte array. 从可以看出因为 QByteArray 不是一个继承自 QI ODevice 的类所以 QDataStream 类在处理它的时候会创建一个 QBuffer 类.而QBuffer 是继承自 QI ODevice 类的,而 QI ODevice 类在处理数据的时候都有一个文件指针,指向当前处理的位置.当使用 writeToByteArray << QString("test");向一个 QByteArray 中写入一个字符串后,就像对文件的写入一样,文件的指针会向后移动,指向下一个位置,当使用: writeToByteArray >> strRead ; 再从 QByteArray 中读入时,因为此时文件的指针指在最后面,读的时候就会发现后面没有数据了,所以就会返回一个空字符串,于是输出什么也没有了.即然知道原因了就好办了,只要在读取之前重新设置一下文件指针就可以了,下面是代码: // 省略相同的........... . // 向 dstByteArray 中写入一个字符串 writeToByteArray << QString("test"); //------------------------------------------------------------- // 设置文件指针 // 这里是新加的 writeToByteArray.device()->seek(0); //----------------------------------------------------------------- // 然后再从里面读出来 writeToByteArray >> strRead ; // 省略相同的........... 结果: 可以看到显示和预想的一样了. 对于用 QDataStream 向一个 ByteArray 中写入的数据,可不可以直接输出呢如下: writeTextConsol << dstByteArray.data(); 因为 data()会返回 QByteArray 中数据的指针。 下面来测试一下: #include #include #include int main() { QByteArray dstByteArray; QString strRead; QDataStream writeToByteArray(&dstByteArray, QIODevice::ReadWrite); QFile fConsol; // 打开控制台输出 fConsol.open(stdout, QIODevice::WriteOnly); QTextStream writeTextConsol(&fConsol); // 向 dstByteArray 中写入一个字符串 writeToByteArray << QString("test"); // 这里直接输出 writeTextConsol << dstByteArray.data(); return 0; } 结是是: 这又是怎么回事? ? ? ? ? ? ? ? 数据是肯定有的, 因为前一个例子都可以输出了。 那么就来看看使用 QDataStream 向 dstByteArray中写入的数据是什么样子的: #include #include #include int main() { QByteArray dstByteArray; QString strRead; QDataStream writeToByteArray(&dstByteArray, QIODevice::ReadWrite); QFile fConsol; // 打开控制台输出 fConsol.open(stdout, QIODevice::WriteOnly); QDataStream writeToConsol(&fConsol); QTextStream writeTextConsol(&fConsol); // 向 dstByteArray 中写入一个字符串 writeToByteArray << QString("test"); // 依次输出 dstByteArray 中的字符 for (int i = 0; i < dstByteArray.length(); i++) { writeTextConsol << showbase << hex << (int)dstByteArray.at(i) << " "; } return 0; } 结果: 0x74 0x65 0x73 0x74 分别对应 test 中的 4 个字符, 那么怎么还多了那么多的 0x0 呢? ? ? 要知道答案, 看 Qt 文档吧! ! ! 下面是 QDataStream 中看到的一段话: a char * string is written as a 32-bit integer equal to the length of the string including the '\0' byte, followed by all the characters of the string including the '\0' byte. When reading a char * string, 4 bytes are read to create the 32-bit length value, then that m any characters for the char * string including the '\0' term inator are read. 在使用 QDataStream 向一个 QByteArray 中写入数据时, 会首先写入一个 32 位的整数, 这个整数保存了了此 QByteArray 的长度 ('\0'也算一个字符), 当从这个 QDataStream 中读 QByteArray中的一个字符串时会首读取这个字符串中一共有多少个字符, 也就是开始的那 4 个 byte, 然后再读取字符串的内容。 回到我们的问题上来, 从输出可以看出, 开始的 4 个字节分别是 00 00 00 08, 也就是这个字符串的长度是 8, 一共有 8 个字符,数一下看看, 嗯, 真的有 8 个字符噢。 可是我们明明只写了” test“4 个字符啊, 怎么变成了 8 个字符了呢? ? ? ? ? ? 这怎么莫名其妙的多出 4 个字符呢? ? ? 而且还全都是 0 呢? ? 这个嘛, 因为我们写的时候是以 QString("test")这样的形式写入QByteArray 中的, 而在 Qt 中 QString 是以 unicode 进行编码的,而 unicode 编码的字符是占两个字节的所以呢, 4* 2 刚好是等于 8个字符, 太好了终于明白了。 因为普通的 ascii 字符中要一个字节就可以表示了, 所以高字节者以 0 填充, 这就是为什么在 0x74 0x65 0x73 0x74 四个字符的前面都多了个 0x0 的原因了。 那现在我们不用 writeToByteArray << QString("test"); 来写入数据, 而改为下面的这种方式: writeToByteArray << “test”; 再看输出结果: 和预想的一样, 哈哈。 前 5 个字符表示了本字符串的长度, 后面接的是实际的字符串, 为什么长度是 5? ? ? 别忘了 QDataStream 会把 最后的那个 '\0' 也算进去的噢, 你年最后不是多了个 0x0 么! ! 这就是最后的那个 '\0' 。 现在即然知道了前 4 个字符是表示了字符串的长度, 那我们可不可以跳过这个长度,当然可以了啊! ! 直接这样写: // 省略相同代码。 。 。 。 。 。 。 。 writeTextConsol << dstByteArray.data() + 4 ; 输出结果: 你看可以吧! ! ! ! 学习脚步。 。 。 。 。 。 。 。 。