QDataStream类型

QDataStream类提供了二进制数据到QIODevice的串行化。

数据流是一个编码信息的二进制流,它与主机的操作系统、CPU或字节顺序100%的没有关系。比如一个在PC的Windows下写的数据流可以在Sun SPARC的Solaris中读出。

QTextStream. 你也可以使用一个数据流来读/写原始的未编码的二进制数据。如果你想“解析”输入流,请参考QTextStream

QDataStream类实现了基本类型的串行化,比如charshortintchar*等等。更加复杂的类型的串行化是通过把数据分解为简单单元来实现的。

数据流和QIODevice合作非常紧密。QIODevice描述了一个可以从中读数据和向它写数据的输入/输出介质。QFile类就是一个IO设备的例子。

实例(向一个流中写二进制数据):

    QFile f( "file.dta" );
    f.open( IO_WriteOnly );
    QDataStream s( &f );    // 我们将把数据串行化至文件f
    s << "the answer is";   // 串行化一个字符串
    s << (Q_INT32)42;       // 串行化一个整数
  

实例(从一个流中读二进制数据):

    QFile f( "file.dta" );
    f.open( IO_ReadOnly );
    QDataStream s( &f );    // 从文件f中读取串行化的数据
    QString str;
    Q_INT32 a;
    s >> str >> a;          // 提取出“the answer is”和42
  

每一个要写到流中的项都被写成一种预定义的二进制格式,这种格式取决于这个项的类型。Qt中支持的类型有QBrushQColorQDateTimeQFontQPixmapQStringQVariant和其它一些。支持数据流的所有的Qt类型的列表请看QDataStream操作符的格式

举个例子,char*字符串被写做一个等于包括NUL字节的字符串长度的32位整数,后面跟着字符串中包括NUL字节的所有字节。当读取char*字符串的时候,先读4个字节创建一个32位长度值,然后读取包括NUL的这么多的字节到char*字符串中。

初始的IODevice通常在构造函数中设置,但是也可以使用setDevice()来改变。如果你到达了数据的终点(或者如果没有IODevice被设置),atEnd()将返回真。

如果你希望数据和以前版本的Qt一致,请使用setVersion()。

如果你希望数据是人们可读的,比如,用于调试,你可以用setPrintableData()设置数据流为可打印数据模式。然后这个数据写起来慢一些,并且膨胀起来但已经是人们可以读取的格式了。

如果你正在生成一种新的二进制数据格式,比如是你的应用程序创建的一种文档的文件格式,你可以使用QDataStream来把数据写成一种可移植的格式。通常,你可以写一个包含幻数字符串和版本信息的简要的头信息,这样可以给你以后的扩展提供一定的空间。比如:

    QFile f( "file.xxx" );
    f.open( IO_WriteOnly );
    QDataStream s( &f );

    // 写一个含有“幻数”和版本号的头
    s << (Q_UINT32)0xa0b0c0d0;
    s << (Q_INT32)123;

    // 写数据
    s << [lots of interesting data]
  

然后这样读:

    QFile f( "file.xxx" );
    f.open( IO_ReadOnly );
    QDataStream s( &f );

    // 读取并检查头
    Q_UINT32 magic;
    s >> magic;
    if ( magic != 0xa0b0c0d0 )
        return XXX_BAD_FILE_FORMAT;

    // 读取版本号
    Q_INT32 version;
    s >> version;
    if ( version < 100 )
        return XXX_BAD_FILE_TOO_OLD;
    if ( version > 123 )
        return XXX_BAD_FILE_TOO_NEW;
    if ( version <= 110 )
        s.setVersion(1);

    // 读取数据
    s >> [很多有趣的数据];
    if ( version > 120 )
        s >> [在1.2版中的新数据XXX];
    s >> [其它有趣的数据];
  

当你串行化数据的时候,你可以选择你要使用的字节顺序。默认的设置是高字节在前。把它改变为低字节在前会破坏可移植性(除非读取程序也是用低字节在前)。我们建议你使用默认设置,除非你有特殊需要。

读写原始二进制数据

你也许希望把你自己的原始二进制数据直接写到数据流中,或者从数据流中直接读取它们。数据可以使用readRawBytes()从流中读取到一个预先分配好的char*。同样地也可以使用writeRawBytes()把数据写到流中。注意,任何数据的编码/解码就只能由你自己来完成了。

一对相似的函数readBytes()和writeBytes()。它们与操作原始数据的那两个的区别是:readBytes()先读取可读的数据长度到一个Q_UINT32,然后读取这个数量的字节到已经预先分配空间的char*;writeBytes()写一个包含数据长度的Q_UNIT32,然后再是数据。注意任何数据的编码/解码(除了长度Q_UINT32)都必须由你自己来做。

也可以参考QTextStreamQVariant输入/输出和网络

void Server::sndMsg() { ui->sSendBtn->setEnabled(false); clntConn = tSrv->nextPendingConnection(); connect(clntConn, SIGNAL(bytesWritten(qint64)), this, SLOT (updClntProgress(qint64))); ui->sStatusLbl->setText(tr("开始传输文件 %1 !").arg(theFileName)); locFile = new QFile(fileName); //只读方式打开 if(!locFile->open((QFile::ReadOnly))){ QMessageBox::warning(this, tr(" 应 用 程 序 "), tr(" 无 法 读 取 文 件 %1:\n%2").arg(fileName).arg(locFile->errorString())); return; } //获取待发送文件的大小 totalBytes = locFile->size(); //将发送缓冲区outBlock封装在一个QDataStream类型的变量中,这样做可以很方便通过重载"<<"操作符填写文件头结构 QDataStream sendOut(&outBlock, QIODevice::WriteOnly); sendOut.setVersion(QDataStream::Qt_4_7); time.start(); //开始计时--用来统计传输所用的时间 QString curFile = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1);//去掉文件的路径部分 sendOut << qint64(0) << qint64(0) << curFile;//构造一个临时的头文件,将该值追加到totalBytes字段,从而完成实际需发送字节数的记录 totalBytes += outBlock.size(); sendOut.device()->seek(0);//将读写操作指向从头开始 sendOut << totalBytes << qint64((outBlock.size() - sizeof(qint64)*2));//填写实际的总长度和文件长度 bytesTobeWrite = totalBytes - clntConn->write(outBlock);//将改文件头发出,同时修改待发送字节数bytesTobeWrite outBlock.resize(0); //清空发送缓冲区以备下次使用 }
06-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值