Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get unique file id in Windows with Java?

I'm looking for a way to get a unique file id in a Java application, and came across this:

Unique file identifier in windows

Now, I tried the answer supplied by Ashley Henderson himself (the one that asked the question), and that worked fine in C#. But I need to do this in Java, in order to have the app work across platforms.

Is there any way to port this to Java, or get to the same id some other way?

EDIT:

I almost got it working now, using the solution by eee, only I need it to be in a library, and when I compile it as a library I get an error, even though everything is working fine in a test application with everything included. But with a separate library that I try to import (no compiler errors) I get this runtime error:

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)

I've included the jna.jar and platform.jar in the library when I compiled it... Please note again that I'm very new to Java, but what am I doing wrong?

like image 300
Anders Avatar asked Nov 29 '11 10:11

Anders


2 Answers

Using JNA version 3.3.0:

Kernel32.INSTANCE.GetFileInformationByHandle Test case:

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());

    }

}

Sample output:

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 instance class:

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
            );
}
like image 192
ecle Avatar answered Oct 05 '22 02:10

ecle


In Java you would need JNI, native C compilation, both for Windows (using the C# code), and for Unix/Linux (using the inode of a file). Honestly I do not think this is very safe.

like image 29
Joop Eggen Avatar answered Oct 05 '22 02:10

Joop Eggen