我遇到的问题是,如果在清理期间由网络用户打开,用Java编写的归档模块无法清除通过smb共享的文件。下面是文件清理代码的简化版本:
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = (new File(targetFilePath)).delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(new File(targetFilePath));
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
return false;
} else {
Logger.INFO("Move succeeded");
return true;
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
}
我在两个Linux会话中测试它时工作正常: 会议A:
cat -v /dev/zero > sourceFile.txt
会议B:
java -jar JavaUnixFileRemovalTest.jar sourceFile.txt targetFile.txt
但在使用网络共享和用户时生产失败。
我想要实现的是将文件复制到存档文件夹并取消链接标题。这样,如果用户仍然打开了文件,他将继续访问内容,同时从文件系统中删除名称,以便其他人无法看到该文件。
所以问题是,如果有一种方法可以通过本机Java方式在Unix中取消链接文件头,而无需显式调用unlink
命令
答案 0 :(得分:2)
经过一番研究后,我决定以一种不同的方式解决这个问题并投下强大的古代魔法 - 也就是说,在JNA (Java Native Access)的帮助下使用原生系统C调用
以下是JNA首次使用者的一些代码示例:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import java.io.File;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Main {
private static CStdLib cStdLib;
// Here you specify prototypes of native C methods to be called during runtime
// Because unlink(char *path) uses pointer to const char as argument, a wrapper class StringByReference is used to convert data types
// Link to other examples at the end of this post
public interface CStdLib extends Library {
int unlink(StringByReference path);
}
public static void main(String[] args) {
// Here I'm declaring libc usage, but you can link anything. Even your own libraries
cStdLib = (CStdLib)Native.loadLibrary("c", CStdLib.class);
Logger.INFO("Source file: " + args[0]);
Logger.INFO("Target file: " + args[1]);
moveFile(args[0],args[1]);
}
private static boolean moveFile(String sourceFilePath, String targetFilePath) {
boolean fileStatus = false;
File sourceFile = new File(sourceFilePath );
File targetFile = new File(targetFilePath );
if(sourceFile.canRead() && sourceFile.canWrite() ) {
if(targetFile.exists()) {
fileStatus = targetFile.delete();
if(!fileStatus) {
Logger.ERROR("Target deletion failed");
}
}
fileStatus = sourceFile.renameTo(targetFile);
if(!fileStatus) {
Logger.ERROR("RenameTo method failed");
Logger.INFO("Trying to copy file and unlink the original");
// ToDo: add copy method
// That's where we convert String to char*
StringByReference unlinkPath=new StringByReference(sourceFilePath);
int status=cStdLib.unlink(unlinkPath);
if(status==0){
Logger.INFO("Unlink succeeded");
}else {
Logger.ERROR("Unlink also failed");
return false;
}
} else {
Logger.INFO("Move succeeded");
}
} else {
Logger.ERROR("Cannot read file");
return false;
}
return true;
}
}
用于转换数据类型的类:
package com.WeLoveStackOverflow.JavaJNAUnlinkTest;
import com.sun.jna.ptr.ByReference;
public class StringByReference extends ByReference {
public StringByReference() {
this(0);
}
public StringByReference(String str) {
super(str.length() < 4 ? 4 : str.length() + 1);
setValue(str);
}
private void setValue(String str) {
getPointer().setString(0, str);
}
}
那么我们最终得到了什么?一个很好的Java unlink实用程序!测试场景:在会话A中创建一个文本文件,在会话B中的less
中打开它,并在会话A中运行java代码。按预期工作:
[me@server1 JavaFileTest]$ lsof | grep sourceFile
less 12611 me 4r REG 253,0 0 73 /home/me/JavaFileTest/sourceFile (deleted)
这是我用作参考的文章: http://jnaexamples.blogspot.com/2012/03/java-native-access-is-easy-way-to.html 它包含了为C调用包装数据类型的其他好例子
提示:
JNA 4.4.0需要GLIBC_2.14。如果您收到此错误,那么 简单地降级JNA(4.2.2为我工作)
Exception in thread "main" java.lang.UnsatisfiedLinkError: /lib64/libc.so.6: version 'GLIBC_2.14' not found