Java get and set windows system file creation time via JNA (Java Native Access)

来自TideWiki
跳转到: 导航, 搜索
Java 通过 JNA (Java Native Access) 获取、设置 Windows 操作系统的文件创建时间、文件修改时间、文件访问时间
Java get/set file Creation/LastWrite/LastAccess time of Windows operation system via JNA (Java Native Access)

目录

概述

最近有个项目,需要把文件从 Web 服务器上下载下来,并根据 Web 服务器返回的文件时间设置为本地文件的“创建时间”(有点像 FlashGet 1.73 General 选项中的“Get File Date And Time From Server”一样)。


java.io.File 里提供的只有设置文件的“最后修改时间”,而文件的“创建时间”是 Windows 操作系统特有的东西,网上对此问题的答案基本都是用 C/C++ 自己写一个 DLL,然后通过 JNI - Java Native Interface 调用之。方法就是这样,只是有没有一种纯 Java 的解决方法?


依旧依赖 Google 的搜索,找到了 JNA - Java Native Access ( http://jna.dev.java.net )。JNA 官方网站的解释:


JNA provides Java programs easy access to native shared libraries (DLLs on Windows) without writing anything but Java code—no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes. Access is dynamic at runtime without code generation.

JNA allows you to call directly into native functions using natural Java method invocation. The Java call looks just like it does in native code. Most calls require no special handling or configuration; no boilerplate or generated code is required.

The JNA library uses a small native library stub to dynamically invoke native code. The developer uses a Java interface to describe functions and structures in the target native library. This makes it quite easy to take advantage of native platform features without incurring the high overhead of configuring and building JNI code for multiple platforms.

While some attention is paid to performance, correctness and ease of use take priority.

JNA includes a platform library with many native functions already mapped as well as a set of utility interfaces that simplify native access.


虽然 JNA 目前仍处于“孵化阶段”(3.2.7),但对于目前的需求已经足够用了。下面的示例代码涉及到 Win32 API 的 6 个函数:

示例代码

JNA 获取/设置 Windows 操作系统文件时间(创建时间、最后修改时间、最后访问时间)的示例代码:

import java.io.*;
import java.nio.*;
import java.util.Date;

// Java Native Access: http://jna.dev.java.net
// Test with jna-3.2.7
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.*;
import com.sun.jna.platform.win32.*;

// http://blog.csdn.net/lovetide
// 2010-07-23

public class WindowsFileTime
{
	public static final int GENERIC_READ = 0x80000000;
	//public static final int GENERIC_WRITE = 0x40000000;	// defined in com.sun.jna.platform.win32.WinNT
	public static final int GENERIC_EXECUTE = 0x20000000;
	public static final int GENERIC_ALL = 0x10000000;

	// defined in com.sun.jna.platform.win32.WinNT
	//public static final int CREATE_NEW = 1;
	//public static final int CREATE_ALWAYS = 2;
	//public static final int OPEN_EXISTING = 3;
	//public static final int OPEN_ALWAYS = 4;
	//public static final int TRUNCATE_EXISTING = 5;

	public interface MoreKernel32 extends Kernel32
	{
		static final MoreKernel32 instance = (MoreKernel32)Native.loadLibrary ("kernel32", MoreKernel32.class, W32APIOptions.DEFAULT_OPTIONS);
		boolean GetFileTime (WinNT.HANDLE hFile, WinBase.FILETIME lpCreationTime, WinBase.FILETIME lpLastAccessTime, WinBase.FILETIME lpLastWriteTime);
		boolean SetFileTime (WinNT.HANDLE hFile, final WinBase.FILETIME lpCreationTime, final WinBase.FILETIME lpLastAccessTime, final WinBase.FILETIME lpLastWriteTime);
	}

	static MoreKernel32 win32 = MoreKernel32.instance;
	//static Kernel32 _win32 = (Kernel32)win32;

	static WinBase.FILETIME _creationTime = new WinBase.FILETIME ();
	static WinBase.FILETIME _lastWriteTime = new WinBase.FILETIME ();
	static WinBase.FILETIME _lastAccessTime = new WinBase.FILETIME ();

	static boolean GetFileTime (String sFileName, Date creationTime, Date lastWriteTime, Date lastAccessTime)
	{
		WinNT.HANDLE hFile = OpenFile (sFileName, GENERIC_READ);	// may be WinNT.GENERIC_READ in future jna version.
		if (hFile == WinBase.INVALID_HANDLE_VALUE) return false;

		boolean rc = win32.GetFileTime (hFile, _creationTime, _lastAccessTime, _lastWriteTime);
		if (rc)
		{
			if (creationTime != null) creationTime.setTime (_creationTime.toLong());
			if (lastAccessTime != null) lastAccessTime.setTime (_lastAccessTime.toLong());
			if (lastWriteTime != null) lastWriteTime.setTime (_lastWriteTime.toLong());
		}
		else
		{
			int iLastError = win32.GetLastError();
			System.out.print ("获取文件时间失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
		}
		win32.CloseHandle (hFile);
		return rc;
	}
	static boolean SetFileTime (String sFileName, final Date creationTime, final Date lastWriteTime, final Date lastAccessTime)
	{
		WinNT.HANDLE hFile = OpenFile (sFileName, WinNT.GENERIC_WRITE);
		if (hFile == WinBase.INVALID_HANDLE_VALUE) return false;

		ConvertDateToFILETIME (creationTime, _creationTime);
		ConvertDateToFILETIME (lastWriteTime, _lastWriteTime);
		ConvertDateToFILETIME (lastAccessTime, _lastAccessTime);

		//System.out.println ("creationTime: " + creationTime);
		//System.out.println ("lastWriteTime: " + lastWriteTime);
		//System.out.println ("lastAccessTime: " + lastAccessTime);

		//System.out.println ("_creationTime: " + _creationTime);
		//System.out.println ("_lastWriteTime: " + _lastWriteTime);
		//System.out.println ("_lastAccessTime: " + _lastAccessTime);

		boolean rc = win32.SetFileTime (hFile, creationTime==null?null:_creationTime, lastAccessTime==null?null:_lastAccessTime, lastWriteTime==null?null:_lastWriteTime);
		if (! rc)
		{
			int iLastError = win32.GetLastError();
			System.out.print ("设置文件时间失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
		}
		win32.CloseHandle (hFile);
		return rc;
	}
	static void ConvertDateToFILETIME (Date date, WinBase.FILETIME ft)
	{
		if (ft != null)
		{
			long iFileTime = 0;
			if (date != null)
			{
				iFileTime = WinBase.FILETIME.dateToFileTime (date);
				ft.dwHighDateTime = (int)((iFileTime >> 32) & 0xFFFFFFFFL);
				ft.dwLowDateTime = (int)(iFileTime & 0xFFFFFFFFL);
			}
			else
			{
				ft.dwHighDateTime = 0;
				ft.dwLowDateTime = 0;
			}
		}
	}

	static WinNT.HANDLE OpenFile (String sFileName, int dwDesiredAccess)
	{
		WinNT.HANDLE hFile = win32.CreateFile (
			sFileName,
			dwDesiredAccess,
			0,
			null,
			WinNT.OPEN_EXISTING,
			0,
			null
			);
		if (hFile == WinBase.INVALID_HANDLE_VALUE)
		{
			int iLastError = win32.GetLastError();
			System.out.print ("	打开文件失败,错误码:" + iLastError + " " + GetWindowsSystemErrorMessage (iLastError));
		}
		return hFile;
	}
	static String GetWindowsSystemErrorMessage (int iError)
	{
		char[] buf = new char[255];
		CharBuffer bb = CharBuffer.wrap (buf);
		//bb.clear ();
		//PointerByReference pMsgBuf = new PointerByReference ();
		int iChar = win32.FormatMessage (
				WinBase.FORMAT_MESSAGE_FROM_SYSTEM
					//| WinBase.FORMAT_MESSAGE_IGNORE_INSERTS
					//|WinBase.FORMAT_MESSAGE_ALLOCATE_BUFFER
					,
				null,
				iError,
				0x0804,
				bb, buf.length,
				//pMsgBuf, 0,
				null
			);
		//for (int i=0; i<iChar; i++)
		//{
		//	System.out.print (" ");
		//	System.out.print (String.format("%02X", buf[i]&0xFFFF));
		//}
		bb.limit (iChar);
		//System.out.print (bb);
		//System.out.print (pMsgBuf.getValue().getString(0));
		//win32.LocalFree (pMsgBuf.getValue());
		return bb.toString ();
	}

	public static void main (String[] args) throws Exception
	{
		if (args.length == 0)
		{
			System.out.println ("获取 Windows 的文件时间(创建时间、最后修改时间、最后访问时间)");
			System.out.println ("用法:");
			System.out.println ("	java -cp .;..;jna.jar;platform.jar WindowsFileTime [文件名1] [文件名2]...");
			return;
		}

		boolean rc;
		java.sql.Timestamp ct = new java.sql.Timestamp(0);
		java.sql.Timestamp wt = new java.sql.Timestamp(0);
		java.sql.Timestamp at = new java.sql.Timestamp(0);

		for (String sFileName : args)
		{
			System.out.println ("文件 " + sFileName);

			rc = GetFileTime (sFileName, ct, wt, at);
			if (rc)
			{
				System.out.println ("	创建时间:" + ct);
				System.out.println ("	修改时间:" + wt);
				System.out.println ("	访问时间:" + at);
			}
			else
			{
				//System.out.println ("GetFileTime 失败");
			}


			//wt.setTime (System.currentTimeMillis());
			wt = java.sql.Timestamp.valueOf("2010-07-23 00:00:00");
			rc = SetFileTime (sFileName, null, wt, null);
			if (rc)
			{
				System.out.println ("SetFileTime (最后修改时间) 成功");
			}
			else
			{
				//System.out.println ("SetFileTime 失败");
			}
		}
	}
}


测试输出

D:\Software\Development\java.net\jna - Java Native Access>java -cp .;..;jna.jar;platform.jar WindowsFileTime c:\pagefile.sys c:\AUTOEXEC.BAT
文件 c:\pagefile.sys
        打开文件失败,错误码:32 另一个程序正在使用此文件,进程无法访问。

文件 c:\AUTOEXEC.BAT
        创建时间:2007-03-01 10:58:19.749
        修改时间:2007-03-01 10:58:19.749
        访问时间:2010-07-23 10:04:05.546

D:\Software\Development\java.net\jna - Java Native Access>java -cp .;..;jna.jar;platform.jar WindowsFileTime Advapi32Dll.java
文件 Advapi32Dll.java
        创建时间:2010-07-23 11:11:34.484
        修改时间:2010-07-23 00:00:00.0
        访问时间:2010-07-23 17:33:22.031
SetFileTime (最后修改时间) 成功


相关资源

个人工具
名字空间
变换
操作
导航
工具箱
Locations of visitors to this page