如何在Python中确定一个打开文件的大小?

12

有一个文件,我希望确保它的大小不会超过2GB(因为它必须在使用ext 2的系统上运行)。有什么好的方法可以检查文件的大小,考虑到我将在检查之间写入此文件吗?特别是,我需要担心尚未写入磁盘的缓冲,未刷新的更改吗?

有一个文件,我希望确保它的大小不会超过2GB(因为它必须在使用ext 2的系统上运行)。有什么好的方法可以检查文件的大小,考虑到我将在检查之间写入此文件吗?特别是,我需要担心尚未写入磁盘的缓冲,未刷新的更改吗?

2
你为什么不能自己跟踪文件大小呢?也就是说,当你打开文件时查看其大小,并在写入时递增计数器。这不是特别优雅,但应该可以工作。 - Blair Conrad
我想那是一个我没有考虑过的可能性... 我也可以尝试一下。 - Jason Baker
2
ext2文件系统下的最大文件大小限制取决于块大小,范围为16GiB-64TiB。有关详细信息,请参见http://en.wikipedia.org/wiki/Ext2。虽然这并不能回答您的问题,但我认为这对您可能会有所帮助。 - unutbu
1
Jason,如果你让文件变得太大会发生什么?通常在Python中,不要“三心二意”,让异常发生并在那时处理它们。这样通常更快、更干净。如果您的计数器表明文件即将变得太大,您会怎么做?在捕获异常后当文件确实变得太大时,您能否做同样的事情?一些额外的细节可能有助于您的问题。 - Peter Hansen
@~unutbu - 我看到了,但是让我担心的是这个:“还有很多用户空间程序无法处理大于2 GB的文件”。 - Jason Baker
显示剩余4条评论
7个回答

21

也许不是你想要的,但我还是会建议一下。

import os
a = os.path.getsize("C:/TestFolder/Input/1.avi")

另外,对于已打开的文件,您可以使用fstat函数,在已打开的文件上使用它。它需要一个整数文件句柄,而不是文件对象,因此您必须在文件对象上使用fileno方法:

a = open("C:/TestFolder/Input/1.avi")
b = os.fstat(a.fileno()).st_size

6

并且它也可以在追加模式下工作!谢谢。是的,在调用此函数之前,我会先刷新缓冲区。 - personal_cloud

5
尽管这是一个老问题,但我认为Isak提供了最简单的解决方案。以下是在Python中执行此操作的方法:
# Assuming f is an open file
>>> pos = f.tell()  # Save the current position
>>> f.seek(0, 2)  # Seek to the end of the file
>>> length = f.tell()  # The current position is the length
>>> f.seek(pos)  # Return to the saved position
>>> print length
1024

我认为在第一行(保存当前位置)中,你应该使用f.tell()而不是seek(),因为seek()需要至少一个参数,否则会引发异常。 - Jkm
@Jkm 是的,你说得对!不确定我怎么会错过那个。谢谢! - Trenton
这将正确计算文件大小,但由于已知问题 [tell在追加模式下] (https://dev59.com/w43da4cB1Zd3GeqP0n7K),无法正确恢复位置。 - personal_cloud
@personal_cloud 我原本认为只要你在 tellseek 之间不写入数据就不会有问题,但我可能是错的。在我的测试中没有出现问题,但看起来这些问题因平台而异。感谢你指出这一点。 - Trenton

4
您可以从以下内容开始:

您可以从以下内容开始:

class TrackedFile(file):
    def __init__(self, filename, mode):
        self.size = 0
        super(TrackedFile, self).__init__(filename, mode)
    def write(self, s):
        self.size += len(s)
        super(TrackedFile, self).write(s)

然后您可以像这样使用它:
>>> f = TrackedFile('palindrome.txt', 'w')
>>> f.size
0
>>> f.write('A man a plan a canal ')
>>> f.size
21
>>> f.write('Panama')
27

显然,如果您不是从头开始编写文件,则此实现无法正常工作,但您可以调整您的__init__方法以处理初始数据。您可能还需要覆盖一些其他方法:例如writelines
这适用于任何编码,因为字符串只是字节序列。
>>> f2 = TrackedFile('palindrome-latin1.txt', 'w')
>>> f2.write(u'A man a plan a canál '.encode('latin1')
>>> f3 = TrackedFile('palindrome-utf8.txt', 'w')
>>> f3.write(u'A man a plan a canál '.encode('utf-8'))
>>> f2.size
21
>>> f3.size
22

这并不是实际情况。如果您使用ASCII、ISO1559和UTF-8,结果将是相同的,但磁盘上的大小将不同。 - Bite code
不,它也适用于其他编码,只要您使用实际的字符串。答案已进行修改以演示。 - jcdyer
诀窍在于不能仅仅编写Unicode对象并依赖于操作系统的编码。 - jcdyer

4

我不熟悉Python,但打开文件时获得的流对象(或任何你所获得的对象)是否有一个包含流当前位置的属性?

类似于C函数ftell()或.NET中的Stream.Position所获得的内容。

显然,只有当你位于流的末尾时才有效,如果你当前正在向其中写入数据,则已位于末尾。

这种方法的好处是,你不必关闭文件或担心未刷新的数据。


'filehandle.tell()' 确实显示打开文件的字节数,并且在写入或附加模式下工作。不确定为什么所有这些更复杂的答案都得到了赞成。 - hurfdurf
1
@hurfdurf 不,f.tell() 在追加模式下似乎不可靠。除非你首先执行 f.seek(0,2)。我不知道为什么会这样。 - personal_cloud

3
或者,如果文件已经打开:
>>> fsock = open('/etc/hosts', 'rb').read()
>>> len(fsock)
444

这是文件的字节数。

2

最可靠的方法是创建一个包装类,在打开文件时检查文件大小,跟踪写入和查找操作,基于这些操作计算当前大小并防止超过大小限制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接