我需要逐行读取一个大文件。 假设文件超过5GB,我需要读取每一行,但显然我不想使用readlines(),因为它会在内存中创建一个非常大的列表。
以下代码如何适用于此案例? xreadlines本身是一个一个地读入内存吗? 是否需要生成器表达式?
1
2
3f = (line for line in open("log.txt").xreadlines()) # how much is loaded in memory?
f.next()
另外,我可以做什么来以相反的顺序读取它,就像Linux tail命令一样?
我发现:
http://code.google.com/p/pytailer/
和
"python头,尾和向后读取文本文件的行"
两者都运作得很好!
我怎么能从尾巴上读到这个? 逐行,从最后一行开始。
这应该是一个单独的问题
复制stackoverflow.com/questions/5896079/
我提供了这个答案,因为Keith虽然简洁,却没有明确地关闭文件
1
2
3with open("log.txt") as infile:
for line in infile:
do_something_with(line)
问题仍然是,"for infile in line"会将我的5GB线路加载到内存中?而且,我怎么能从尾巴上读?
@rochacbruno,它一次只读一行。当读取下一行时,前一个行将被垃圾收集,除非您在其他地方存储了对它的引用
@rochacbruno,不幸的是,以相反的顺序读取行并不是那么容易。通常你会想要从文件的末尾读取合理大小的块(千字节到兆字节)并拆分换行符(或者你的平台上的字符结尾字符串)
谢谢!我找到了尾部解决方案stackoverflow.com/questions/5896079/
@gnibbler:实际上,由于Python内存管理的特殊语义,Keith的版本应该关闭CPython中的文件。
@Dietrich,你是对的。我们大多数人在我想象的某个时间利用了这一点。即使在像Jython这样的实现中,文件在被收集时也会被关闭,但是当它被收集时它是不确定的
@JohnLaRooy如果一条线本身超长怎么办?
应该注意的是,Python会将(旧DOS)或(旧Mac)的行结尾转换为简单的(现代* Nix / Everything)。这是我欣赏的功能,但如果您不了解它,您可能会有意想不到的结果。请参阅stackoverflow.com/a/45623945/117471下面的评论
我测试它并且工作正常,尝试使用超过50MB的日志文件
@bawejakunal,你的意思是如果一行太长而无法一次加载到内存中?这对于文本文件来说是不寻常的。您可以使用chunk = infile.read(chunksize)来读取有限大小的块,而不是使用遍历行的for循环,而不管其内容如何。您必须自己在块内搜索换行符。
您需要做的就是使用文件对象作为迭代器。
1
2for line in open("log.txt"):
do_something_with(line)
更好的是在最近的Python版本中使用上下文管理器。
1
2
3with open("log.txt") as fileobject:
for line in fileobject:
do_something_with(line)
这也会自动关闭文件。
那不是将整个文件加载到内存中?
不。它逐行读取。
旧学校方法:
1
2
3
4
5
6fh = open(file_name, 'rt')
line = fh.readline()
while line:
# do stuff with line
line = fh.readline()
fh.close()
次要说明:对于异常安全,建议使用'with'语句,在你的情况下"open(filename,'rt')为fh:"
@prokher:是的,但我确实称之为"老派"。
你最好使用迭代器。相关:http://docs.python.org/library/fileinput.html
来自文档:
1
2
3import fileinput
for line in fileinput.input("filename"):
process(line)
这样可以避免一次将整个文件复制到内存中。
尽管文档将代码段显示为"典型用法",但在循环结束时使用它并不会调用返回的FileInput类对象的close()方法 - 所以我会避免以这种方式使用它。在Python 3.2中,他们最终使FileInput与解决此问题的上下文管理器协议兼容(但代码仍然不会按照显示的方式编写)。
如果您在文件中没有换行符,请执行以下操作:
1
2
3
4
5
6with open('large_text.txt') as f:
while True:
c = f.read(1024)
if not c:
break
print(c)
请试试这个:
1
2
3with open('filename','r',buffering=100000) as f:
for line in f:
print line
请解释?
来自Python的官方docmunets:link可选的缓冲参数指定文件所需的缓冲区大小:0表示无缓冲,1表示行缓冲,任何其他正值表示使用(大约)该大小的缓冲区(以字节为单位)。负缓冲意味着使用系统默认值,通常为tty设备进行行缓冲,并为其他文件进行完全缓冲。如果省略,则使用系统默认值
在我的情况下,保存了我的一天,带有两个文件处理程序(一个读取,另一个写入)的~~ 4gb文件挂起,现在它很好! 谢谢。
我无法相信它可以像@ john-la-rooy的答案那样简单。因此,我使用逐行读取和写入重新创建cp命令。这很疯狂。
1
2
3
4
5
6
7
8#!/usr/bin/env python3.6
import sys
with open(sys.argv[2], 'w') as outfile:
with open(sys.argv[1]) as infile:
for line in infile:
outfile.write(line)
注意:因为python的readline标准化行结尾,这具有将DOS行结尾的文档转换为的Unix行结尾的副作用。我找出这个主题的全部理由是我需要转换一个接收混乱行结尾的日志文件(因为开发人员盲目地使用了各种.NET库)。我很惊讶地发现,在我的初始速度测试之后,我不需要回到rstrip线。它已经完美了!
大火项目在过去的6年里已经走过了漫长的道路。它有一个简单的API,涵盖了一个有用的pandas功能子集。
dask.dataframe负责内部分块,支持许多可并行操作,并允许您将切片轻松导出回到pandas以进行内存操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import dask.dataframe as dd
df = dd.read_csv('filename.csv')
df.head(10) # return first 10 rows
df.tail(10) # return last 10 rows
# iterate rows
for idx, row in df.iterrows():
...
# group by my_field and return mean
df.groupby(df.my_field).value.mean().compute()
# slice by column
df[df.my_field=='XYZ'].compute()
当您希望并行工作并且只读取数据块但使用新行保持清洁时,这可能很有用。
1
2
3
4
5
6
7
8
9def readInChunks(fileObj, chunkSize=1024):
while True:
data = fileObj.read(chunkSize)
if not data:
break
while data[-1:] != '
':
data+=fileObj.read(1)
yield data
下面是用于加载任何大小的文本文件而不会导致内存问题的代码。
它支持千兆字节大小的文件
https://gist.github.com/iyvinjose/e6c1cb2821abd5f01fd1b9065cbc759d
下载文件data_loading_utils.py并将其导入您的代码
用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import data_loading_utils.py.py
file_name = 'file_name.ext'
CHUNK_SIZE = 1000000
def process_lines(data, eof, file_name):
# check if end of file reached
if not eof:
# process data, data is one single line of the file
else:
# end of file reached
data_loading_utils.read_lines_from_file_as_data_chunks(file_name, chunk_size=CHUNK_SIZE, callback=self.process_lines)
process_lines方法是回调函数。它将被调用所有行,参数数据一次代表文件的一行。
您可以根据机器硬件配置配置变量CHUNK_SIZE。
我在另一个问题中演示了并行字节级随机访问方法:
获取没有readlines的文本文件中的行数
已经提供的一些答案很简洁。我喜欢其中的一些。但这实际上取决于你想要对文件中的数据做什么。在我的情况下,我只想在大文本文件上尽可能快地计算行数。我的代码当然可以修改为做其他事情,就像任何代码一样。
谢谢!我最近转换为python 3并且因使用readlines(0)读取大文件而感到沮丧。这解决了这个问题。但要获得每一条线,我不得不做几个额外的步骤。每行前面都有一个"b",我猜它是二进制格式。使用"decode(utf-8)"将其更改为ascii。
然后我不得不在每行的中间删除一个"= n"。
然后我在新线上分割线条。
1
2
3
4
5
6
7
8
9
10
11
12
13b_data=(fh.read(ele[1]))#endat This is one chunk of ascii data in binary format
a_data=((binascii.b2a_qp(b_data)).decode('utf-8')) #Data chunk in 'split' ascii format
data_chunk = (a_data.replace('=
','').strip()) #Splitting characters removed
data_list = data_chunk.split('
') #List containing lines in chunk
#print(data_list,'
')
#time.sleep(1)
for j in range(len(data_list)): #iterate through data_list to get each item
i += 1
line_of_data = data_list[j]
print(line_of_data)
这是从Arohi代码中的"打印数据"上方开始的代码。
这个怎么样?
将文件分成块然后逐行读取,因为当您读取文件时,操作系统将缓存下一行。如果您逐行读取文件,则无法有效使用缓存的信息。
相反,将文件分成块并将整个块加载到内存中然后进行处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def chunks(file,size=1024):
while 1:
startat=fh.tell()
print startat #file's object current position from the start
fh.seek(size,1) #offset from current postion -->1
data=fh.readline()
yield startat,fh.tell()-startat #doesnt store whole list in memory
if not data:
break
if os.path.isfile(fname):
try:
fh=open(fname,'rb')
except IOError as e: #file --> permission denied
print"I/O error({0}): {1}".format(e.errno, e.strerror)
except Exception as e1: #handle other exceptions such as attribute errors
print"Unexpected error: {0}".format(e1)
for ele in chunks(fh):
fh.seek(ele[0])#startat
data=fh.read(ele[1])#endat
print data
这很有希望。这是按字节还是按行加载?如果它是按字节的话,我害怕线被破坏..我们怎么能一次加载说1000行并处理它?
1
2
3
4
5f=open('filename','r').read()
f1=f.split('
')
for i in range (len(f1)):
do_something_with(f1[i])
希望这可以帮助。
这不会读取内存中的整个文件吗?这个问题明确要求如何避免这种情况,因此这不能回答这个问题。