可以用Python变量来保存整个文件吗?

8 投票
6 回答
10824 浏览
提问于 2025-04-15 14:22

假设我们知道所有的文件都会被加载到内存中,并且我们可以承受这样的操作,那么把整个文件(可能是二进制文件)加载到一个Python变量中有什么缺点或限制吗?如果从技术上讲这是可行的,是否应该避免这样做,为什么呢?

关于文件大小的问题,这种方法应该限制在什么最大大小呢?为什么会有这样的限制?

实际的加载代码可以参考这个StackOverflow的帖子

示例代码是:

def file_get_contents(filename):
    with open(filename) as f:
        return f.read()

content = file_get_contents('/bin/kill')

... code manipulating 'content' ...

[编辑] 想到的一些代码操作(但可能不适用)是标准的列表/字符串操作(方括号、'+'号)或者一些字符串操作('len'、'in'操作符、'count'、'endswith'/'startswith'、'split'、'translation'等)。

6 个回答

4
with open(filename) as f:

这个方法只在Unix系统上的Python 2.x版本中有效。在Python 3.x或者Windows上,它的表现可能和你预期的不一样,因为这两个环境对文本文件和二进制文件有很明确的区分。更好的做法是明确告诉程序这个文件是二进制文件,像这样:

with open(filename, 'rb') as f:

这样做会关闭Windows系统对换行符的自动转换,并且会强制Python 3.x返回一个字节数组,而不是Unicode字符。

至于你问题的其他部分,我同意Lennart Regebro的(未编辑的)回答。

11
  • 是的,你可以这么做。
  • 唯一的缺点是会占用内存,如果文件很大的话,速度也可能会变慢。
  • 文件的大小应该限制在你内存能容纳的范围内。

总的来说,还有更好的方法来处理这个问题,但如果你只是写一个临时的小脚本,而且知道内存不是问题,那就没问题。

8

虽然你得到了不错的回答,但似乎没有人回答你问题的这一部分(这在提问时常常发生,尤其是当你问了很多问题的时候;-)...:

关于文件大小的担忧,这个解决方案应该限制在什么最大大小?为什么?

最重要的是,这个特定的Python进程实际上可以使用多少物理内存(我们称之为“工作集”),而不会对系统的其他性能造成太大影响。如果你的“工作集”超出了物理内存的限制,你就会开始频繁地将数据交换到硬盘上,这样会导致性能迅速下降(有时候会出现一种叫做“抖动”的状态,基本上所有的计算资源都用在了数据的进出上,而实际的工作几乎无法完成)。

在总内存中,通常会有一小部分(一般来说最多几MB)被可执行代码(Python的可执行文件、DLL或.so文件)和一些需要在内存中活跃使用的支持数据结构占用;在一台现代的普通电脑上,如果没有其他重要或紧急的任务,这部分开销几乎可以忽略不计,相比于你整体可用的几GB内存来说(不过在嵌入式系统等情况下,情况可能会有所不同)。

剩下的内存就是用来存放你的数据——这包括你正在读取到内存中的文件,以及其他重要的数据结构。文件数据的“修改”通常会暂时占用大约两倍于文件内容大小的内存(如果你把它放在字符串中),当然,如果你还保留了旧数据的副本,同时又创建了新的修改版本,那占用的内存会更多。

所以在一台典型的现代32位机器上,比如说总内存为2GB,进行“只读”操作时,读取1.5GB的内容应该没有问题;但如果你要进行“修改”,那么这个大小必须大大低于1GB(如果内存中还有其他重要的数据结构,要求会更高!)。当然,在一台专用的服务器上,使用64位的Python、64位操作系统和16GB内存,实际的限制会非常不同——这实际上与可用的内存量成正比。

例如,下载的《钦定版圣经》文本(解压后)大约是4.4MB;所以在一台2GB内存的机器上,你可以在内存中保留大约400个稍微修改过的副本(如果没有其他程序在请求内存的话),而在一台有16GB可用内存的机器上,你可以保留超过3000个这样的副本。

撰写回答