[ACCEPTED]-Find the oldest file (recursively) in a directory-file-io
Hm. Nadia's answer is closer to what you 28 meant to ask; however, for finding the (single) oldest 27 file in a tree, try this:
import os
def oldest_file_in_tree(rootfolder, extension=".avi"):
return min(
(os.path.join(dirname, filename)
for dirname, dirnames, filenames in os.walk(rootfolder)
for filename in filenames
if filename.endswith(extension)),
key=lambda fn: os.stat(fn).st_mtime)
With a little modification, you 26 can get the n
oldest files (similar to Nadia's 25 answer):
import os, heapq
def oldest_files_in_tree(rootfolder, count=1, extension=".avi"):
return heapq.nsmallest(count,
(os.path.join(dirname, filename)
for dirname, dirnames, filenames in os.walk(rootfolder)
for filename in filenames
if filename.endswith(extension)),
key=lambda fn: os.stat(fn).st_mtime)
Note that using the .endswith
method allows 24 calls as:
oldest_files_in_tree("/home/user", 20, (".avi", ".mov"))
to select more than one extension.
Finally, should 23 you want the complete list of files, ordered 22 by modification time, in order to delete 21 as many as required to free space, here's 20 some code:
import os
def files_to_delete(rootfolder, extension=".avi"):
return sorted(
(os.path.join(dirname, filename)
for dirname, dirnames, filenames in os.walk(rootfolder)
for filename in filenames
if filename.endswith(extension)),
key=lambda fn: os.stat(fn).st_mtime),
reverse=True)
and note that the reverse=True
brings the 19 oldest files at the end of the list, so 18 that for the next file to delete, you just 17 do a file_list.pop()
.
By the way, for a complete solution 16 to your issue, since you are running on 15 Linux, where the os.statvfs
is available, you can 14 do:
import os
def free_space_up_to(free_bytes_required, rootfolder, extension=".avi"):
file_list= files_to_delete(rootfolder, extension)
while file_list:
statv= os.statvfs(rootfolder)
if statv.f_bfree*statv.f_bsize >= free_bytes_required:
break
os.remove(file_list.pop())
statvfs.f_bfree
are the device free blocks and statvfs.f_bsize
is the 13 block size. We take the rootfolder
statvfs, so mind 12 any symbolic links pointing to other devices, where 11 we could delete many files without actually 10 freeing up space in this device.
UPDATE (copying 9 a comment by Juan):
Depending on the OS and 8 filesystem implementation, you may want 7 to multiply f_bfree by f_frsize rather than 6 f_bsize. In some implementations, the latter 5 is the preferred I/O request size. For example, on 4 a FreeBSD 9 system I just tested, f_frsize 3 was 4096 and f_bsize was 16384. POSIX says 2 the block count fields are "in units 1 of f_frsize" ( see http://pubs.opengroup.org/onlinepubs/9699919799//basedefs/sys_statvfs.h.html )
To do it in Python, you can use os.walk(path)
to iterate 3 recursively over the files, and the st_size
and 2 st_mtime
attributes of os.stat(filename)
to get the file sizes and 1 modification times.
You can use stat and fnmatch modules together to find 4 the files
ST_MTIME refere to the last modification 3 time. You can choose another value if you 2 want
import os, stat, fnmatch
file_list = []
for filename in os.listdir('.'):
if fnmatch.fnmatch(filename, '*.avi'):
file_list.append((os.stat(filename)[stat.ST_MTIME], filename))
Then you can order the list by time 1 and delete according to it.
file_list.sort(key=lambda a: a[0])
I think the easiest way to do this would 9 be to use find along with ls -t (sort files 8 by time).
something along these lines should 7 do the trick (deletes oldest avi file under 6 specified directory)
find / -name "*.avi" | xargs ls -t | tail -n 1 | xargs rm
step by step....
find / -name "*.avi" - find 5 all avi files recursively starting at the 4 root directory
xargs ls -t - sort all files found by 3 modification time, from newest to oldest.
tail -n 1 - grab 2 the last file in the list (oldest)
xargs rm - and 1 remove it
Here's another Python formulation, which 4 a bit old-school compared to some others, but 3 is easy to modify, and handles the case 2 of no matching files without raising an 1 exception.
import os
def find_oldest_file(dirname="..", extension=".avi"):
oldest_file, oldest_time = None, None
for dirpath, dirs, files in os.walk(dirname):
for filename in files:
file_path = os.path.join(dirpath, filename)
file_time = os.stat(file_path).st_mtime
if file_path.endswith(extension) and (file_time<oldest_time or oldest_time is None):
oldest_file, oldest_time = file_path, file_time
return oldest_file, oldest_time
print find_oldest_file()
Check out the linux command find
.
Alternatively, this post pipes 6 together ls and tail to delete the oldest 5 file in a directory. That could be done 4 in a loop while there isn't enough free 3 space.
For reference, here's the shell code 2 that does it (follow the link for more alternatives 1 and a discussion):
ls -t -r -1 /path/to/files | head --lines 1 | xargs rm
The os module provides the functions that you need 9 to get directory listings and file info 8 in Python. I've found os.walk to be especially 7 useful for walking directories recursively, and 6 os.stat will give you detailed info (including 5 modification time) on each entry.
You may 4 be able to do this easier with a simple 3 shell command. Whether that works better 2 for you or not depends on what you want 1 to do with the results.
Using standard library's pathlib
:
from pathlib import Path
def creation_time(path: Path):
return path.stat().st_ctime
working_dir = Path()
avi_files = working_dir.glob("**/*.avi")
sorted_avi_files = sorted(avi_files, key=creation_time)
print(sorted_avi_files[0])
Or if you like 1 one-liners:
min(Path().glob("**/*.avi"), key=lambda p: p.stat().st_ctime)
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.