删除 x 天前的文件

46

我想用Java找出文件的创建时间,因为我想删除早于一定时间段的文件,目前我正在删除目录中的所有文件,但这不是理想的解决方案:

public void DeleteFiles() {
    File file = new File("D:/Documents/NetBeansProjects/printing~subversion/fileupload/web/resources/pdf/");
    System.out.println("Called deleteFiles");
    DeleteFiles(file);
    File file2 = new File("D:/Documents/NetBeansProjects/printing~subversion/fileupload/Uploaded/");
    DeleteFilesNonPdf(file2);
}

public void DeleteFiles(File file) {
    System.out.println("Now will search folders and delete files,");
    if (file.isDirectory()) {
        for (File f : file.listFiles()) {
            DeleteFiles(f);
        }
    } else {
        file.delete();
    }
}

这是我的当前代码,现在我想添加一个 if 语句,只删除一周前的文件。

编辑:

@ViewScoped
@ManagedBean
public class Delete {

    public void DeleteFiles() {
        File file = new File("D:/Documents/NetBeansProjects/printing~subversion/fileupload/web/resources/pdf/");
        System.out.println("Called deleteFiles");
        DeleteFiles(file);
        File file2 = new File("D:/Documents/NetBeansProjects/printing~subversion/fileupload/Uploaded/");
        DeleteFilesNonPdf(file2);
    }

    public void DeleteFiles(File file) {
        System.out.println("Now will search folders and delete files,");
        if (file.isDirectory()) {
            System.out.println("Date Modified : " + file.lastModified());
            for (File f : file.listFiles()) {
                DeleteFiles(f);
            }
        } else {
            file.delete();
        }
    }

现在添加一个循环。

编辑

我注意到在测试上面的代码时,我得到的最后修改是:

INFO: Date Modified : 1361635382096

如果要删除七天前的内容,请按上述格式编写if循环代码。

15个回答

50
你可以使用 File.lastModified() 来获取文件/目录的最后修改时间。
可以像这样使用:
long diff = new Date().getTime() - file.lastModified();

if (diff > x * 24 * 60 * 60 * 1000) {
    file.delete();
}

删除比 x(一个 int)天更旧的文件。


它将提供最后修改时间而不是文件创建时间。 - Arpit
没问题,一旦文件创建后就不能进行修改,也没有人能够编辑它 :) - user2065929
那真的很简单。我正在编写有关文件创建时间的答案。 ;) - Arpit
谢谢! :) 我正在测试它,但目前看起来完美! - user2065929
当X == 25时,您会得到int溢出。25 * 24 * 60 * 60 * 1000L更加健壮。 - Oleg Gritsak

33

Commons IO内置了AgeFileFilter来支持按年龄过滤文件。你的DeleteFiles可能看起来像这样:

import java.io.File;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AgeFileFilter;
import static org.apache.commons.io.filefilter.TrueFileFilter.TRUE;

// a Date defined somewhere for the cutoff date
Date thresholdDate = <the oldest age you want to keep>;

public void DeleteFiles(File file) {
    Iterator<File> filesToDelete =
        FileUtils.iterateFiles(file, new AgeFileFilter(thresholdDate), TRUE);
    for (File aFile : filesToDelete) {
        aFile.delete();
    }
}

更新:要使用您编辑中给出的值,请将thresholdDate定义为:

Date tresholdDate = new Date(1361635382096L);

1
你能否将AgeFileFilter和另一个过滤器(例如NameFileFilter)结合起来使用? - NathanChristie
@NathanChristie 请查看AndFileFilterOrFileFilter - maxb3k
参数:iterateFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter),其中 dirFilter 是可选的(可以为 null)。 - thijsraets
1
示例无法编译,无法迭代Iterator。可能想使用listFiles? - NickL

16

使用Apache utils可能是最简单的方法。以下是我能想到的最简单的解决方案。

