文件操作的效率,欢迎讨论和赐教

whoho 2005-09-08 04:51:07
其实讨论时希望能够一般化一些

暂只考虑二进制文件操作方式。

考虑这么一个操作,在往一个文件追加(没有其他操作类型)时,
实际上运行时间效率与所处的操作系统可能有密切关系,但总的说来,
在通常流行的操作系统上,能否达到常数时间复杂度?也就是说,
添加一段确定大小的数据,运行时间会不会独立于原有文件的尺寸,而是常数时间?

以下三个比较相关的问题:
(1)在文件当中的某个位置插入一个“记录”,通常程序的写法中,都会有将
从所插入位置开始的所有剩余数据进行“后移”的操作;
(2)如果是删除记录,又会有将删除位置后方的所有记录前移的操作;
(3)在(2)中的假设是可以对文件进行“截尾”的情形,如果文件系统没有
提供直接“截尾”的功能,可能意味着要把原有的文件拷贝到新的文件中,
但不复制要删除的记录。
这三个问题中,如果我要操作的记录的位置是随机的,那就需要常数复杂度O(n),
有没有能够克服这种问题的办法呢?或者说,要达到的话必须写针对各个不同
文件系统的程序?
...全文
296 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
Jagen在路上 2005-09-09
  • 打赏
  • 举报
回复
这一般需要文件系统提供帮助,我的知识也有限,仅对我所熟悉的Linux和Windows系统说一下。
1)加快文件访问速度,达到常数时间追加,我认为,简单的mmap(Unix/Linux)和CreateFileMapping(Windows)就可以办到,先将现有文件映射到内存,这个时候就可以通过指针操作定位到文件末尾处,追加数据也仅需要普通的内存复制操作就能完成,最后将内存内容重新影射为磁盘即可。
2)在文件中添加或删除记录也可以说能够完成近似O(1)的时间复杂度。这取决于文件在磁盘中的存储结构。我们知道,Linux的ext3文件采用的是类似于链表的节点方式(inode),每一个节点有其固定大小,可以采用O(1)时间复杂度计算出要修改的节点,那么其余的操作仅对于本块进行操作即可,如果添加数据,块增加超过的单块的长度,那么就增加一个新块,将这个新块添加到超级块中即可,同样删除的数据使得一个块失效了,将这个块删除即可。同样的办法也可以在Windows的Fat32或Fat16下操作即可,至于NTFS一直没有时间研究,因此不是很清楚,但是我想也会有同样的办法。
James_ht 2005-09-09
  • 打赏
  • 举报
回复
(1)在文件当中的某个位置插入一个“记录”,通常程序的写法中,都会有将
从所插入位置开始的所有剩余数据进行“后移”的操作;


这个问题我以前碰到过。我是这样解决的。
对文本文件建立 一个对应的二进制索引文件,直接在文件插入记录即可。插入记录时更变索引文件。查找时用二分法查找索引文件对应的记录行数。找到后处理它。
  • 打赏
  • 举报
回复
还是要用索引的办法, 在索引中记录ABSOLUTE地址, 在删除时仅仅做标记即可. 在"适当"的时候提交做PACK的操作.
Jagen在路上 2005-09-09
  • 打赏
  • 举报
回复
这样,如果楼主有嵌入式系统的要求,楼主也有能力编写适配器的话,我倒有一个建议,不知道楼主是否认可。
各位可能都知道ACE这个准C++标准库,好多人可能认为它仅是作为网络编程的产品,但是他得很多的性却可以满足楼主的需求,即平均O(1)时间复杂度操作文件。它拥有几个内存分配器和与这些内存分配器相适配的hash_map结构。其中有一个内存分配器就是基于内存映射文件的,这就说明hash_map所产生的内存结构以及hash_map本身可以被转存到一个文件上,同时这个内存分配器也提供了一个地址中立的策略选项。因此不用担心其在向内存映射后原有分配指针失效的问题。这个分配器及hash_map的定义如下:
typedef ACE_Allocator_Adaptr< ACE_Malloc_T< ACE_MMAP_MEMORY_POOL, ACE_Null_Mutex, ACE_PI_Control_Block> > ALLOCATOR;
typedef ACE_Hash_Map_With_Allocator< int, class Record > HASH_MAP;
class Record是具体处理记录操作的类。

由于详细说明这些分配器需要很大的篇幅,我在这里不复述了。请楼主参考ACE的相关著作。
hjf1010 2005-09-09
  • 打赏
  • 举报
回复
数据库在底层上也是操作文件,只不过采用了比较好的方法,比如分区,建立索引等等.
数据库之所以出现就是要解决大量信息在普通文件中存储带来的:存取效率低,杂乱无章,维护不方便,安全性差等问题.
文件操作本来就是效率很低的,所以一些要求及时响应的系统对文件操作甚至数据库操作次数都严格限制,还要对数据库进行优化.
许多大型数据库在进行数据更新,查询等操作的时候都是将数据读到内存进行操作,完了后commit.
国内某著名IT公司在这方面针对一些不经常更新,使用频率高的数据设计了内存表,常驻内存,效率的确得到了很大的提高.
whoho 2005-09-09
  • 打赏
  • 举报
