请教高效分割 txt 大文件(100GB)方案( Python , Java , shell) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Nick2VIPUser
V2EX    程序员

请教高效分割 txt 大文件(100GB)方案( Python , Java , shell)

  •  
  •   Nick2VIPUser
    nickliqian 2020-04-09 18:16:29 +08:00 7249 次点击
    这是一个创建于 2010 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个 100G 的 txt 文件,按指定行内容分割为若干个文件,如何处理?
    例如:这个文件有几亿行,其中会有大概 20 行的内容是”my content\t“
    想以这个内容将文件分割开,如何在内存 16GB 的电脑上实现呢?

    40 条回复    2020-04-23 09:46:33 +08:00
    xupefei
        1
    xupefei  
       2020-04-09 18:18:31 +08:00 via iPhone   2
    边读边写,线性时间,内存占用超低。
    U7Q5tLAex2FI0o0g
        2
    U7Q5tLAex2FI0o0g  
       2020-04-09 18:21:11 +08:00   1
    歪楼,为啥会有这样的文件啊,可怕
    alan0liang
        3
    alan0liang  
       2020-04-09 18:21:15 +08:00 via Android   1
    xupefei
        4
    xupefei  
       2020-04-09 18:22:11 +08:00 via iPhone
    如果是 ssd 的话,可以把文件分块后多线程扫描来拿到分隔符位置。对于每个位置,起一个线程从那个位置开始边读边写,直到遇到下一个分隔符。
    vuuv
        5
    vuuv  
       2020-04-09 18:22:23 +08:00 via Android   1
    根据内容分割需要用 csplit 。
    alan0liang
        6
    alan0liang  
       2020-04-09 18:23:05 +08:00 via Android
    哦看错了 一楼流处理正解
    luckyrayyy
        7
    luckyrayyy  
       2020-04-09 18:28:13 +08:00
    你的难点在哪?如果说只是不能一次性读到内存,那就一边读一边处理呗。是否还有其他困难?
    vuuv
        8
    vuuv  
       2020-04-09 18:32:15 +08:00 via Android
    毕竟只会生成 20 多个文件,都是顺序大块读写。
    如果可能,写的目的地不要放在同一块磁盘上。
    复制到 SSD 后能加快处理时的读取速度。但是你复制也要时间。自行决策吧。

    提前创建个小文件测试下命令行参数效果。
    Nick2VIPUser
        9
    Nick2VIPUser  
    OP
       2020-04-09 18:42:35 +08:00
    @xupefei 是的~我的想法是读 2GB,然后逐行写入,依次循环。我打算先计算预计需要的时间...如果是读一行写一行,算了一下时间不能承受。
    Nick2VIPUser
        10
    Nick2VIPUser  
    OP
       2020-04-09 18:43:23 +08:00
    @littleylv 因为自己的某些 zhizhang 操作...哭了
    Nick2VIPUser
        11
    Nick2VIPUser  
    OP
       2020-04-09 18:43:46 +08:00
    @vuuv 我回去试试
    yxt
        12
    yxt  
       2020-04-09 18:45:21 +08:00 via Android
    emeditor?
    Nick2VIPUser
        13
    Nick2VIPUser  
    OP
       2020-04-09 18:45:53 +08:00
    @luckyrayyy 目前准备是按 2GB 分批读,然后逐行判断和写入,目前还在找 python 相关的 api 进行实现
    Nick2VIPUser
        14
    Nick2VIPUser  
    OP
       2020-04-09 18:46:41 +08:00
    @vuuv 是了~我打算放在 ssd 上跑一下
    pcbl
        15
    pcbl  
       2020-04-09 18:50:53 +08:00 via Android
    反正才 100g 如果只是一次性处理的话,一行一行的读取都行,然后预估下内存最大可以放多少行在超出之前写入到文件
    yxt
        16
    yxt  
       2020-04-09 18:50:53 +08:00 via Android
    emeditor 最大支持大概 250g 先搜索,bookmark all,然后 split done
    aptupdate
        17
    aptupdate  
       2020-04-09 18:52:11 +08:00 via iPhone
    在 SSD 里面把线程拉满然后边读边写,你是想分割成 20 个文件吗?感觉分割完 20 个 5GB 大小的文件后续处理也够呛。好奇 100GB 的 txt 文件是什么东西……
    also24
        18
    also24  
       2020-04-09 18:53:40 +08:00
    提醒下,边读边写方案,如果你是 HDD,最好分开在两个硬盘进行,或者读取一长段数据( x GB )后再一次性写入,避免大量的随机读写降低 IO 性能。

    如果是 SSD 的话可以不用管这个。
    caola
        19
    caola  
       2020-04-09 18:55:43 +08:00
    逐行读,判后再写入新文件……
    line
        20
    line  
       2020-04-09 20:34:35 +08:00
    cat | awk
    rayray314
        21
    rayray314  
       2020-04-09 21:07:03 +08:00 via Android
    emeditor
    cheng6563
        22
    cheng6563  
       2020-04-09 21:47:00 +08:00
    就算是 HDD 同盘复制缓冲区给个 50M 就行了,没必要上 GB
    lululau
        23
    lululau  
       2020-04-09 22:20:20 +08:00
    zsh:

    offsets=($(echo 1; grep -b 'my content' big.log | cut -d: -f1; stat -c%s big.log))
    for ((i=1; i < $#offsets; i++)) { echo dd if=big.log of=small.$i.log bs=1 count=$[$offsets[i+1]-$offsets[i]] skip=$[$offsets[i]-1] }
    lululau
        24
    lululau  
       2020-04-09 22:20:49 +08:00   1
    zsh:

    offsets=($(echo 1; grep -b 'my content' big.log | cut -d: -f1; stat -c%s big.log))
    for ((i=1; i < $#offsets; i++)) { dd if=big.log of=small.$i.log bs=1 count=$[$offsets[i+1]-$offsets[i]] skip=$[$offsets[i]-1] }
    lniwn
        25
    lniwn  
       2020-04-09 23:32:28 +08:00   1
    mmap 内存映射,一个映射读的文件,一个映射写的文件,64mb 一个块,一个块 commit 一次,hdd 没有任何压力。
    qinrui
        26
    qinrui  
       2020-04-09 23:51:57 +08:00 via iPhone
    awk 一行一行的读
    scriptB0y
        27
    scriptB0y  
       2020-04-09 23:58:03 +08:00
    直接用 fileinput,无论按照什么逻辑分割都能三五行搞定

    https://docs.python.org/3.8/library/fileinput.html
    rrfeng
        28
    rrfeng  
       2020-04-10 00:13:57 +08:00 via Android
    sd
    awk
    都能轻易完成…
    popbones
        29
    popbones  
       2020-04-10 00:27:12 +08:00
    msg7086
        30
    msg7086  
       2020-04-10 00:35:15 +08:00
    读进 buffer 然后扫描分割就行了吧。
    一次读比如说 128M,扫描完,再读下一块,如果能多线程跑更好,IO 扔给子线程。
    marcomarco
        31
    marcomarco  
       2020-04-10 07:33:56 +08:00 via iPhone
    txtkiller 了解一下
    sxfscool
        32
    sxfscool  
       2020-04-10 08:44:11 +08:00
    bufio
    dantegg
        33
    dantegg  
       2020-04-10 08:53:40 +08:00
    sed +1
    BlackBerry999
        34
    BlackBerry999  
       2020-04-10 10:01:05 +08:00
    按行读,边读边写。
    matepi
        35
    matepi  
       2020-04-10 10:06:02 +08:00
    边读边写不就完了么

    真正难的是让你快速定位到随机第 n 行的内容
    zz554952942
        36
    zz554952942  
       2020-04-10 10:35:14 +08:00
    go
    开一个生产者协程 负责读取文本 读到换行符则塞到通道上
    然后开一定量的消费者协程负责取然后写入
    llussy
        37
    llussy  
       2020-04-10 11:15:05 +08:00
    split -b 10G log.txt newfile
    feelinglucky
        38
    feelinglucky  
       2020-04-10 12:18:30 +08:00
    @littleylv 以前很多日志都还存文件系统的时候,一天就要好几百 G 了…
    augustheart
        39
    augustheart  
       2020-04-10 14:07:18 +08:00
    逐字节线性读入就行。你只需要长度为“my content\t”的缓存就行
    JimiJimi
        40
    JimiJimi  
       2020-04-23 09:46:33 +08:00
    流处理,一行一行读
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3839 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 05:11 PVG 13:11 LAX 22:11 JFK 01:11
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86