2017-04-11 116 views
2

我遇到了一个问题,即用Java编写的归档模块无法清理通过smb共享的文件(如果在清理过程中由网络用户打开)。下面是对文件的清理代码的简化版本:Java删除文件unix方式(unlink header)

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; 
    } 
} 

它的工作原理,当我在两个ftp会话测试罚款: 会议答:

cat -v /dev/zero > sourceFile.txt 

会议B:

java -jar JavaUnixFileRemovalTest.jar sourceFile.txt targetFile.txt 

但是在使用网络共享和用户时生产失败。

我想实现的是将文件复制到存档文件夹并取消链接标题。这样,如果用户仍然打开文件,他将继续访问内容,而名称从文件系统中删除,以便其他人无法看到该文件。

所以现在的问题是,如果有一种方法,通过本地Java取消链接文件头中的Unix指没有显式调用unlink命令

+0

你为什么叫'新文件(targetFilePath)'三次? – EJP

+0

是的,我知道。这是一种原始代码的复制粘贴,与前一个团队很早以前编写的代码相同。我还没做过任何重构。相信我,这不是代码中最糟糕的部分 –

回答

1

经过一番研究,我决定有点不同的方式来处理这个问题,并施放强大的失落的魔法古人 - 也就是使用原生系统下用的JNA (Java Native Access)

求助电话下面是一些解释为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解除链接工具!测试场景:创建会话中的一个文本文件,在less在会话B打开并运行在会话A.按预期运行Java代码:

[[email protected] 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