【问题标题】:Get unique file id in Windows with Java?使用 Java 在 Windows 中获取唯一的文件 ID?
【发布时间】:2011-11-29 10:25:46
【问题描述】:

我正在寻找一种在 Java 应用程序中获取唯一文件 ID 的方法,并遇到了这个问题:

Unique file identifier in windows

现在,我尝试了 Ashley Henderson 本人(提出问题的那个人)提供的答案,并且在 C# 中运行良好。但我需要在 Java 中执行此操作,以便让应用程序跨平台工作。

有没有办法将它移植到 Java,或者以其他方式获取相同的 id?

编辑:

我现在几乎可以使用 eee 的解决方案了,我只需要将它放在库中,当我将它编译为库时出现错误,即使在测试应用程序中一切正常一切都包括在内。但是我尝试导入一个单独的库(没有编译器错误)我得到这个运行时错误:

debug:
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/jna/Structure
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    at winfileid.FileId.getFileId(FileId.java:37)
    at testfileid.TestFileId.main(TestFileId.java:19)
Caused by: java.lang.ClassNotFoundException: com.sun.jna.Structure
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 14 more
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)

我在编译时已将 jna.jar 和 platform.jar 包含在库中...请再次注意,我对 Java 很陌生,但我做错了什么?

【问题讨论】:

  • 我怀疑你必须使用 JNI 来获取它。为什么你仍然想要这些信息?
  • 用例是什么 - 为什么需要唯一 ID?
  • 用例是在文件被移动或重命名时跟踪文件,以保留来自其他文件的链接。
  • @AndersSvensson 由于您的最新编辑使用了我的解决方案,因此在您的编辑中应如此说明。否则,任何人都会对此感到困惑。关于异常错误,您是使用 Eclipse/Netbean IDE 编译它还是从命令行编译它?这将有助于解决问题...
  • 对,对不起,编辑它以表明编辑基于您的解决方案。我用 NetBeans 编译。

标签: java windows filesystems


【解决方案1】:

使用 JNA 3.3.0 版:

Kernel32.INSTANCE.GetFileInformationByHandle 测试用例:

package win.test;

import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinBase.FILETIME;
import com.sun.jna.platform.win32.WinNT.HANDLE;

import win.test.Kernel32.BY_HANDLE_FILE_INFORMATION;


public class FileTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
        final int FILE_SHARE_READ = (0x00000001);
        //final int FILE_SHARE_WRITE = (0x00000002);
        //final int FILE_SHARE_DELETE = (0x00000004);
        final int OPEN_EXISTING = (3);
        final int GENERIC_READ = (0x80000000);
        //final int GENERIC_WRITE = (0x40000000);
        //final int FILE_FLAG_NO_BUFFERING = (0x20000000);
        //final int FILE_FLAG_WRITE_THROUGH = (0x80000000);
        //final int FILE_READ_ATTRIBUTES = (0x0080);
        //final int FILE_WRITE_ATTRIBUTES = (0x0100);
        //final int ERROR_INSUFFICIENT_BUFFER = (122);
        final int FILE_ATTRIBUTE_ARCHIVE = (0x20);

        WinBase.SECURITY_ATTRIBUTES attr = null;
        BY_HANDLE_FILE_INFORMATION lpFileInformation = new BY_HANDLE_FILE_INFORMATION();
        HANDLE hFile = null;

        hFile = Kernel32.INSTANCE.CreateFile(args[0], GENERIC_READ, FILE_SHARE_READ, attr, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, null);

        System.out.println("CreateFile last error:" + Kernel32.INSTANCE.GetLastError());

        //if (hFile. != -1)
        {

            win.test.Kernel32.INSTANCE.GetFileInformationByHandle(hFile, lpFileInformation);

            System.out.println("CREATION TIME: " + FILETIME.filetimeToDate(lpFileInformation.ftCreationTime.dwHighDateTime, lpFileInformation.ftCreationTime.dwLowDateTime));

            System.out.println("VOLUME SERIAL NO.: "  + Integer.toHexString(lpFileInformation.dwVolumeSerialNumber.intValue()));

            System.out.println("FILE INDEX HIGH: "  + lpFileInformation.nFileIndexHigh);
            System.out.println("FILE INDEX LOW: "  + lpFileInformation.nFileIndexLow);


            System.out.println("GetFileInformationByHandle last error:" + Kernel32.INSTANCE.GetLastError());
        }

        Kernel32.INSTANCE.CloseHandle(hFile);

        System.out.println("CloseHandle last error:" + Kernel32.INSTANCE.GetLastError());

    }

}

样本输出:

CreateFile last error:0
CREATION TIME: Tue Nov 29 22:24:04 SGT 2011
VOLUME SERIAL NO.: 900c0655
FILE INDEX HIGH: 1769472
FILE INDEX LOW: 286306
GetFileInformationByHandle last error:0
CloseHandle last error:0

Kernel32 JNA 实例类:

package win.test;

import java.util.HashMap;
import java.util.Map;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinBase.FILETIME;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;