回复
现在我把问题放宽一点儿,看看各位有没有办法:
我现在不要求所有信息放在一个文件里头,只要能够达到常数效率的添加、删除、追加
三种操作即可。当然对于二进制定长记录文件,修改记录我觉得肯定还是可以达到
常数复杂度的,这作为默认要求。

另外呢,我想尽量不把数据部分拆分为太多个文件,类似于数据库系统中的“元数据”
和“索引”(如果有的话)倒是可以有多个
whoho 2005-09-09
  • 打赏
  • 举报
回复
嘉俊兄提供的办法,有些地方可能我的理解暂时也有误差,
我想提点儿疑问:
(1)关于追加,假设文件大小是N,如果先把文件映射到内存,那么不就以为着
引起O(N)次的硬盘读和O(N)次的写吗?这样似乎得不偿失。嘉俊兄的意思是否
是:多次的追加操作的话,就全部在内存映射文件中进行,待全部完成以后才写入
文件中?不过这样似乎还不如把全部记录先在内存中汇总为一块,然后写入文件中去,
此时也就是在文件尾端进行一次性的添加操作。虽然不认同这种方法,但觉得如果
还有其他各种操作也需要完成的话,放在内存中可能不错,但要避免大文件的情形。

(2)现在我也只是考虑定长记录。看了上面的阐述,觉得也挺有道理的,不过,
我担心记录大小跟文件块block尺寸不匹配的时候可能不是很好办。如果真的直接
调用这些操作系统的api,我可能得用C++模板写几个配接器了。如果不写针对各个
操作系统的话,我该怎么办呢?--主要是,我有时候还要写些嵌入式系统的代码,
某些细节并不清楚,或者这种系统中没有复杂的文件系统。还是说:办不到?

现在我把问题放宽一点儿,看看各位有没有办法:
我现在不要求所有信息放在一个文件里头,只要能够达到常数效率的添加、删除、追加
三种操作即可。当然对于二进制定长记录文件,修改记录我觉得肯定还是可以达到
常数复杂度的,这作为默认要求。
Jagen在路上 2005-09-09
  • 打赏
  • 举报
回复
另外补充一句,好多路由器的嵌入式软件就是采用ACE开发的。
Jagen在路上 2005-09-09
  • 打赏
  • 举报
回复
哈哈,不要担心这个问题,ACE本来就是可以支持嵌入式开发的。当然,你所接触过的开发平台不知道是什么CPU,它的C++不支持模板可能会比较不爽,那么也可以利用gcc作为它的编译器,目前大多数的硬件平台,gcc都有支持,我想只要你的嵌入式CPU还算常用的话,仅需编译一个交叉版本的gcc即可。那么就什么问题都解决了。
caocheng8230 2005-09-09
  • 打赏
  • 举报
回复
在这里我只能学习,学习再学习.不过是不交学费的,哈哈!!!
whoho 2005-09-09
  • 打赏
  • 举报
回复
嘉俊兄关于ACE的建议,我想我该好好去了解一下,不失为一个简单易行的方案。非常感谢。

稍微不爽的是,在嵌入式系统中我不太好弄ACE,毕竟,我刚刚碰过的一个嵌入式开发平台,
连C++模板也不支持,即使支持,要让ACE能在目标系统上稳健地运行,可能需要相当多的精力
作移植。
whoho 2005-09-09
  • 打赏
  • 举报
回复
Erik兄,谢谢你的回答,这个方法我也想到过。这个方法其实还可以类似地
解决删除记录的问题:借鉴前面有位兄台的方法,在“数据文件”中把相应
记录作个“删除”标记,然后把相应的索引删除掉即可,甚至,数据文件可以
不改,只在索引上“删除”。

这个方法不足的地方是:数据会比较依赖于索引,如果索引损坏或丢失,就
可能让数据的有效性或者时效性受到影响;或者,因为其他偶然性因素,致使
索引和数据的一致性受到影响。另外一个,就是可能什么时候去
重新整理数据文件的时机不太好把握,不过这个倒是比较与实际需求相关。

不论怎么说,这都是目前比较好的办法了。希望各位继续发表高见。
xlsue 2005-09-08
  • 打赏
  • 举报
回复
关注...
“楼主应该去参考数据库的实现,存放数据库的地方本质上来说其实是一个文件,设计数据库的时候,肯定要考虑到跟你的需求相关的情况,数据库的实现应该有很好的答案的。”
不失为一个办法,楼主研究有了眉目。拿出来给大家也研究研究?
qingyuan18 2005-09-08
  • 打赏
  • 举报
回复
惭愧,做东西时很少考虑到效率得问题.....
jsjjms 2005-09-08
  • 打赏
  • 举报
回复
偶也没有好法子,近来就在做文件系统,解析是晕得一塌糊涂...,效率也让人头疼...
megaboy 2005-09-08
  • 打赏
  • 举报
回复
楼主应该去参考数据库的实现,存放数据库的地方本质上来说其实是一个文件,设计数据库的时候,肯定要考虑到跟你的需求相关的情况,数据库的实现应该有很好的答案的。
healer_kx 2005-09-08
  • 打赏
  • 举报
回复
我觉得文件的效率可以不考虑,只要在编程的时候不做傻事就可以了,反正它基本上仅仅比Moden快... ...
zhouhuahai 2005-09-08
  • 打赏
  • 举报
回复
这个问题,以我目前的水平,不能解决,只有用你说出来的移动的方法.

64,632

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