public void deleteOldFiles() {
    Date oldestAllowedFileDate = DateUtils.addDays(new Date(), -3); //minus days from current date
    File targetDir = new File("C:\\TEMP\\archive\\");
    Iterator<File> filesToDelete = FileUtils.iterateFiles(targetDir, new AgeFileFilter(oldestAllowedFileDate), null);
    //if deleting subdirs, replace null above with TrueFileFilter.INSTANCE
    while (filesToDelete.hasNext()) {
        FileUtils.deleteQuietly(filesToDelete.next());
    }  //I don't want an exception if a file is not deleted. Otherwise use filesToDelete.next().delete() in a try/catch
}

2
值得注意的是,您可以使用毫秒来创建一个AgeFileFilter,例如 new AgeFileFilter(System.currentTimeMillis() - AGE_LIMIT_MILLIS),其中AGE_LIMIT_MILLIS可以是246060*1000L,表示24小时。 - Glenn Lawrence
@MattC 如果我在包含 2 或 3 百万条记录的目录中使用它,是否会像内存不足异常一样产生影响? - diwa
@Diwa 是的,我猜如果你有数百万个文件,你可能会遇到内存问题。FileUtils创建了一个java.util.LinkedList,然后返回该列表的迭代器。 - MattC

14

使用Java 8的时间API的示例

LocalDate today = LocalDate.now();
LocalDate eailer = today.minusDays(30);
    
Date threshold = Date.from(eailer.atStartOfDay(ZoneId.systemDefault()).toInstant());
AgeFileFilter filter = new AgeFileFilter(threshold);
    
File path = new File("...");
File[] oldFolders = FileFilterUtils.filter(filter, path);
    
for (File folder : oldFolders) {
    System.out.println(folder);
}

3
请注意,AgeFileFilter 是来自 Apache Commons IO 而不是 Java 8 Time API。 - Nate

12

这里是使用时间API的Java 8版本。它已经在我们的项目中进行了测试和使用:

    public static int deleteFiles(final Path destination,
        final Integer daysToKeep) throws IOException {

    final Instant retentionFilePeriod = ZonedDateTime.now()
            .minusDays(daysToKeep).toInstant();

    final AtomicInteger countDeletedFiles = new AtomicInteger();
    Files.find(destination, 1,
            (path, basicFileAttrs) -> basicFileAttrs.lastModifiedTime()
                    .toInstant().isBefore(retentionFilePeriod))
            .forEach(fileToDelete -> {
                try {
                    if (!Files.isDirectory(fileToDelete)) {
                        Files.delete(fileToDelete);
                        countDeletedFiles.incrementAndGet();
                    }
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            });

    return countDeletedFiles.get();
}

我正在根据我的需求进行调整,但是SonarQube发出了警告,指出Files.find流应该被关闭,或者最好放入try with resources块中。 - Matt Harrison

12

使用Lambda表达式(Java 8+)

删除当前文件夹中所有早于N天的文件的非递归选项(忽略子文件夹):

public static void deleteFilesOlderThanNDays(int days, String dirPath) throws IOException {
    long cutOff = System.currentTimeMillis() - (days * 24 * 60 * 60 * 1000);
    Files.list(Paths.get(dirPath))
    .filter(path -> {
        try {
            return Files.isRegularFile(path) && Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS) < cutOff;
        } catch (IOException ex) {
            // log here and move on
            return false;
        }
    })
    .forEach(path -> {
        try {
            Files.delete(path);
        } catch (IOException ex) {
            // log here and move on
        }
    });
}

递归选项,遍历子文件夹并删除所有早于N天的文件:

public static void recursiveDeleteFilesOlderThanNDays(int days, String dirPath) throws IOException {
    long cutOff = System.currentTimeMillis() - (days * 24 * 60 * 60 * 1000);
    Files.list(Paths.get(dirPath))
    .forEach(path -> {
        if (Files.isDirectory(path)) {
            try {
                recursiveDeleteFilesOlderThanNDays(days, path.toString());
            } catch (IOException e) {
                // log here and move on
            }
        } else {
            try {
                if (Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS) < cutOff) {
                    Files.delete(path);
                }
            } catch (IOException ex) {
                // log here and move on
            }
        }
    });
}

