在Java中确定文件创建日期

137

在StackOverflow上有一个类似于我的问题 (如何在Java中获取文件的创建日期),但是答案并没有解决我的问题,因为原贴作者的需求不同,可以通过其他机制解决。我正在尝试创建一个目录中按年龄排序的文件列表,因此需要文件的创建日期。

在网上搜寻了很多,没有找到好的方法。是否有一种机制可以获取文件的创建日期?

顺便说一下,我目前在Windows系统上,可能也需要在Linux系统上工作。另外,我不能保证遵循将创建日期/时间嵌入名称的文件命名约定。


2
好的,在更多的讨论和对文件系统的调查后,我们决定使用最后修改时间是足够的,因为它很可能已经与创建日期一起被检查过了。需要检查两者才能确定旧文件是否最近被修改,因此仍然处于活动状态。所以,只需检查最久远的文件修改时间即可。感谢所有的意见。顺便说一句,我很想使用nio,但这里的Linux版本不支持文件创建。 - Todd
8个回答

199

Java nio提供了访问creationTime和其他元数据的选项,只要文件系统支持。 请查看此链接

例如(基于@ydaetskcoR的评论提供):

Path file = ...;
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);

System.out.println("creationTime: " + attr.creationTime());
System.out.println("lastAccessTime: " + attr.lastAccessTime());
System.out.println("lastModifiedTime: " + attr.lastModifiedTime());

16
这样做最好,但这是Java 7。我们仍在使用6,但我会调查升级选项。 - Todd
8
如果要获取文件的属性,请使用 readAttributes(file.toPath(), BasicFileAttributes.class),否则会出现以下错误:no suitable method found for readAttributes(File,Class<BasicFileAttributes>) method Files.<A>readAttributes(Path,Class<A>,LinkOption...) is not applicable (cannot infer type-variable(s) A (argument mismatch; File cannot be converted to Path)) - Hooli
1
@Hooli 不用担心,老兄!试试这个 https://www.logicbig.com/how-to/java/file-creation-date.html。 - Socrates
2
由于较新的Linux内核版本中添加了“statx”系统调用,因此在JDK 8(至少)中无法获取文件创建日期。 - St.Antario
1
但是为什么创建时间总是与上次修改时间相同呢? - LeeR
是的,非常令人困惑,但似乎在Java上调用get creationTime,与其报告不存在,它只会返回lastModifiedTime。 - Paul Taylor

20

我用以下代码使用JDK 7解决了这个问题:

package FileCreationDate;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class Main
{
    public static void main(String[] args) {

        File file = new File("c:\\1.txt");
        Path filePath = file.toPath();

        BasicFileAttributes attributes = null;
        try
        {
            attributes =
                    Files.readAttributes(filePath, BasicFileAttributes.class);
        }
        catch (IOException exception)
        {
            System.out.println("Exception handled when trying to get file " +
                    "attributes: " + exception.getMessage());
        }
        long milliseconds = attributes.creationTime().to(TimeUnit.MILLISECONDS);
        if((milliseconds > Long.MIN_VALUE) && (milliseconds < Long.MAX_VALUE))
        {
            Date creationDate =
                    new Date(attributes.creationTime().to(TimeUnit.MILLISECONDS));

            System.out.println("File " + filePath.toString() + " created " +
                    creationDate.getDate() + "/" +
                    (creationDate.getMonth() + 1) + "/" +
                    (creationDate.getYear() + 1900));
        }
    }
}

15
作为对这个问题的后续 - 因为它与创建时间有关并讨论通过新的nio类获取它,所以目前在JDK7的实现中似乎没有办法。附言:在OpenJDK7中也是相同的行为。
在Unix文件系统中,您无法检索创建时间戳,您只能获取最后修改时间的副本。很遗憾,但不幸的是这是真的。我不确定为什么会这样,但代码明确执行此操作,如下面的示例所示。
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.*;

public class TestFA {
  static void getAttributes(String pathStr) throws IOException {
    Path p = Paths.get(pathStr);
    BasicFileAttributes view
       = Files.getFileAttributeView(p, BasicFileAttributeView.class)
              .readAttributes();
    System.out.println(view.creationTime()+" is the same as "+view.lastModifiedTime());
  }
  public static void main(String[] args) throws IOException {
    for (String s : args) {
        getAttributes(s);
    }
  }
}

1
你知道如何在Android上实现吗?BasicFileAttributes在那里不是内置API... - android developer
这确实是真的,即使调用 stat 也不起作用。除非你运行的内核高于4.11,glibc高于2.28,coreutils高于8.31,然后 stat 将报告文件的_birth_。参见相关答案 https://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4/50184#50184 目前 JDK 不使用 statx 系统调用。 - bric3

