V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
join
V2EX  ›  Linux

如何修改一个大文件?

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

    有的游戏存档是这样做的,虽然没到 1g 这么大,但是这样都是相同长度,应该是因为程序写起来方便吧。
    join
        9
    join  
    OP
       2021-06-02 08:55:14 +08:00 via iPhone
    @mingl0280 是的,感谢指点。我确实这块没学好,赶紧学习去。如果按你这样说的,sqlite 岂不是数据库越大,性能越差?但看起来好像不是这样的,他们也没用 lsm,只是用 b 树。
    join
        10
    join  
    OP
       2021-06-02 08:56:12 +08:00 via iPhone
    @kokutou 这个还是会越写越慢吧?中间插入后面全部要改。
    jorneyr
        11
    jorneyr  
       2021-06-02 10:22:32 +08:00
    sqlite 之类的,创建一个大一些的文件,写入的数据都是从文件中预定一段然后写入,并不是顺序的写入。
    kokutou
        12
    kokutou  
       2021-06-02 11:03:17 +08:00 via Android
    @join 是一段固定长度的 0,写入的时候就写这么长,覆盖写入。
    sxw
        13
    sxw  
       2021-06-02 15:44:08 +08:00
    @join 可以用 "r+" 打开文件,seek 到要修改的地方。https://es2q.com/blog/2019/02/22/modify_file_without_rewrite/
    join
        14
    join  
    OP
       2021-06-02 16:58:19 +08:00 via iPhone
    @sxw 仔细再看各位大佬的讨论,这个问题没那么简单的。
    sxw
        15
    sxw  
       2021-06-02 17:02:36 +08:00
    @join 抱歉没写清楚,我回复的是 #10
    liuxu
        16
    liuxu  
       2021-06-02 21:12:28 +08:00
    1 个 G 不是大文件吧,现在内存条再怎么涨价也就 300 块钱 8G,买一个插上
    mingl0280
        17
    mingl0280  
       2021-06-02 22:18:59 +08:00 via Android
    @join SQLite 数据库确实越大性能越差,不知道你这个看起来不是这样是哪来的……BTree 就是维护的 Pager 索引,也不知道你说的只用 b 树是哪来的。
    join
        18
    join  
    OP
       2021-06-02 23:52:09 +08:00 via iPhone
    @mingl0280 不是抬杠,官网说了最大支持 10tb,他们也确实用的是 b tree 。
    @liuxu 写代码不能有这种想法,万一是 10g 100g 1t 的文件呢?
    liuxu
        19
    liuxu  
       2021-06-03 00:58:43 +08:00
    @join 万一 1PB 呢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2930 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 14:02 · PVG 22:02 · LAX 07:02 · JFK 10:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.