QDataSet 的导入与导出数据功能终于开工了!通过它,你可以将数据保存到流或者文件中,也可以从文件或流中加载数据。
QDataSet 将数据保存到流的函数 SaveToStream ,保存到文件的函数为 SaveToFile,我们看一下它们声明:
procedure SaveToStream(AStream: TStream; AConverter: TQConverter); overload; procedure SaveToStream(AStream: TStream; AConverterClass: TQConverterClass;AExports: TQExportRanges); overload; procedure SaveToFile(const AFileName: QStringW;AConverter: TQConverter); overload; procedure SaveToFile(const AFileName: QStringW;AConverterClass: TQConverterClass; AExports: TQExportRanges); overload;
我们可以看到,SaveToStream 函数要求提供一个TQConverter 的转换器实例 AConverter 或者 TQConverterClass 类型的参数,它决定了QDataSet 以什么格式来存贮数据。另外一个参数 AExports 参数用于决定你要保存到流中的数据范围,它是以下值的一个集合:
- merMeta
导出时包含元数据信息,如字段的定义等内容。不同的转换器对元数据的支持级别不一样,这个需要对相应的转换器格式进行相应的了解。
- merUnmodified
导出时包含未修改的数据内容。
- merInserted
导出时包含新插入的数据内容。
- merModified
导出时包含修改的记录内容
- merDeleted
QDB 预定义了几个组合,方便大家使用,它们是:
merChanges=[merMeta, merInserted, merModified,merDeleted]; merChangesData=[merInserted, merModified,merDeleted]; merAll=[merMeta, merUnmodified, merInserted, merModified,merDeleted];
- merChanges 对应于变更内容的元数据及变更(增删改)的数据内容
- merChangesData 只包含变更的数据,而不包含元数据信息
- merAll 则对应于全部数据及元数据信息
下面的代码是一个设置导出数据内容范围的例子(AConverter 为一个 TQConverter 类型的实例):
AConverter.ExportRanges := merAll; FDataSet.SaveToFile(AFileName, AConverter);
关于转换器,qconverter_stds 提供默认的标准转换器,包括 MessagePack 和 Json 格式的打包封装,分别对应于 TQMsgPackConverter 和 TQJsonConverter。关于如何从 TQConverter 继承下来新的转换器,我会在单独的文章里予以说明,这里我们说说其用法。
我们在将数据保存到流里时,各种转换器都是明码保存的,这在传输时可能不安全,所以 TQConverter 需要和 TQStreamProcessor 配合,对编码后的数据流进行二次处理。而这些处理过程是如此的简单,只需要将 TQConverter 的为Processors 添加相应的处理器就可以。QDB 默认为您提供了 TQZLibStreamProcessor 用于压缩数据( qsp_zlib.pas 单元),以及TQAESStreamProcessor 用于加密数据( qsp_aes.pas 单元)。如果同时加密并压缩数据,这里有一个提示给大家:应先添加压缩处理器,然后再添加加密处理器。理由很简单,加密后的数据一般是乱码,此时可能数据的可压缩性会明显降低,从而使得压缩无法达到满意的效果。而先添加压缩处理器,则先压缩数据再加密,由于原始数据是明文,规律性较强,就可以大幅压缩以减少生成的结果体积。示例代码如下:
FZLibProcessor := TQZlibStreamProcssor.Create(Self); FZlibProcessor.CompressionLevel:=TZCompressionLevel(cbxCompressLevel.ItemIndex); AConverter.StreamProcessors.Add.Processor := FZLibProcessor; FAESProcessor:=TQAESStreamProcessor.Create(Self); FAESProcessor.InitVector:=edtInitVector.Text; FAESProcessor.KeyType:=TQAESKeyType(cbxKeyType.ItemIndex); FAESProcessor.Password:=edtKey.Text; FAESProcessor.EncryptMode:=emCBC; AConverter.StreamProcessors.Add.Processor:=FAESProcessor;
目前,程序暂时未支持安装组件到 IDE 的组件面板,将来加入安装支持后,就可以直接拖放控件,设置相关属性了,也就可以不用写一句代码直接设置好 Converter 的相关属性。
这里有一点需要注意,流处理器的顺序在保存和打开时,相应的转换器设置要保持一致。在使用 LoadFromStream 和 LoadFromFile 从流中加载数据内容时,会自动从最后一个流处理器调用到第一个处理器,实现保存的反过程。我们看一下函数声明:
procedure LoadFromStream(AStream: TStream;AConverter: TQConverter); overload; procedure LoadFromStream(AStream: TStream;AConverterClass: TQConverterClass); overload; procedure LoadFromFile(const AFileName: QStringW;AConverter: TQConverter); overload; procedure LoadFromFile(const AFileName: QStringW;AConverterClass: TQConverterClass); overload;
看到了什么?比 SaveToXXX 少了一个AExports 参数。也就是说,加载是从流或文件中加载所有的数据,不管它处于何种状态。至于转换器的规则和上面保存时完全一样,我就不再这里缀述。
FDataSet.LoadFromFile(AFileName, AConverter);
如果要将数据提交到数据库,我们将来会讨论 TQDataSet 与 TQProvider ,TQConverter 和 TQProvider 之间的数据交换,但目前这块并没有完成,所以也就不在讨论范围了。