【问题标题】:Get file mtime with millisecond resolution from Java从 Java 获取毫秒分辨率的文件 mtime
【发布时间】:2014-09-08 09:19:20
【问题描述】:

当我使用 Files.getLastModifiedTime 从 Java 读取文件的 mtime 时,返回值被截断为整秒。我知道这适用于其他系统以获得毫秒分辨率的 mtime,那么我的有什么不同呢?

这是一个完整的独立测试,可以编译并运行:

import java.nio.file.attribute.FileTime;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Test {
  public static void main(String[] args) throws java.io.IOException {
    FileTime timestamp = Files.getLastModifiedTime(Paths.get("/tmp/test"));
    System.out.println(timestamp.toMillis());
  }
}

输出是(带有我的特定测试文件)1405602038000,而ls 显示:

$ ls --full-time /tmp/test                                                                                                                                                                                                    
-rw-rw-r-- 1 daniel daniel 0 2014-07-17 16:00:38.413008992 +0300 /tmp/test

我希望 Java 输出为 1405602038413。

我在带有 ext4 的 Linux 上运行。我尝试了 openjdk 1.7 和 Oracle jdk 1.8。

【问题讨论】:

    标签: java file last-modified


    【解决方案1】:

    this commit 在 Java 8 中添加了在 *nix 系统上以更高精度获取文件时间戳的功能,但是,在本机方面,它需要符合 POSIX 2008:

    #if (_POSIX_C_SOURCE >= 200809L) || defined(__solaris__)
        (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->st_atim.tv_nsec);
        (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->st_mtim.tv_nsec);
        (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->st_ctim.tv_nsec);
    #endif
    

    而且,显然,您正在使用的 Java 构建没有设置它,因此时间戳的纳秒部分不可用并且保持为零。

    【讨论】:

    【解决方案2】:

    我看了源码:

    在 Java 7 的情况下,该方法以 1 秒的精度给出最后修改的时间戳:

    在 Java 8 的情况下,看起来它应该提供微秒级精度:

    但无论哪种情况,代码似乎都没有提供一种以不同精度获取时间戳的方法。

    【讨论】:

    • This #if 似乎是相关的。我能够在 Ubuntu 上重现 Oracle Java 8 的问题。
    • 当我用调试器查看UnixFileAttributes.st_mtime 时,已经过了整整几秒钟。本机方面出了点问题。此外,即使在 Java 8 中使用(oracle 构建,而不是 openjdk),我也无法获得millis。当你运行 java 8 时,你真的能得到毫秒吗?
    • @izstas 宾果游戏!我也在ubuntu上。现在我们只需要知道为什么 Ubuntu 构建(和 Oracle 构建!)不设置 POSIX2008 合规性。其他操作系统或发行版的构建是否设置它?该代码适用于哪些人?如果您将此作为答案,我会接受,谢谢!
    • 当前的 ubuntu jdk8 确实提供了微秒级的精度。但他们可以将其提高到纳秒精度,因为评论中的那一刻“如果更新 FileTime 以定义 from(secs,nsecs) 方法,我们可以重新访问它。”来了。 FileTime 从 1.8 开始定义了一个 from(Instant) 方法。
    • 但除非文件系统以高精度存储时间戳,否则这一切都没有实际意义。我看到的消息来源说时间戳精度在不同的文件系统之间变化很大。 (然后要考虑时钟精度。)
    【解决方案3】:

    这似乎在 java 9 中已修复

    • Oracle jdk 9.0.4 - Files.getLastModifiedTime 提供毫秒级分辨率
    • Oracle jdk 1.8.162 - Files.getLastModifiedTime 提供第二个解决方案

    【讨论】:

    • 也在 Debian 的 1.8.0_292 中修复
    【解决方案4】:

    你可以使用简单的日期格式来显示时间是毫秒:

    java.nio.file.attribute.FileTime time = java.nio.file.Files.getLastModifiedTime(java.nio.file.Paths.get("/tmp/test"))
    java.text.SimpleDateFormat dateformat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    System.out.println(dateformat.format(time.toMillis()));
    

    【讨论】:

    • 你误会了。 time.toMillis 返回的值已经被截断为整秒分辨率(即总是以三个零结尾)。这就是问题所在。
    • 这看起来很奇怪,因为当我在我的电脑上尝试时,我确实得到了毫秒级的分辨率。
    • 我知道它适用于其他人(我编辑了问题以澄清这一点),但它在这里不起作用,我正试图找出原因。
    猜你喜欢
    • 2012-11-12
    • 2012-01-05
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 2011-04-13
    • 2018-06-01
    • 2021-11-21
    相关资源
    最近更新 更多