大文件定位某一行?

2017-08-22 19:13:37 +08:00
 kaiser1992
现有一个很大的文件(比如 40G 的文本),假如我随机定位某一行,怎么样实现最快(时间和空间)?
希望 V 友们想什么说什么,畅所欲言
8704 次点击
所在节点    程序员
81 条回复
EchoUtopia
2017-08-22 22:31:24 +08:00
awk
rrfeng
2017-08-22 22:34:54 +08:00
随机定位是什么鬼?

你随机给个数字,我输出行号等于这个数字的行?
0ZXYDDu796nVCFxq
2017-08-22 22:47:53 +08:00
@kaiser1992 索引表怎么可能比原文件大
你要建立的是行数和偏移量两个值
ynyounuo
2017-08-22 23:17:18 +08:00
Ctags
不过 40G ???这是什么文本啊
am241
2017-08-22 23:28:24 +08:00
扫一遍,记录下每个换行符的位置,然后二分搜索就够了
qian19876025
2017-08-23 00:19:43 +08:00
@Fishdrowned 那你还是要把东西大部分读进内存啊 难不成你不用? 难不成你知道硬盘中怎么存储的? 不读进内存你来搞
qian19876025
2017-08-23 00:23:16 +08:00
当然如果你的数据是 线性排序 或者 hash 固定 没有冲突的 那是另外的话了
qian19876025
2017-08-23 00:25:41 +08:00
如果每行数据是 固定大小的 或者能直接算出偏移值的 那也可以直接取出
watzds
2017-08-23 00:28:15 +08:00
顺序读取文件似乎每秒几百兆,30g 遍历大概得几分钟吧。
还有个问题,30g 文件中间加一行会怎样?😁
什么需求需要单机存储 30g 大文件?可能一开始就不应该这么存
FanWall
2017-08-23 00:38:06 +08:00
@gstqc #23 都不用想最坏情况了,假设一个字节一行,换行符是\n,40G 光记录偏移值就要 160G 了(UL 是装不下的),如果再考虑全部空行…… 320G ?

@qian19876025 #26 我觉得他是对的,索引是有组织的,是可以计算的,只读需要的一小段就行了。
Fishdrowned
2017-08-23 01:31:54 +08:00
@qian19876025 #26 大哥,我不知道你是怎么理解的,遍历的时候,读一小段文字进内存,获取到换行位置之后就可以释放了然后读下一段了啊,难道你要一直放在内存里?
Fishdrowned
2017-08-23 01:48:13 +08:00
打个比方,楼主有一本一万页的书,想随机精确地定位到第几个段落。

我一个人数太慢,于是叫来 20 个人(多线 /进程),每人撕走 2000 页,让他们各自统计自己的 2000 页里面各有多少段。

然后我等这 20 个人数完了,汇总整理一下做个索引,我不就知道这本书有几段了?

每个线程做的事情没有什么花巧,就是遍历,只不过是适合并行计算,把时间分摊了。

至于内存,每个人都不用把 2000 页背下来啊,他只要知道每个段落位置分布在哪里就可以了,内存不够就拿笔写下来。
t6attack
2017-08-23 02:48:02 +08:00
“随机定位某一行” ,, 究竟是 “随机定位一行”?还是 “定位某一行”?
前者其实简单多了,用 64 位文件指针,随便定位个位置,向前、向后找到换行符就是了。感觉实际应用中,需要的应该就是前者。
t6attack
2017-08-23 02:51:10 +08:00
也不对。这样结果并不随机。内容多的行更容易被定位到。
ufjfeng
2017-08-23 04:54:11 +08:00
知道行号的话,awk 就行,性能不详

awk 'NR=n {print $0}'

n 是行号
ufjfeng
2017-08-23 04:55:02 +08:00
awk 'NR=n {print $0}' filename

楼上忘了写文件名
linux40
2017-08-23 07:15:24 +08:00
40g 为什么是一个文件呢。。。
libook
2017-08-23 08:29:30 +08:00
定位某一行就是定位某一个换行符,和定位某一个字母 a 或定位某一个数字 1 是一样的,都需要遍历整个文件,除非是像数据库一样做索引优化。
个人以为 linux 提供的指令效率极高,如果还是满足不了需求的话建议想办法建起换行符的索引。
wangyucn
2017-08-23 08:36:53 +08:00
@kaiser1992 建索引需要时间,存索引需要的空间最后貌似比源文件都大了把

不会,索引不一定是完全的。可以每隔 1000 行建一个索引。查找时先用索引定位到文件偏移,然后稍微做一点遍历。
wangyucn
2017-08-23 08:40:32 +08:00
索引例子:
行数(单位千) 文件偏移
1 456789 (第 1000 行的文件偏移)
2 1234567 (第 2000 行的文件偏移)
3 2345678 (第 2000 行的文件偏移)
4

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

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

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

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

© 2021 V2EX