open()读取文件问题(假设思考题).

2021-01-13 17:28:51 +08:00
 zyb201314
1, in.txt 文本文件非常非常大,(意为着不能一次读取到内存中).
2, in.txt 文件没有换行,都在一行内,意为着直接使用 readlines 无效.
3, in.txt 里内都是英文及标点符. 需要统计英文词频到 output.txt 文件.

问: 下面通过迭代器 iter()函数封装的代码,能否解决,上面内容不足问题? 如不能,该如何处理?若可以, 该如何验证,内存使用量. 请大佬指教,谢谢!!
代码如下:

from collections import defaultdict
import re

a=iter(re.split('[^\w]+',open("in.txt","r").read()))
#此条是否可避免使用内存过大?

d=defaultdict(int)
for b in a:
d[b]+=1

out=dict(sorted(d.items(),key=lambda x:x[1],reverse=True))

f=open("output.txt","w")
f.write(repr(out))
f.close()
2300 次点击
所在节点    Python
11 条回复
ysc3839
2021-01-13 17:33:52 +08:00
不能,因为 f.read() 就会把整个文件读到内存。
fuis
2021-01-13 18:58:00 +08:00
我看到 split 和 read 就不看了
zyb201314
2021-01-13 19:13:22 +08:00
@ysc3839 谢回复
liprais
2021-01-13 19:43:09 +08:00
mmap 完事
xpresslink
2021-01-13 19:43:44 +08:00
建议分块读。
FILE_PATH = "/path/to/your/in.txt"
CHUNK_SIZE=1024*1024*64 #64M 块
def read_in_chunks(filePath, chunk_size):
□□□□file_object = open(filePath,'r',encoding='utf-8')
□□□□while True:
□□□□□□□□chunk_data = file_object.read(chunk_size)
□□□□□□□□if not chunk_data:
□□□□□□□□□□□□break
□□□□□□□□yield chunk_data


for chunk in read_in_chunks(FILE_PATH, CHUNK_SIZE):
□□□□handling_func(chunk)

有很少部分单词被块截断,如果要求非常高精确,自己再处理一下。
neoblackcap
2021-01-13 20:20:36 +08:00
自己写一个简单 parser 不就可以了?实际上内存使用量可以是一个最大单词长度的两倍(动态扩展)
这个问题不是跟处理 TCP 流一样吗?
你只要读一定量的数据进你分配的缓冲区(预分配),然后开始解析。
1.如果整个缓冲区都读完了但是还是未能解析出一个单词( token )那么就将缓冲区变为已有的两倍,继续读取内容并重复此步骤。
2.如果解析到缓冲区末端,但是不是结束符(我假定是空格符),那么就继续读取你缓冲区长度减去未解析字符长度的字符。
然后继续上面的流程,进行解析。但是有直到读到文件底部就可以了。
autoxbc
2021-01-13 21:30:30 +08:00
考虑一下换语言? ry 大神新作 Deno,有个现成的函数直接对应你的需求

https://deno.land/std@0.83.0/io#readstringdelim
----------
readStringDelim

Read reader[like file] chunk by chunk, splitting based on delimiter.

import { readStringDelim } from "https://deno.land/std@0.83.0/io/mod.ts";
import * as path from "https://deno.land/std@0.83.0/path/mod.ts";

const filename = path.join(Deno.cwd(), "std/io/README.md");
let fileReader = await Deno.open(filename);

for await (let line of readStringDelim(fileReader, "\n")) {
console.log(line);
}

Output:

# std/io

## readLines

```ts
import * as path from "https://deno.land/std@0.83.0/path/mod.ts";

## Rest of the file
zyb201314
2021-01-14 10:34:29 +08:00
先谢过各大佬!

@liprais
稍后去了解.

@autoxbc
Python 学了近半年,算是新人吧,还没有精力了解别的语言哟~
@neoblackcap

学习了. 本人很菜,不知理解对不对.关于第 2 点,解析到缓冲区末端,如果不是符号,是否大概率英文词分两截?

@xpresslink
辛苦! 我想这种处理方案,应该是比较优解和大众吧.
Latin
2021-01-14 11:00:30 +08:00
with open('filename') as file:
for line in file:
do_things(line)

不换行也试试这个
neoblackcap
2021-01-14 11:53:12 +08:00
@zyb201314 有两种可能,一种是一个单词很长,你还没读完(截断了),第二种是你有可能读到单词最末尾的字符(刚刚好),两种情况都需要再读数据再解析
AoEiuV020
2021-01-20 09:46:00 +08:00
这种问题就明显感觉 java 系更合适了,java 自带的输入流就有各种各样的封装,python 只有整行读取,

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

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

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

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

© 2021 V2EX