在目录中查找最旧的文件(递归)

时间:2009-05-07 23:50:51

标签: python linux file-io

我正在编写Python备份脚本,我需要在目录(及其子目录)中找到最旧的文件。我还需要将其过滤为* .avi文件。

该脚本将始终在Linux计算机上运行。有没有办法在Python中执行它或者运行一些shell命令会更好?

目前我正在运行df以获取特定分区上的可用空间,如果可用空间少于5千兆字节,我想开始删除最早的*.avi文件,直到条件得到满足。

7 个答案:

答案 0 :(得分:22)

嗯。 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

答案 1 :(得分:13)

要在Python中执行此操作,您可以使用os.walk(path)以递归方式对文件进行迭代,并使用os.stat(filename)st_sizest_mtime属性来获取文件大小和修改时间。

答案 2 :(得分:10)

您可以同时使用statfnmatch个模块来查找文件

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])

答案 3 :(得分:7)

我认为最简单的方法是使用find和ls -t(按时间排序文件)。

沿着这些方向应该做的事情(删除指定目录下最旧的avi文件)

find / -name "*.avi" | xargs ls -t | tail -n 1 | xargs rm

一步一步......

find / -name“* .avi” - 从根目录开始递归查找所有avi文件

xargs ls -t - 对修改时间找到的所有文件进行排序,从最新到最旧。

tail -n 1 - 抓取列表中的最后一个文件(最旧的)

xargs rm - 并将其删除

答案 4 :(得分:3)

这是另一个Python公式,与其他一些相比有点老派,但很容易修改,并且处理不匹配文件的情况而不会引发异常。

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()

答案 5 :(得分:2)

查看linux命令find

或者,this post将ls和tail连接在一起以删除目录中最旧的文件。这可以在没有足够可用空间的情况下在循环中完成。

供参考,这是执行此操作的shell代码(请点击链接以获取更多选择和讨论):

ls -t -r -1 /path/to/files | head --lines 1 | xargs rm

答案 6 :(得分:0)

os module提供了在Python中获取目录列表和文件信息所需的功能。我发现os.walk对于递归遍历目录特别有用,os.stat会为你提供每个条目的详细信息(包括修改时间)。

使用简单的shell命令,您可以更轻松地完成此操作。这对你有效还是更好取决于你想对结果做些什么。