在文件上设置/更改ctime或“更改时间”属性

11

我希望使用 java.nio.Files 类在 Java 中更改文件的时间戳元数据。

我想要更改所有 3 个 Linux/ext4 时间戳(最后修改、访问和更改)。

我可以按照以下方式更改前两个时间戳字段:

Files.setLastModifiedTime(pathToMyFile, myCustomTime);
Files.setAttribute(pathToMyFile, "basic:lastAccessTime", myCustomTime);

然而,我无法修改文件上的最后一个更改时间。另外,令人担忧的是,在文档中没有提到更改时间戳。最接近的可用属性是creationTime,但我尝试失败了。

有什么想法可以根据自定义时间戳在Java中修改文件的Change:元数据吗?

谢谢!


在Linux终端中,对于ls输出,它显示了最后修改的时间,你尝试过修改它吗? - Pradeep Pati
是的。我成功使用上面第一行代码修改了最后修改时间。 - Eitan
没有“更改时间戳”,因为ctime(应该是)文件的创建时间,而不是它被更改的时间(“lastModifiedTime”是最后修改或“更改”的时间)。 - Jürgen A. Erhard
2个回答

18

我能使用两种不同的方法修改ctime:

  1. 更改内核,使得 ctime mtime 匹配
  2. 编写一个简单(但有些hacky)的shell脚本。

第一种方法:更改内核。

我只需要调整 KERNEL_SRC/fs/attr.c 中的几行代码。这个修改会在每次“明确定义” mtime 时更新 ctime

有许多方法可以“明确定义” mtime ,例如:

在Linux中:

touch -m --date="Wed Jun 12 14:00:00 IDT 2013" filename
在Java中(使用Java 6或7,以及可能的其他版本):
long newModificationTime = TIME_IN_MILLIS_SINCE_EPOCH;
File myFile = new File(myPath);
newmeta.setLastModified(newModificationTime);

这是在notify_change函数中对KERNEL_SRC/fs/attr.c进行的更改:

    now = current_fs_time(inode->i_sb);

    //attr->ia_ctime = now;  (1) Comment this out
    if (!(ia_valid & ATTR_ATIME_SET))
        attr->ia_atime = now;
    if (!(ia_valid & ATTR_MTIME_SET)) {
        attr->ia_mtime = now;
    }
    else { //mtime is modified to a specific time. (2) Add these lines
        attr->ia_ctime = attr->ia_mtime; //Sets the ctime
        attr->ia_atime = attr->ia_mtime; //Sets the atime (optional)
    }

(1) 这行代码,如果不注释掉,在文件发生更改时会将ctime更新为当前的系统时间。我们不想要这种情况发生,因为我们希望自己设置ctime。因此,我们注释掉了这行代码。(这不是强制性的)

(2) 这实际上是解决方案的核心。在文件被修改后,执行notify_change函数来更新时间元数据。如果没有指定mtime,则将其设置为当前时间。否则,如果将mtime设置为特定值,则我们还将ctime和atime设置为该值。

第二种方法:简单(但有点hacky)的shell脚本。

简要说明:

  1. 更改系统时间为目标时间
  2. 对文件执行chmod命令,文件的ctime现在反映出目标时间
  3. 将系统时间恢复为原来的时间。

changectime.sh

#!/bin/sh
now=$(date)
echo $now
sudo date --set="Sat May 11 06:00:00 IDT 2013"
chmod 777 $1
sudo date --set="$now"

按以下方式运行脚本:

./changectime.sh MYFILE

文件的ctime将反映文件中的时间。

当然,您可能不希望该文件具有777权限,请在使用之前确保修改此脚本以适应您的需求。


2
需要更改脚本。现在=$(date)不能(总是?)获取有效的日期格式进行设置。使用:now=$(date +"%Y-%M-%d %T")。那个脚本/方法很好,对我有用。 - gaoithe
1
不错的解决方法!.. 不过针对我的当前用例,我只会将原始分区镜像到新目标驱动器上,然后扩大文件系统 - 直到我有时间参与内核修改游戏.. 也许到那时,有人想出了一个适当的系统调用,而不是这种疯狂的方式.. - eMPee584

3

这个答案应用到你的情况:

// Warning: Disk must be unmounted before this operation
String disk = "/dev/sda1";
// Update ctime
Runtime.getRuntime().exec("debugfs -w -R 'set_inode_field "+pathToMyFile+" ctime "+myCustomTime+"' "+disk);
// Drop vm cache so ctime update is reflected
Runtime.getRuntime().exec("echo 2 > /proc/sys/vm/drop_caches");

我怀疑我们不会在Java标准API中看到一个方便的方法来实现这个,因为Linux(man touch)和Windows(MSDN上的GetFileTime函数)都不能轻松访问此字段。本地系统调用仅提供访问创建/访问/修改时间戳的权限,Java也一样。


1
有没有其他的方法可以让我保持磁盘挂载? - Eitan

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