Java删除文件unix方式(取消链接头)

时间:2017-04-11 09:33:12

标签: java

我遇到的问题是,如果在清理期间由网络用户打开,用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命令

1 个答案:

答案 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和JNA平台文件
  • 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