当Java向Windows Server 2016写入时,文件最后修改时间未更新。

9

我在Windows Server 2016上运行一个使用java.util.logging不断写入文件的Java 10应用程序。在Windows文件资源管理器中,“最后修改”和“大小”列没有更新。按下[F5]键也无法更新详细信息。DOS DIR命令给出了相同错误的答案。右键单击 > 属性 > 详细信息 给出了甚至更旧的答案。

只有在DOS TYPE命令或在Notepad中打开/关闭(不保存)文件时,似乎才会导致文件资源管理器和DOS DIR命令更新。

我认为Java代码关于flush()是正确的,因为在Windows Server 2008上运行Java 8相同的类会导致文件资源管理器更新。当运行TYPE命令和Notepad时,我也看到时间戳记录与系统时钟匹配,但晚于“最后修改”的时间。

所以我认为问题在于Windows Server 2016。有什么想法或者需要检查什么吗?


应用程序在Java 8上运行,能在Windows Server 2016上工作吗?应用程序在Java 10上运行,能在Windows Server 2008上工作吗?如果我没记错的话,您需要配置其中一个测试来确定问题是由较新版本的Java还是较新版本的Windows Server引入的。 - FThompson
同一类在2016年使用Java 8也有相同的症状。Control M也有相同的症状(我可能错了,但尽管Control M是一个EXE,它看起来好像在Apache commons日志记录下运行Java 8)。本地二进制文件(例如DLL)似乎没有出现这个问题。 - lafual
这些文件是在本地磁盘上还是在某种网络文件共享/文件系统上?我怀疑您正在遇到某种与网络相关的文件元数据问题。这实际上与Java无关。 - Stephen C
本地磁盘,没有其他人登录到服务器。但是,服务器及其磁盘在VMWare上。我遇到了这个问题[JDK-8170718](https://bugs.openjdk.java.net/browse/JDK-8170718),它说可能与文件扩展名有关。目前我正在使用`.log`。明天回到工作岗位时,我将尝试更常见的`.txt`并查看发生了什么。 - lafual
就JDK-8170718而言,更改为“.txt”并没有产生任何影响。 - lafual
1个回答

5
我假设Windows Server 2016存在某些问题。有什么想法要检查吗?
默认情况下,Windows设置为以这种方式工作。来自File timestamp not updating on 2008 but does on 2003
在2003年,打开资源管理器中的日志文件夹,您可以看到每次更新日志时时间戳和文件大小会实时更改。
在2008年,大多数情况下,除非以其他方式交互,否则不会有任何变化...
是的,其中一些属性已在2008年被禁用。 例如,如果您想要查看/使用“上次访问”时间,则需要启用此属性的跟踪。

您可以通过将HKLM\System\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate设置为0来启用此功能(该值为REG_DWORD)。

请注意,这可能会影响繁忙文件服务器的磁盘IO性能!

因此,该行为已更改以提高性能。

性能调整Web服务器中:

该系统全局开关NtfsDisableLastAccessUpdate(REG_DWORD)1位于HKLM \ System \ CurrentControlSet \ Control \ FileSystem下,并默认设置为1。通过禁用上次访问文件或目录的日期和时间戳更新,此开关可以减少磁盘I / O负载和延迟。 Windows Server 2016,Windows Server 2012 R2,Windows Server 2012,Windows Server 2008 R2和Windows Server 2008的干净安装默认启用此设置,您无需调整它。早期版本的Windows未设置此密钥。如果您的服务器运行较早版本的Windows,或者已升级到Windows Server 2016,Windows Server 2012 R2,Windows Server 2012,Windows Server 2008 R2或Windows Server 2008,则应启用此设置。
似乎该设置仍可在Windows Server 2016中使用。
我认为Java代码在flush()方面是正确的,因为在Windows Server 2008上的Java 8上相同的类会导致File Explorer进行更新。当运行TYPE和Notepad时,我也看到时间戳记录与系统时钟匹配,但晚于“上次修改”时间。

刷新不等于同步。每个记录发布后,FileHandler只执行刷新操作。Windows未设置强制写入元数据到文件系统。来自在不关闭文件的情况下修改文件时,“日期修改”属性不更新。

在2008年,即使按F5刷新视图,日志文件上的“上次修改”字段也不会更新,除非另一个程序尝试打开该文件或停止实用程序。

资源管理器从NTFS获取其信息,通过使用cmd提示符和“dir”,我们发现直到关闭对文件的句柄,文件的NTFS元数据才会更新。

刷新文件夹信息只会访问NTFS元数据缓存,但显式查询文件将强制磁盘I/O以获取属性 - 这是Vista引入的设计更改,旨在减少不必要的磁盘I/O以提高性能。
有一些例外情况:
- 在某些情况下,“dir文件名”足以刷新元数据。 - “特殊”文件夹可能会被处理得不同,例如用户配置文件,我们不希望有大量文件并且希望能够依赖所呈现的文件数据。 - 内核过滤驱动程序可能会更改行为,因为它们“添加、删除或更改其他驱动程序的功能”。
由于解决方法是任何进程打开并关闭句柄到日志文件,因此编写了一个工具来执行此操作,并获取文件信息,使用以下API:
- CreateFile - GetFileInformationByHandle - CloseHandle 您可以尝试使用FileHandler创建的文件名打开FileInputStream。

只有在DOS TYPE运行或在记事本中打开/关闭(不保存)文件,似乎会导致文件资源管理器和DOS DIR更新。

我发现唯一一种通用的从外部过程更新元数据的方法是通过交互式地使用文件资源管理器选择一个文件

explorer /select, c:\test\file.txt

很可能这与记事本中发生的情况非常相似。

我喜欢你使用 TYPE 命令的方式。你可以将其与 nul 一起使用以忽略输出。

type filename.log > NUL

通过使用元数据开关运行dir可能会强制更新元数据:

dir /A /R /Q filename.log > nul

感谢您抽出时间查看。我也偶然发现了这些帖子。正如原始线程上的评论所确认的那样,regy更改无效。在我的Java中,如果我获取FileDescriptor并调用sync()(如您建议的),它确实会导致“修改日期”更新(即使没有按[F5])。我实现了一个TimerTask来每分钟进行一次sync(),因为我不太关心精度到秒级别。__然而__,这解决了我的Java问题,但无法解决我无法重新编码的任何问题。我会点赞您的答案,但不会将其标记为解决方案,因为它似乎是一个> = WS2008R2问题。 - lafual
@lafaul 在Windows资源管理器中选择文件似乎是唯一一个对我有效的方法。我个人无法以自动化的方式正确地完成这项任务。 - jmehrens

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