在目录中(递归)查找最旧的文件
我正在写一个Python备份脚本,需要找到一个文件夹(以及它里面的子文件夹)中最旧的文件。而且,我只想找后缀是*.avi的文件。
这个脚本会一直在Linux机器上运行。请问有没有办法用Python来实现,还是用一些命令行指令更好呢?
目前我在用df
命令来查看某个分区的可用空间,如果可用空间少于5GB,我想开始删除最旧的*.avi
文件,直到空间满足要求。
8 个回答
你可以一起使用 stat 和 fnmatch 这两个模块来查找文件。
ST_MTIME 是指最后修改的时间。如果你想的话,可以选择其他的值。
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))
然后你可以根据时间对文件列表进行排序,并根据这个顺序删除文件。
file_list.sort(key=lambda a: a[0])
在Python中,你可以使用 os.walk(path)
这个功能来递归地遍历文件,也就是从一个文件夹开始,逐层查看里面的所有文件和子文件夹。而要获取文件的大小和最后修改时间,你可以用 os.stat(filename)
这个功能中的 st_size
和 st_mtime
属性。
嗯,Nadia的回答更接近你想问的内容。不过,如果你想在一个文件夹树中找到(唯一的)最旧文件,可以试试这个:
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)
稍微修改一下,你就可以找到 n
个最旧的文件(和Nadia的回答类似):
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)
注意,使用 .endswith
方法可以让你这样调用:
oldest_files_in_tree("/home/user", 20, (".avi", ".mov"))
这样可以选择多个文件扩展名。
最后,如果你想要一个完整的文件列表,按修改时间排序,以便删除尽可能多的文件来释放空间,这里有一些代码:
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)
注意,reverse=True
会把最旧的文件放在列表的最后,所以下一个要删除的文件,你只需要用 file_list.pop()
就可以了。
顺便说一下,为了彻底解决你的问题,因为你在使用Linux,那里可以用到 os.statvfs
,你可以这样做:
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
是设备的空闲块数,而 statvfs.f_bsize
是块的大小。我们获取的是 rootfolder
的 statvfs,所以要注意任何指向其他设备的符号链接,这样我们可能会删除很多文件,但实际上并没有释放这个设备的空间。
更新(复制Juan的评论):
根据操作系统和文件系统的实现,你可能想把 f_bfree 乘以 f_frsize,而不是 f_bsize。在某些实现中,后者是首选的I/O请求大小。例如,在我刚测试的FreeBSD 9系统中,f_frsize是4096,而f_bsize是16384。POSIX说块计数字段是“以 f_frsize 为单位”(见 http://pubs.opengroup.org/onlinepubs/9699919799//basedefs/sys_statvfs.h.html)