6

使用NIO文件流和JSR-310的JDK 8解决方案如下:

long cut = LocalDateTime.now().minusWeeks(1).toEpochSecond(ZoneOffset.UTC);
Path path = Paths.get("/path/to/delete");
Files.list(path)
        .filter(n -> {
            try {
                return Files.getLastModifiedTime(n)
                        .to(TimeUnit.SECONDS) < cut;
            } catch (IOException ex) {
                //handle exception
                return false;
            }
        })
        .forEach(n -> {
            try {
                Files.delete(n);
            } catch (IOException ex) {
                //handle exception
            }
        });

这里很糟糕的一点是需要在每个lambda中处理异常。如果API为每个IO方法提供了UncheckedIOException重载,那将会非常好。通过辅助工具,我们可以这样编写代码:

public static void main(String[] args) throws IOException {
    long cut = LocalDateTime.now().minusWeeks(1).toEpochSecond(ZoneOffset.UTC);
    Path path = Paths.get("/path/to/delete");
    Files.list(path)
            .filter(n -> Files2.getLastModifiedTimeUnchecked(n)
                    .to(TimeUnit.SECONDS) < cut)
            .forEach(n -> {
                System.out.println(n);
                Files2.delete(n, (t, u)
                              -> System.err.format("Couldn't delete %s%n",
                                                   t, u.getMessage())
                );
            });
}


private static final class Files2 {

    public static FileTime getLastModifiedTimeUnchecked(Path path,
            LinkOption... options)
            throws UncheckedIOException {
        try {
            return Files.getLastModifiedTime(path, options);
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
    }

    public static void delete(Path path, BiConsumer<Path, Exception> e) {
        try {
            Files.delete(path);
        } catch (IOException ex) {
            e.accept(path, ex);
        }
    }

}

6

JavaSE 规范解决方案。 删除早于expirationPeriod天的文件。

private void cleanUpOldFiles(String folderPath, int expirationPeriod) {
    File targetDir = new File(folderPath);
    if (!targetDir.exists()) {
        throw new RuntimeException(String.format("Log files directory '%s' " +
                "does not exist in the environment", folderPath));
    }

    File[] files = targetDir.listFiles();
    for (File file : files) {
        long diff = new Date().getTime() - file.lastModified();

        // Granularity = DAYS;
        long desiredLifespan = TimeUnit.DAYS.toMillis(expirationPeriod); 

        if (diff > desiredLifespan) {
            file.delete();
        }
    }
}

例如:要删除 "/sftp/logs" 文件夹中 30 天前的所有文件,请调用:

cleanUpOldFiles("/sftp/logs", 30);

(注:此为代码示例,不是解释)

4
您可以使用NIO获取文件的创建日期,以下是方法:

你可以通过NIO获得文件的创建日期,下面是具体步骤:

BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
System.out.println("creationTime: " + attrs.creationTime());

更多相关信息可在此处找到:http://docs.oracle.com/javase/tutorial/essential/io/fileAttr.html

(此链接为外部链接)

涉及IT技术。


BasicFileAttributes 仅适用于 Java 7。您无法在 Java 6 或更早版本中使用它。 - user2030471

3

使用Java NIO文件与lambda和Commons IO

final long time = System.currentTimeMillis();
// Only show files & directories older than 2 days
final long maxdiff = TimeUnit.DAYS.toMillis(2);

列出所有找到的文件和目录:
Files.newDirectoryStream(Paths.get("."), p -> (time - p.toFile().lastModified()) < maxdiff)
.forEach(System.out::println);

或者使用FileUtils删除已找到的文件:

Files.newDirectoryStream(Paths.get("."), p -> (time - p.toFile().lastModified()) < maxdiff)
.forEach(p -> FileUtils.deleteQuietly(p.toFile()));

2
建议使用System.currentTimeMillis(),并且我认为应该是> - CeePlusPlus

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