300分征求一个文件格式的设计思路要设计一种本地文件存储格式,可以象队列一样向队尾存数据,从队首取数据。
300分征求一个文件格式的设计思路 要设计一种本地文件存储格式,可以象队列一样向队尾存数据,从队首取数据。 数据不定长,而且可能会很大,要求尽量快速。 大家有没有好想法?用access数据库不知道是不是可行(随着数据的不断存取,文件会不会越来越大?用什么SQL语句可以快速取到“队首”并删除之?),目前还有一个想法是用复合文件,不过同样对其效率不放心。故上来向弟兄们征求意见,谢谢![解决办法] 我觉得access或SQL都慢不错的。建议使用之。。[解决办法] <队首地址><队列块8><队列块9><队列块10>....<队列块n><队列块1>...<队列块7><EOF>[解决办法] sqlite一个内置嵌入式数据库, 本地就是一个文件. 速度超级快,最差也和你本地文件操作一样快.[解决办法] 1、数据量的大小变化不大的情况下,数据库变化不大。 2、delete from tab1 where rows 1;(interbase) 3、要求速度用楼上说的sqlite,比access快。 4、更要求速度,用内存式数据库,具体叫什么名字不清楚,只是听说过。[解决办法] 我觉得微软的结构化存储就挺好的啊。如果考虑数据库的话,建议用SQLite,开源,而且功能比较强大。[解决办法] rows是interbase和firebird的关键字,其他数据库里面有相同功能的关键字,关键字不同罢了。 splite你到官方下载有个单文件版的源代码amalgamation版,那个好编译。 官方下载地址:http://www.sqlite.org/sqlite-amalgamation-3_6_0.zip
探讨 谢谢阿丁第一个回贴:-) to sczyq, 存入的数据不定长,要用块的方式存取的话得模拟文件系统的方式,觉得很复杂:-(,你的呢称是不是改过啦? to 僵哥, 逻辑顺序文件的话删除队首会造成整个文件数据移动(要是系统有重定义文件头位置就好了-_-),另外啥是MQ? to 大头娃娃, sqlite确实不错,就是我没法在bcb下编译成功,不知为何。虚拟文件系统估计和复合文件一样,如果得不到好方案我就使用复合文件…[解决办法] 我的一个贴子也讨论了,记录队列解决方法,目的是限制记录数目,我的观点:
1。不要删除队首,留下空洞会使用空间越占越大,解决方法是,覆盖队首记录;
2。用一个时间字段做增序字段,select top 1... order by 时间,
显然第一个记录就是队首;
[解决办法] 楼主有见过dbase或foxbase没?你直接用它的存贮就可以了。采用记录块存贮,再建一个索引文件就可以了!
[解决办法] 想了一个晚上,导致今天上班迟到!我认为按照下面的结构会很快,也会很方便 :
typedef struct tagFileHeader
{
DWORD dwTail; // 队列尾的相对于文件头的偏移量,初始化设置成为sizeof(TFileHeader)
DWORD dwHeader; // 队列头的相对于文件头的偏移量,初始化设置成为sizeof(TFileHeader)
DWORD dwCount; // 队列的元素个数,初始化设置为0
} TFileHeader,*PFileHeader;
typedef struct tagFileInfo
{
DWORD dwOffset;
DWORD dwSize; // 数据大小
DWORD dwAddress; // 数据的相对于文件头的偏移量
DWORD dwNext; // 下一个节点有对于文件头的偏移量
} TFileInfo,*PFileInfo;
使用方式 :
每次启动程序的时候,将文件头TFileHeader 读入到内存,这样可以获得队列的头与尾和节点的数量.
写入一个节点 :
SetFilePointer(hFile,PFileHeader->dwTail,NULL,FILE_BEGIN);
// 写入节点(假设节点为一个100字节大小)
TFileInfo.dwSize = 100;
TFileInfo.dwAddress = PFileHeader->dwTail;
TFileInfo.dwNext = 0;
// 写入节点头
WriteFile(hFile,&TFileInfo,sizeof(TFileInfo),&dwWritten,NULL);
// 写入文件数据
WriteFile(hFile,&FileData,100,&dwWritten,NULL);
// 更新 队列头结点的信息
PFileHeader->dwTail = sizeof(TFileInfo) + 100; // 计算出新的偏移
PFileHeader->dwCount++;
// 保存队列头节点信息至文件
WriteFile(hFile,PFileHeader,sizeof(TFileHeader),&dwWritten,NULL);
// 写入一个节点完毕
读取一个节点 :
SetFilePointer(hFile,PFileHeader->dwHeader,File_BEGIN);
// 读取节点头信息
ReadFile(hFile,&TFileInfo,sizeof(TFileInfo),&dwRead,NULL);
// 读取数据
//SetFilePointer(hFile,TFileInfo.dwAddress,NULL,FILE_BEGIN); // 可以考虑不需要定位直接读取,因为节点头与节点内容是连续存储的
ReadFile(hFile,FileBuffer,TFileInfo.dwSize,&dwRead,NULL);
删除一个节点 :
// 可以考虑使用下表来删除,也可以考虑使用关键字来删除(可以在TFileInfo 中增加一个识别关键字),删除数据之后并不重新移动其它节点的内容
DWORD dwPrev; // 记录上一个节点偏移,假设要删除节点K(delete FileQueue[k])
// 删除的是头节点 if ( k == 0 ) { SetFilePointer(hFile,PFileHeader->dwHeader,NULL,FILE_BEGIN); ReadFile(hFile,&TFileInfo,sizeof(TFileInfo),&dwRead,NULL); PFileHeader->dwHeader = TFileInfo.dwNext; PFileHeader->dwCount--; } else { SetFilePointer(hFile,PFileHeader->dwHeader,NULL,FILE_BEGIN); ReadFile(hFile,&TFileInfo,sizeof(TFileInfo),&dwRead,NULL); dwPrev = PFileHeader->dwHeader; // 记录上一个节点 for ( int i = 1; i < PFileHeader->dwCount; i++ ) { // 读取上一个节点头信息 SetFilePointer(hFile,dwPrev,NULL,FILE_BEGIN); ReadFile(hFile,&TFileInfo_Prev,sizeof(TFileInfo),&dwRead,NULL); if ( k == i ) { // 读取待删除节点的节点头 SetFilePointer(hFile,FileInfo_Prev.dwNext,NULL,FILE_BEGIN); ReadFile(hFile,&FileInfo_Delete,sizeof(TFileInfo),&dwRead,NULL); TFileInfo_Prev.dwNext = FileInfo_Delete.dwNext; // 删除当前节点 break; } else { dwPrev = TFileInfo_Prev.dwAddress; } } } 压缩文件 : // 针对删除了一个节点之后,并不会删除这个节点的内容,导致文件的容量越来越大,可以使用重新建立一个文件的方式来压缩文件 方法 : 遍历整个队列,然后把这个队列中的有效节点(包括节点头 + 节点内容)重新按照排列写入到其它的一个文件中,待全部写入完毕.然后删除旧的文件, 再将新的文件rename 成旧的文件名,达到压缩文件的目的 队列的排序与查找 : // 在程序第一次启动的时候,可以将整个队列的节点头(不包括节点内容)全部装载到内存,然后按照某种方式排序. // 在排序好之后的查找就很快了. // 当查找到某一个节点之后,直接使用这个节点的dwAddress 就可以定位到文件中这个节点的内容,使用ReadFile 读取出来就可以了 呵呵 : 一个弱智的想法,请大家讨论 [解决办法]
探讨 内存式数据库就算了,如果用内存的话我就直接使用队列了,呵呵[解决办法] 樓主要的是一個先進先出隊列queue.管理是比支持隨機讀取的 vector 容易些。
看數據量大小。
如果數據量太大, > 1G , 用多個文件會容易做些。如果數據總量小於10M,也就沒什麼好擔心的了。
可以考慮每個文件約 10M 左右,可以保證讀取速度,用一個索引文件來標識文件塊及隊列節點。
因為節點是自行控制的,所以就能做到刪除節點而不用重寫文件,只要重寫索引(先進先出隊列的頭尾指針)即可。讀寫時也能很容易計算到要讀的數據塊,廢棄的數據塊回收重用即可。這樣編程難度不大,關鍵在於索引的格式設計,因為索引文件是要全部讀入內存的。
如果數據時大,都放在同一文件中的話,就要熟悉底層的文件操作了。但使用底層的文件操作,直接操作硬盤,速度確實會更快些,要針對FAT32 NTFS等格式的不同而寫不同的程序,編程難度較大。光盤ISO文件及GHOST克隆文件就是超大文件的例子。
自行編程直接讀取foxbase文件都比通過用 foxbase引擎讀取來得快,所以使用foxbase也就沒有執行速度上的優勢,但能實現快速編程的目的。
在queue這樣簡單的結構上,只需要支持queue頭尾操作的話,自行編程要比用任何一個數據庫都快得多。因為數據庫都是支持隨機讀取的。
[解决办法] 我曾經的做法是,使用文件頭索引+鏈的方式實現,但文件索放在文件尾部,這樣不怕文件大小超過文件索引表限制。
[解决办法] 建议用 SQLite.
[解决办法] 首先,我先否定前面一部分兄弟的方案,要么内存开销大,要么文件会无限增长;
因为你的数据结构是个队列,队列成员是块,块大小不一定(还可能比较大),
所以,你可以这样设计:
首先,把文件分成一个一个的页,每个页的大小是固定的;(比如4k字节一个页)
一个数据块可能使用多个页,所以,需要为每个块建立一个[页表];
还需要一个垃圾回收机制,就是全局的[垃圾页表];
如果要加入一个块,按照块大小去[垃圾页表]申请页,如果[垃圾页表]里面不足,就建立新页;
如果要释放一个块,就把这个块的页加到[垃圾页表]里面去;
这样一来,我们就可以在文件里面随意加块删块了;
最后,别忘记在文件前面开辟一个固定大小的空间,存储一个[队列块表],一切就ok了;
[解决办法] 好复杂!
就用access好了,建个表用个自增长字段当主键;
选择队首时就直接用select top 100 * from table 来查;
插入数据到队尾就是直接 insert 语句即可,
效率怎么样未知,就是简单而已
[解决办法] 和上面某些观点类似,建立若干相同大小的文件,比如1M,然后用一个文件索引。
以文件为单位,如果要存2.1M数据,就占3个文件。删除的时候删除对应文件就行。
这种方式类似于FAT32存储,个人认为是最快的方式。
------解决方案--------------------
1:感觉是在设计一个数据库系统
2:如果支持索引之类的话,看来需要考虑存储结构,而读写嘛,应该都是直接的API了,最重要的地方应该是在数据文件的存储结构方面,能够协助快速定位的模式。没有阅读过mysql的代码,如果看一下他的文件存储数据结构,我想一定会有很大收获
3:xml出现之后,很多人开始使用xml存储数据库,个人感觉大部分时候都是夸大了xml的能力,xml除了结构方便定义之外,在存储以及定位方面效率很低,两种模型都非常的不利于检索
4:对于多线程读写的时候,必须加锁,mysql中在写入数据都是
LOCK TABLES `cc_alarm` WRITE;
//operator
UNLOCK TABLES;
所以,同样也是应该加锁,另外记得刀客在看到我的一个操作mysql的类的时候,提出了我没有考虑事务过程,我想如果考虑事务的话,我想应该是在Log中保留此次执行的所有模式,在某个失败通过Log回滚。
5:大家继续