12
这是一个获取文件创建日期的基本示例,使用 BasicFileAttributes 类来编写 Java 代码:
   Path path = Paths.get("C:\\Users\\jorgesys\\workspaceJava\\myfile.txt");
    BasicFileAttributes attr;
    try {
    attr = Files.readAttributes(path, BasicFileAttributes.class);
    System.out.println("Creation date: " + attr.creationTime());
    //System.out.println("Last access date: " + attr.lastAccessTime());
    //System.out.println("Last modified date: " + attr.lastModifiedTime());
    } catch (IOException e) {
    System.out.println("oops error! " + e.getMessage());
}

想要使用这个类的人应该注意它在Java 1.7中开始被发布。 - jwj

12

java.io.File的API仅支持获取最后修改时间。关于这个话题在互联网上也非常安静。

除非我遗漏了什么重要的内容,否则Java库本身(包括Java 7之前)并不包括此功能。因此,如果你迫切需要这个功能,一种解决方案是编写一些C(++)代码来调用系统例程,并使用JNI进行调用。不过,大部分这项工作似乎已经为你完成在一个叫做JNA的库中。

然而,你可能仍需要在Java中进行一些特定于操作系统的编码,因为你可能无法在Windows和Unix/Linux/BSD/OS X中找到相同的系统调用。


2
是啊,Java 7应该很棒,因为nio似乎具备了这些基本属性。从未想过我会抱怨自己出生得太早!; ) - Todd
7
File类没有这种功能的原因是大多数文件系统甚至不跟踪此信息。而那些跟踪此信息的文件系统在更新时间方面也不总是一致的。 - Syntactic
@Syntactic: 其实,大多数文件系统都会跟踪这些信息。例外包括ext<=3和Reiser。FAT、NTFS、HFS、ZFS和ext4都支持它。但是,在Linux的所有层和库以及用于普遍使用的命令中推广它一直很缓慢。 - hippietrail
@Carl 在Linux中,我使用Java NIO时发现修改日期和创建日期相同,这是正常行为吗? - Jayesh Dhandha
@JayeshDhandha,如果文件在创建后没有被修改,我会期望创建时间和修改时间相等。您可以尝试使用“touch”更改修改时间,然后再次检查以更改这种情况。 - Carl Smotricz
@CarlSmotricz,我刚刚发现对于某些文件系统,创建时间与修改时间是相同的,因此我们可以说这是文件系统的一个限制。 - Jayesh Dhandha

10

有没有其他方法可以在不支持创建时间的Linux机器上实现? - Maverick
只需使用支持文件创建时间戳的文件系统即可。维基百科链接的文章建议使用现在相当普遍的ext4。 - rbncrthms

2

在Java 1.7及以上版本中,您可以使用以下代码获取文件的创建时间!

private static LocalDateTime getCreateTime(File file) throws IOException {
        Path path = Paths.get(file.getPath());
        BasicFileAttributeView basicfile = Files.getFileAttributeView(path, BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
        BasicFileAttributes attr = basicfile.readAttributes();
        long date = attr.creationTime().toMillis();
        Instant instant = Instant.ofEpochMilli(date);
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

请问您能否详细说明为什么我们需要使用 Instant.ofEpochMilli(date) 这个方法吗?谢谢。 - Kirill Karmazin
自Java 1.8版本开始,我们无需再使用旧方法。我们可以直接使用 Instant instant = attr.creationTime().toInstant(); - Ole V.V.

0

基本上,当您从BasicFileAttributeView对象获取创建日期后,应该格式化日期以显示:

String modifiedDate;
Path inPath = Paths.get(yourfile.getAbsolutePath());
BasicFileAttributes attr;
try {
    attr = Files.readAttributes(inPath, BasicFileAttributes.class);
} catch (IOException e) {
    attr = null;
}
        
if (attr == null) {
     this.modifiedDate = null;
} else {
    this.modifiedDate = simpleDateFormat.format(attr.creationTime().toMillis());
}

2
感谢您想要做出贡献。请不要教年轻人使用早已过时且臭名昭著的 SimpleDateFormat 类。从 creationTime() 得到的 FileTime 对象有一个 toInstant 方法,可以给您一个 Instant,您可以将其转换为所需的时区(例如 ZoneId.systemDefault()),并使用现代的 DateTimeFormatter 进行格式化。结果代码会稍微长一些,这是一个优点,因为它更明确地表达了正在发生的事情,因此读起来更清晰、自然。 - Ole V.V.

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