views:

164

answers:

6

There's a file that I would like to make sure does not grow larger than 2 GB (as it must run on a system that uses ext 2). What's a good way to check a file's size bearing in mind that I will be writing to this file in between checks? In particular, do I need to worry about buffered, unflushed changes that haven't been written to disk yet?

+4  A: 

Perhaps not what you want, but I'll suggest it anyway.

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

Alternatively for an opened file you can use the fstat function, which can be used on an opened file. It takes an integer file handle, not a file object, so you have to use the fileno method on the file object:

a = open("C:/TestFolder/Input/1.avi")
b = os.fstat(a.fileno()).st_size
Dominic Bou-Samra
+2  A: 

Most reliable would be create a wrapping class which would check file's size when you open it, track write and seek operations, count current size based on those operations and prevent from exceeding size limit.

Bartosz
+1  A: 

Or, if the file is already open:

>>> fsock = open('/etc/hosts', 'rb').read()
>>> len(fsock)
444

That's how many bytes the file is.

jathanism
+1  A: 

os.fstat(file_obj.fileno()).st_size should do the trick. I think that it will return the bytes written. You can always do a flush before hand if you are concerned about buffering.

D.Shawley
+1  A: 

I'm not familiar with python, but doesn't the stream object (or whatever you get when opening a file) have a property that contains the current position of the stream?

Similar to what you get with the ftell() C function, or Stream.Position in .NET.

Obviously, this only works if you are positioned at the end of the stream, which you are if you are currently writing to it.

The benefit of this approach is that you don't have to close the file or worry about unflushed data.

Isak Savo
+3  A: 

You could start with something like this:

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)

Then you could use it like this:

>>> f = TrackedFile('palindrome.txt', 'w')
>>> f.size
0
>>> f.write('A man a plan a canal ')
>>> f.size
21
>>> f.write('Panama')
27

Obviously, this implementation doesn't work if you aren't writing the file from scratch, but you could adapt your __init__ method to handle initial data. You might also need to override some other methods: writelines, for instance.

This works regardless of encoding, as strings are just sequences of bytes.

>>> 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
jcdyer
+1: That is a really clever idea. I like it!
jathanism
That's not actually. It you use ASCII, ISO1559 and UTF-8, the result will be the same, but the on disk size will not be.
e-satis
No. It works for other encodings too, if you use actual strings. Answer modified to demonstrate.
jcdyer
The trick is you can't just write unicode objects and rely on the os's encoding.
jcdyer