file.createNewFile()在实际创建时间之前创建具有上次修改时间的文件

时间:2010-04-27 00:26:03

标签: java linux filesystems race-condition os-dependent

我正在使用JPoller检测特定目录中文件的更改,但它丢失了文件,因为它们最终的时间戳早于实际创建时间。这是我测试的方式:

public static void main(String [] files)
{
    for (String file : files)
    {
        File f = new File(file);
        if (f.exists())
        {
            System.err.println(file + " exists");
            continue;
        }

        try
        {
            // find out the current time, I would hope to assume that the last-modified
            // time on the file will definitely be later than this
            System.out.println("-----------------------------------------");
            long time = System.currentTimeMillis();

            // create the file
            System.out.println("Creating " + file + " at " + time);
            f.createNewFile();

            // let's see what the timestamp actually is (I've only seen it <time)
            System.out.println(file + " was last modified at: " + f.lastModified());

            // well, ok, what if I explicitly set it to time?
            f.setLastModified(time);
            System.out.println("Updated modified time on " + file + " to " + time + " with actual " + f.lastModified());
        }
        catch (IOException e)
        {
            System.err.println("Unable to create file");
        }
    }
}

这就是我得到的输出:

-----------------------------------------
Creating test.7 at 1272324597956
test.7 was last modified at: 1272324597000
Updated modified time on test.7 to 1272324597956 with actual 1272324597000
-----------------------------------------
Creating test.8 at 1272324597957
test.8 was last modified at: 1272324597000
Updated modified time on test.8 to 1272324597957 with actual 1272324597000
-----------------------------------------
Creating test.9 at 1272324597957
test.9 was last modified at: 1272324597000
Updated modified time on test.9 to 1272324597957 with actual 1272324597000

结果是竞争条件:

  1. JPoller将上次检查的时间记录为xyz ... 123
  2. 在xyz ... 456
  3. 创建的文件
  4. 文件上次修改时间戳实际上读取xyz ... 000
  5. JPoller查找时间戳大于xyz ... 123
  6. 的新/更新文件
  7. JPoller忽略新添加的文件,因为xyz ... 000小于xyz ... 123
  8. 我把头发拉了一会儿
  9. 我尝试深入研究代码,但lastModified()createNewFile()最终解析为原生调用,所以我只剩下很少的信息。

    对于test.9我输了957毫秒。我可以期待什么样的准确度?我的结果会因操作系统或文件系统而异吗?建议的解决方法?

    注意:我目前正在运行带有XFS文件系统的Linux。我在C编写了一个快速程序,stat system callst_mtime作为truncate(xyz...000/1000)编写。

    更新:我在Windows 7上运行了与NTFS相同的程序,确实保持完整的毫秒精度。 MSDN link @mdma提供了进一步说明,FAT文件系统对于10 ms分辨率的创建是准确的,但访问时间仅精确到2秒。因此,这确实取决于操作系统。

2 个答案:

答案 0 :(得分:2)

最后修改的时间戳显然以秒为单位存储,而不是以毫秒为单位。这可能是文件系统限制。我建议将它与秒而不是毫秒进行比较。

答案 1 :(得分:2)

文件系统不能精确地存储时间,并且通常不能以毫秒的分辨率存储时间,例如FAT具有2秒的创建时间分辨率,NTFS可以将上次访问时间的更新延迟长达一个小时。 (关于MSDN的详细信息。)虽然不是在你的情况下,但一般来说,如果文件是在另一台计算机上创建的,也会出现同步时钟的问题。

对于JPoller人来说,这似乎是一个问题,因为这是时间处理逻辑的所在。在修复之前,您可以通过手动将每个文件的最后修改时间设置为距实际时间+4秒来解决此问题 - +4是一个任意值,应该大于您正在处理的文件系统的分辨率。将文件写入文件系统时,它们将向下舍入,但小于您添加的值。不漂亮,但它会起作用!