public interface Kernel32 extends StdCallLibrary {
    final static Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
        private static final long serialVersionUID = 1L;
        {
            put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
            put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
        }
    };

    public Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("Kernel32", Kernel32.class, WIN32API_OPTIONS);

    public int GetLastError();

    /**
    typedef struct _BY_HANDLE_FILE_INFORMATION {
          DWORD    dwFileAttributes;
          FILETIME ftCreationTime;
          FILETIME ftLastAccessTime;
          FILETIME ftLastWriteTime;
          DWORD    dwVolumeSerialNumber;
          DWORD    nFileSizeHigh;
          DWORD    nFileSizeLow;
          DWORD    nNumberOfLinks;
          DWORD    nFileIndexHigh;
          DWORD    nFileIndexLow;
        } BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION;
     */

    public class BY_HANDLE_FILE_INFORMATION extends Structure {
        public DWORD    dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public DWORD    dwVolumeSerialNumber;
        public DWORD    nFileSizeHigh;
        public DWORD    nFileSizeLow;
        public DWORD    nNumberOfLinks;
        public DWORD    nFileIndexHigh;
        public DWORD    nFileIndexLow;
        public static class ByReference extends BY_HANDLE_FILE_INFORMATION implements Structure.ByReference {

        };
        public static class ByValue extends BY_HANDLE_FILE_INFORMATION implements Structure.ByValue {

        };        
    }; 

    /**
    BOOL WINAPI GetFileInformationByHandle(
              __in   HANDLE hFile,
              __out  LPBY_HANDLE_FILE_INFORMATION lpFileInformation
            );
    */
    boolean GetFileInformationByHandle(
              HANDLE hFile,
              BY_HANDLE_FILE_INFORMATION lpFileInformation
            );
}

【讨论】:

  • 哇,感谢您的详细回答...!不过,正如我所提到的,这有点超出我的想象,而且我对 Java 完全陌生,之前只用 C# 编程过。但是既然您提供了如此详细的示例,我必须尝试一下...但是我不明白您在哪里指定要检查的文件?它可能在那里,但我很难解码它。另外,文件索引高与文件索引低是什么?在我使用的示例中(来自链接)只有一个索引值,那么我应该在这里使用哪个来标识文件?
  • 顺便说一句,由于 JNA 似乎用于访问 dll 中的本机代码,因此无法通过将示例链接中的代码(我已经在 C# 中工作)中的代码编译成一个dll,然后用JNA调用它?如果是的话,我真的很感激一个简单的例子......我只是希望这可能会更简单。
  • @AndersSvensson 是的,你可以这样做,但它有点困难,因为你从 C# DLL 而不是 C/C++ DLL 开始,后者是 JNA 中首选的 DLL 调用约定。您需要先将 C# DLL 包装到 C/C++ DLL 中,然后才能将其与 JNA 一起使用。这就是我对 JNA 的理解。
  • @AndersSvensson 哦,args[0] 来自您需要传递给程序的程序命令参数;例如:FileTest "test.txt" 其中"test.txt" 将是FileTest 程序的args[0] 的值
  • @AndersSvensson 要成功运行程序,需要下载JNA平台库(jna.jarplatform.jar),添加为引用库并设置系统属性-Djna.library.path=&lt;relative folder where the jars can be found&gt;download here
【解决方案2】:

在 Java 中,您需要 JNI,本机 C 编译,既适用于 Windows(使用 C# 代码),也适用于 Unix/Linux(使用文件的 inode)。老实说,我认为这不是很安全。

【讨论】:

  • +1 使用中的文件系统也很重要,这进一步使可移植性变得更加困难——例如 FAT 祝你好运:)
  • 是的,我简要地研究了一下,希望有更简单的方法。但我希望不必编译它并在Java中使用它,而是如果有办法在Java中重写它以获得相同的ID......在*nix中获取文件ID要简单得多,但除了 C# 中的这个示例之外,我找不到在 Windows 上执行此操作的方法。顺便说一句,FAT 不是问题。它将是 Windows 中的 NTFS,而 Mac OS X 是我需要考虑的另一个操作系统。
【解决方案3】:

你不能使用文件路径作为它的唯一ID吗?!

完整的文件路径足够独特...

【讨论】:

  • 是的,它是独一无二的 - 但是当您将文件移动到另一个目录时它不会被保留,这似乎是文件 ID 背后的意图。
  • 对,关键是要能够随意移动文件和重命名文件,所以文件路径实际上是我在移动或重命名后需要找出的。
【解决方案4】:

通过挂载的卷和各种类型的链接/重解析点,可以有多个路径指向同一个文件。唯一文件 ID API 是我所知道的唯一方法来确定看似相同文件的多个路径是指唯一文件还是通过不同路径引用相同文件。

话虽如此,我同意唯一的 java 通用方式将涉及 C 或 C++ 代码和 JNI。虽然这样做可能会提供在 Linux 和 Windows 上工作的解决方案,但如果使用不同的后端库,并且对托管 java 代码有一个共同的表示,那么做得对。

【讨论】:

    猜你喜欢
    • 2022-12-05
    • 2017-12-25
    • 2018-07-03
    • 1970-01-01
    • 2013-01-31
    • 2014-08-27
    • 2014-10-30
    • 2012-12-08
    • 1970-01-01
    相关资源
    最近更新 更多