如何修改一个大文件?

2021-06-01 19:54:31 +08:00
 join
假设我有一个 1G 的大文件,我要修改中间某个地方的 1 个 byte,这个时候可以用 file.seek 定位到具体的位置,再用 append 模式写。
但如果我要删除一段内容,再添加一段新的内容呢?(内容的长度不确定),这个时候是怎么做的?
一个编辑器如何做到这个功能?
一个像 sqlite 这样涉及到大量读写的数据库系统又是如何做到的?
照 posix 现有的 api 来看要么只能全读内存再调用 fsync 写入。或者用 mmap 这种底层的 api 提高写入速度。有相关的书籍介绍这个问题的吗?
3343 次点击
所在节点    Linux
19 条回复
join
2021-06-01 20:01:14 +08:00
WAL 是不是解决这个问题用的?
no1xsyzy
2021-06-01 22:18:35 +08:00
从块文件的层面去考虑的话,长度改变后面的全部都要重新写一遍。
文件系统可能允许文件分为多个块或者簇,它们可以变长的话可能可以解决。
sqlite 说是有并发问题的…… 应当也是全读全写?可能有 padding 空间?可能允许乱序?
lululau
2021-06-01 22:21:00 +08:00
做不到,文本编辑器要么是重新写一遍,要么是用一个新文件替换到原有文件
join
2021-06-01 22:24:18 +08:00
@lululau 感谢,我纠结了一天也没在网上找到合适的方案。原来的确是我的想法有问题。
XiaoxiaoPu
2021-06-01 22:58:12 +08:00
数据库会尽量避免改变长度。可以看下 LSM 树的原理,将磁盘随机写操作转化为顺序写操作,相比 B+树的存储结构好理解一些。
coldear
2021-06-02 02:54:08 +08:00
长度不确定没发 in place, 关系型数据库都字段都是固定长度的。
mingl0280
2021-06-02 03:12:17 +08:00
数据库原理没有学好就是这样的。
数据库文件本身内部会有数据库软件的分页,每个分页的长度固定,然后数据库软件会在文件前部保持一个对页的索引,这样数据库的 IO 就只需要读写一个页(如果不够长会重新分配页,一般在文件尾部直接增长)。效率比重写一大截文件好很多。
但是,如果你是一个普通的二进制文件,那么你只能把后半截保存下来然后删掉重写……
kokutou
2021-06-02 07:06:15 +08:00
有个办法是长度对齐,空余的填 0 。
然后写入就是一块一块的写入。自己计算末尾 0 的个数。

有的游戏存档是这样做的,虽然没到 1g 这么大,但是这样都是相同长度,应该是因为程序写起来方便吧。
join
2021-06-02 08:55:14 +08:00
@mingl0280 是的,感谢指点。我确实这块没学好,赶紧学习去。如果按你这样说的,sqlite 岂不是数据库越大,性能越差?但看起来好像不是这样的,他们也没用 lsm,只是用 b 树。
join
2021-06-02 08:56:12 +08:00
@kokutou 这个还是会越写越慢吧?中间插入后面全部要改。
jorneyr
2021-06-02 10:22:32 +08:00
sqlite 之类的,创建一个大一些的文件,写入的数据都是从文件中预定一段然后写入,并不是顺序的写入。
kokutou
2021-06-02 11:03:17 +08:00
@join 是一段固定长度的 0,写入的时候就写这么长,覆盖写入。
sxw
2021-06-02 15:44:08 +08:00
@join 可以用 "r+" 打开文件,seek 到要修改的地方。https://es2q.com/blog/2019/02/22/modify_file_without_rewrite/
join
2021-06-02 16:58:19 +08:00
@sxw 仔细再看各位大佬的讨论,这个问题没那么简单的。
sxw
2021-06-02 17:02:36 +08:00
@join 抱歉没写清楚,我回复的是 #10
liuxu
2021-06-02 21:12:28 +08:00
1 个 G 不是大文件吧,现在内存条再怎么涨价也就 300 块钱 8G,买一个插上
mingl0280
2021-06-02 22:18:59 +08:00
@join SQLite 数据库确实越大性能越差,不知道你这个看起来不是这样是哪来的……BTree 就是维护的 Pager 索引,也不知道你说的只用 b 树是哪来的。
join
2021-06-02 23:52:09 +08:00
@mingl0280 不是抬杠,官网说了最大支持 10tb,他们也确实用的是 b tree 。
@liuxu 写代码不能有这种想法,万一是 10g 100g 1t 的文件呢?
liuxu
2021-06-03 00:58:43 +08:00
@join 万一 1PB 呢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/780688

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX