Java 1.7中的符号链接lastModifiedTime
我正在尝试更改没有目标的符号链接的lastModifiedTime值 例如:foo-->nothing 我可以使用Java 1.7中的符号链接lastModifiedTime,java,time,symlink,Java,Time,Symlink,我正在尝试更改没有目标的符号链接的lastModifiedTime值 例如:foo-->nothing 我可以使用 String fooPath=“/Users/me/test/foo”; 路径路径=新文件(fooPath).toPath(); FileTime t=Files.getLastModifiedTime(路径,LinkOption.NOFOLLOW\u LINKS); 但是,我无法使用下面的代码段设置相同的符号链接;这为目标提供了一个java.nio.file.NoSuchFil
String fooPath=“/Users/me/test/foo”;
路径路径=新文件(fooPath).toPath();
FileTime t=Files.getLastModifiedTime(路径,LinkOption.NOFOLLOW\u LINKS);
但是,我无法使用下面的代码段设置相同的符号链接;这为目标提供了一个java.nio.file.NoSuchFileException
String fooPath=“/Users/me/test/foo”;
路径路径=新文件(fooPath).toPath();
FileTime t=FileTime.fromMillis(date.getTime());
setLastModifiedTime(路径,t);
我甚至尝试手动设置属性,但这给了我一个java.nio.file.FileSystemException
“符号链接级别太多或无法访问符号链接的属性”错误:
Files.setAttribute(路径,“lastModifiedTime”,t,LinkOption.NOFOLLOW\u LINKS);
我不想走系统调用路线,因为我需要跨平台支持。这可以说是JDK中的一个缺陷或限制,至少在Linux和Solaris上是如此(我还没有尝试Windows)。假设您创建的
BasicFileAttributeView
没有link选项。没有follow\u LINKS
。问题是sun.nio.fs.UnixFileAttributeViews$Basic.setTimes()
调用sun.nio.fs.UnixPath.openForAttributeAccess()
,这反过来又调用符号链接上的open
/open64
。现在,如果符号链接有一个目标,这将成功并返回指向目标的fdsetTimes()
然后在fd上调用futimesat
,以更新访问和修改时间。但是,这将更新链接目标的修改时间,而不是链接本身,这不是您想要的,并且如果链接断开,将不起作用
因此,当您请求BasicFileAttributeView
时,您会认为答案是通过LinkOption.NOFOLLOW\u LINKS
。但是,在该场景中,openForAttributeAccess()
将O_NOFOLLOW
传递到open
,指定在出现符号链接时返回ELOOP
错误,这将导致您提到的错误消息。无论如何,由于无法获得符号链接的fd,JDK使用的策略将不起作用。它需要放弃fd,而是使用sayutimensat
或lutimes
不幸的是,看起来使用系统调用(比如使用JNA)是这里唯一的选择
utimensat
是POSIX 2008的标准方式,但它非常新,许多类Unix操作系统还没有,或者只在最新版本中才有lutimes
存在于Linux和BSD上,但它是非标准的。以下是使用FileTime作为输入的utimensat的JNA代码
POM相关性:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.2.2</version>
</dependency>
net.java.dev.jna
jna
4.2.2
爪哇
import java.nio.file.Path;
导入java.nio.file.attribute.FileTime;
导入java.util.array;
导入java.util.List;
导入java.util.concurrent.TimeUnit;
导入com.sun.jna.Library;
导入com.sun.jna.Native;
导入com.sun.jna.NativeLong;
导入com.sun.jna.Structure;
公共类FileUtil{
符号链接处的公共静态最终整数=0x100;
公共接口CLibrary扩展库{
CLibrary实例=(CLibrary)Native.loadLibrary(“c”,CLibrary.class);
int-utimensat(int-dirfd、字符串文件名、timespec-times、int标志);
}
公共静态类timespec扩展结构{
公共静态类ByReference扩展timespec实现结构。ByReference{}
公共国家电视节目_sec;//秒
公共本地电视\u nsec;//纳秒
公共时间段(){
}
@凌驾
受保护列表getFieldOrder(){
返回Arrays.asList(新字符串[]{“tv_-sec”,“tv_-nsec”});
}
}
公共静态布尔值changeFileTime(路径文件、文件时间atime、文件时间mtime){
timespec times=新timespec.ByReference();
timespec[]VAL=(timespec[]次)toArray(2);
设置时间(VAL[0],atime);
设置时间(VAL[1],mtime);
int rtn=CLibrary.INSTANCE.utimensat(0,file.toString(),times,AT_SYMLINK_NOFOLLOW);
返回(rtn==0);
}
私有静态void设置时间(timespec val,FileTime){
val.tv_sec=新的NativeLong(time.to(TimeUnit.SECONDS));
val.tv_nsec=new NativeLong(time.toInstant().getNano());
}
}
即使链接没有目标,也可以使用touch-mht 200805191919/Users/me/test/foo在命令行上更改modtime。不幸的是,~unix的所有版本上都不存在touch-h。
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Structure;
public class FileUtil {
public static final int AT_SYMLINK_NOFOLLOW = 0x100;
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int utimensat(int dirfd, String filename, timespec times, int flags);
}
public static class timespec extends Structure {
public static class ByReference extends timespec implements Structure.ByReference {}
public NativeLong tv_sec; // seconds
public NativeLong tv_nsec; // nanoseconds
public timespec() {
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "tv_sec", "tv_nsec" });
}
}
public static boolean changeFileTime(Path file, FileTime atime, FileTime mtime) {
timespec times = new timespec.ByReference();
timespec[] vals = (timespec[])times.toArray(2);
setTime(vals[0], atime);
setTime(vals[1], mtime);
int rtn = CLibrary.INSTANCE.utimensat(0, file.toString(), times, AT_SYMLINK_NOFOLLOW);
return (rtn == 0);
}
private static void setTime(timespec val, FileTime time) {
val.tv_sec = new NativeLong(time.to(TimeUnit.SECONDS));
val.tv_nsec = new NativeLong(time.toInstant().getNano());
}
}