6.3.3 变长数据块的读写
6.3.3 变长数据块的读写
变长数据块的含义为每一段数据的长度是不固定的。设计这种数据的关键是在某个已知的位置记录每段记录的长度,这有点像Windows API中的某些结构的定义,它们的第一个字节会标识本结构的长度。比如创建进程时,CreateProcess()函数需要一个STARTUPINFO结构的参数,STARTUPINFO结构的定义如下:
- typedef struct _STARTUPINFO {
- DWORD cb;
- LPTSTR lpReserved;
- LPTSTR lpDesktop;
- LPTSTR lpTitle;
- DWORD dwX;
- DWORD dwY;
- DWORD dwXSize;
- DWORD dwYSize;
- DWORD dwXCountChars;
- DWORD dwYCountChars;
- DWORD dwFillAttribute;
- DWORD dwFlags;
- WORD wShowWindow;
- WORD cbReserved2;
- LPBYTE lpReserved2;
- HANDLE hStdInput; //标准输入
- HANDLE hStdOutput; //标准输出
- HANDLE hStdError; //标准错误
- } STARTUPINFO, *LPSTARTUPINFO;
其第一个成员cb就负责指明当前结构块的字节长度,一般我们需要将其设置为:
- STARTUPINFO sui;
- sui.cb = sizeof(STARTUPINFO);
提示
针对以上cb成员的赋值,很多程序员可能会觉得有点多此一举,sizeof(STARTUPINFO)是静态不变的,那为什么还要浪费一个成员来存储自己的长度呢?唯一合理的解释是:Windows可能是处于版本升级的考虑,在不同的Windows版本下,STARTUPINFO可能会具有不同的长度。
在写文件时,如果待写数据段的长度不固定,则将其长度记录在该段相对固定的位置上,当文件读取程序遇到该段数据时,读取到长度值。
现在动手
如下程序为变长数据块的读写,我们将数据块的长度记录在每段数据块的头部,请读者仔细体验。
【程序6-5】使用CFile完成变长数据块的读写
- 01 #include "stdafx.h"
- 02
- 03 //写入字符串
- 04 void WriteString(CFile & file, CString & s)
- 05 {
- 06 int len = s.GetLength();
- 07 //写入字符串的长度
- 08 file.Write(&len, sizeof(int));
- 09 //写入字符串
- 10 file.Write((LPCTSTR)s, len);
- 11 }
- 12
- 13 //读取字符串
- 14 bool ReadString(CFile & file, CString & s)
- 15 {
- 16 //先读取字符串长度
- 17 int len;
- 18 if(file.Read(&len, sizeof(int)) == sizeof(int))
- 19 {
- 20 TRACE("字符串长度: %d bytes/r/n", len);
- 21
- 22 char * sp = new char[len + 1];
- 23 sp[len] = 0;
- 24 if(file.Read(sp, len) == len)
- 25 {
- 26 s = sp;
- 27 delete [] sp;
- 28 return true;
- 29 }
- 30 delete [] sp;
- 31 }
- 32
- 33 return false;
- 34 }
- 35
- 36 //读取指定索引的字符串
- 37 bool ReadString(CFile & file, CString & s, int index)
- 38 {
- 39 //比较麻烦,必须从头开始数
- 40 file.SeekToBegin();
- 41 int i = 0;
- 42 while(i < index)
- 43 {
- 44 //读取记录长度
- 45 int len;
- 46 if(file.Read(&len, sizeof(int)) != sizeof(int))
- 47 return false;
- 48
- 49 //定位文件指针
- 50 file.Seek(len, CFile::current);
- 51 i++;
- 52 }
- 53
- 54 return ReadString(file, s);
- 55 }
- 56
- 57 int main()
- 58 {
- 59 CFile file;
- 60 file.Open("test.out", CFile::modeWrite
| CFile::modeCreate);- 61
- 62 CString s1 = "bluejoe";
- 63 CString s2 = "jerry";
- 64 CString s3 = "even";
- 65
- 66 //写入
- 67 WriteString(file, s1);
- 68 WriteString(file, s2);
- 69 WriteString(file, s3);
- 70
- 71 file.Close();
- 72 //读取
- 73 file.Open("test.out", CFile::modeRead);
- 74 printf("文件大小: %d bytes/r/n", file.GetLength());
- 75
- 76 int i = 0;
- 77 while(true)
- 78 {
- 79 CString s;
- 80 if(!ReadString(file, s))
- 81 break;
- 82
- 83 printf("[%d]: %s/r/n", i, s);
- 84 i++;
- 85 }
- 86
- 87 CString s;
- 88 if(ReadString(file, s, 1))
- 89 printf("[%d]: %s/r/n", 1, s);
- 90
- 91 return 0;92 }
运行结果如图6-16所示。
图6-16 运行结果 |
- 字符串长度: 7 bytes
- 字符串长度: 5 bytes
- 字符串长度: 4 bytes
- 字符串长度: 5 bytes
可以看出,采用变长数据块来存储字符串,可以大大节省存储空间。其原理如图6-17所示。很多应用程序都会采用类似的存储方式,但是它们往往更喜欢将每一段数据块的描述信息(如:偏移量、长度)统一地记录在文件的首部。
图6-17 变长数据块的读写 |
我们可以通过记事本等工具来观察两种形式的数据文件的内容,如图6-18所示。
图6-18 定长数据与变长数据 |
光盘导读
该项目对应于光盘中的目录"/ch06/VarSizedBlock"。
以上摘自《把脉VC++》第6.3.3小节的内容 ,转载请注明出处。
如果你想与我交流,请点击如下链接加我为好友:http://student.csdn.net/invite.php?u=113292&c=8913f87cffe7d533
如本文存在任何侵权部分,请及时告知,我会第一时间删除!
转载本博客原创文章,请附上原文@cnblogs的网址!
QQ: 5854165 我的开源项目 欢迎大家一起交流编程架构技术&大数据技术! +++++++++++++++++++++++++++++++++++++++++++