SWT3.3 M4(2006年12月15日)新增加的功能之一是自動(dòng)加載原生庫(kù),特別是從SWT的Jar文件中加載原生庫(kù)的功能,大大方便了我們發(fā)布基于SWT的Java程序。SWT是怎么實(shí)現(xiàn)這個(gè)功能的呢? 理解其中的原理后,您也可以在您自己的程序中實(shí)現(xiàn)類似的功能。
SWT負(fù)責(zé)加載原生庫(kù)的方法是Library類的loadLibrary (String name)
static
{
Library.loadLibrary(
"
swt
"
);
}
Library.loadLibrary()做的第一件事在庫(kù)名上加上版本號(hào),比如swt-win32-3325。
如果您的原生庫(kù)文件名不包含版本號(hào),您可以省略這一步。
String version = System.getProperty ("swt.version");
if (version == null) {
version = "" + MAJOR_VERSION;
/* Force 3 digits in minor version number */
if (MINOR_VERSION < 10) {
version += "00"; //$NON-NLS-1$
} else {
if (MINOR_VERSION < 100) version += "0";
}
version += MINOR_VERSION;
/* No "r" until first revision */
if (REVISION > 0) version += "r" + REVISION;
}
libName1 = name + "-" + Platform.PLATFORM + "-" + version;
libName2 = name + "-" + Platform.PLATFORM
第二件事是加上操作系統(tǒng)相關(guān)的庫(kù)擴(kuò)展名,比如Windows的.dll, Unix/Linux的.so.
調(diào)用System.mapLibraryName (libName1).
mappedName1
=
System.mapLibraryName (libName1);
mappedName2
=
System.mapLibraryName (libName2);
然后按順序從swt.library.path和java.library.path指定的目錄下尋找。如若沒(méi)有成功,
并且沒(méi)有設(shè)置swt.library.path,那么再找一下java.io.tmpdir指定的目錄。要是還沒(méi)有成功,Library將嘗試
將SWT的Jar文件中的原生庫(kù)解壓到swt.library.path目錄下或者java.io.tmpdir目錄下。
/*
Try loading library from java library path
*/
f
(load (libName1))
return
;
if
(mapName
&&
load (libName2))
return
;
/*
Try loading library from the tmp directory if swt library path is not specified
*/
if
(path
==
null
) {
path
=
System.getProperty (
"
java.io.tmpdir
"
);
path
=
new
File (path).getAbsolutePath ();
if
(load (path
+
SEPARATOR
+
mappedName1))
return
;
if
(mapName
&&
load (path
+
SEPARATOR
+
mappedName2))
return
;
}
/*
Try extracting and loading library from jar
*/
if
(path
!=
null
) {
if
(extract (path
+
SEPARATOR
+
mappedName1, mappedName1))
return
;
if
(mapName
&&
extract (path
+
SEPARATOR
+
mappedName2, mappedName2))
return
;
}
/*
Failed to find the library
*/
throw new UnsatisfiedLinkError (
"
no
"
+
libName1
+
"
or
"
+
libName2
+
"
in swt.library.path, java.libary.path or the jar file
"
);
extract (path+SEPARATOR+mappedName1, mappedName1)將mappedName1從Jar中解壓到
path+SEPARATOR+mappedName1。最后如果還是沒(méi)有成功,甩出一個(gè)UnsatisfiedLinkError。
整個(gè)過(guò)程有意思的只是extract()方法,下面來(lái)看看extract
static
boolean
extract (String fileName, String mappedName)
{
FileOutputStream os
=
null
;
InputStream is
=
null
;
File file
=
new
File(fileName);
try
{
if
(
!
file.exists ())
{
is
=
Library.
class
.getResourceAsStream (
"
/
"
+
mappedName);
if
(is
!=
null
)
{
int
read;
byte
[] buffer
=
new
byte
[
4096
];
os
=
new
FileOutputStream (fileName);
while
((read
=
is.read (buffer))
!=
-
1
)
{
os.write(buffer,
0
, read);
}
os.close ();
is.close ();
if
(
!
Platform.PLATFORM.equals (
"
win32
"
))
{
try
{
Runtime.getRuntime ().exec (
new
String []
{
"
chmod
"
,
"
755
"
, fileName}
).waitFor();
}
catch
(Throwable e)
{}
}
if
(load (fileName))
return
true
;
}
}
}
catch
(Throwable e)
{
try
{
if
(os
!=
null
) os.close ();
}
catch
(IOException e1)
{}
try
{
if
(is
!=
null
) is.close ();
}
catch
(IOException e1)
{}
}
if
(file.exists ()) file.delete ();
return
false
;
}
Library.class.getResourceAsStream ("/" + mappedName)返回指向Jar根目錄下mappedName文件的
InputStream.個(gè)人感覺(jué),extract寫得有點(diǎn)亂,if套著if,if套著try,當(dāng)然并不是很糟糕,本身這是一個(gè)比較簡(jiǎn)單的函數(shù)。
在我自己的程序中,重寫了extract(改名為extractAndLoad),相對(duì)來(lái)說(shuō)要清爽一些,請(qǐng)大家比較。
通過(guò)上面的分析,我們可以很簡(jiǎn)單實(shí)現(xiàn)我們自己的loadLibrary
import
org.eclipse.swt.SWT;
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.InputStream;
/**
* The method loadLibrary load a native library in the order
* from java.library.path, os.library.path, tmpdir and from jar.
*
*
@author
pan
*/
public
class
Library {
static
final
String SEPARATOR
=
System.getProperty(
"
file.separator
"
);
public
static
void
loadLibrary(String name) {
//
Try loading library from os library path
String path
=
System.getProperty(
"
os.library.path
"
);
if
(path
!=
null
) {
path
=
new
File(path).getAbsolutePath();
if
(_load(System.mapLibraryName(path
+
SEPARATOR
+
name)))
return
;
}
//
Try loading library from java library path
if
(_load(name))
return
;
//
Try loading library from the tmp directory if os library path is not specified
if
(path
==
null
) {
path
=
System.getProperty(
"
java.io.tmpdir
"
);
path
=
new
File(path).getAbsolutePath();
if
(_load(System.mapLibraryName(path
+
SEPARATOR
+
name)))
return
;
}
//
Try extracting and loading library from jar
if
(path
!=
null
&&
loadFromJar(System.mapLibraryName(path
+
SEPARATOR
+
name),
System.mapLibraryName(name)))
return
;
//
Failed to find the library
throw
new
UnsatisfiedLinkError(
"
no
"
+
name
+
"
in java.libary.path, os.library.path or jar file
"
);
}
private
static
boolean
_load(String libName) {
try
{
if
(libName.indexOf(SEPARATOR)
!=
-
1
) {
System.load(libName);
}
else
{
System.loadLibrary(libName);
}
return
true
;
}
catch
(UnsatisfiedLinkError e) {
}
return
false
;
}
private
static
boolean
loadFromJar(String outFileName, String libName) {
try
{
return
extractAndLoad(outFileName, libName);
}
catch
(Throwable e) {
}
return
false
;
}
private
static
boolean
extractAndLoad(String outFileName, String libName)
throws
Throwable {
int
read;
byte
[] buf
=
new
byte
[
4096
];
InputStream is
=
null
;
FileOutputStream os
=
null
;
File file
=
new
File(outFileName);
if
(file.exists())
file.delete();
if
(
!
file.exists()) {
try
{
os
=
new
FileOutputStream(file);
is
=
Library.
class
.getResourceAsStream(
"
/
"
+
libName);
if
(is
==
null
||
os
==
null
)
return
false
;
while
((read
=
is.read(buf))
!=
-
1
)
os.write(buf,
0
, read);
}
finally
{
if
(os
!=
null
)
os.close();
if
(is
!=
null
)
is.close();
}
if
(
!
SWT.getPlatform().equals(
"
win32
"
)) {
Runtime.getRuntime().exec(
new
String[] {
"
chmod
"
,
"
755
"
, outFileName }).waitFor();
}
return
_load(outFileName);
}
return
false
;
}
}
然后把您的原生庫(kù)打在Jar里面,用Library.loadLibrary加載原生庫(kù),而不是System.loadLibrary,這樣您就
把原生庫(kù)隱藏在您的Jar里面了。
轉(zhuǎn)載請(qǐng)保留
http://m.tkk7.com/xilaile/archive/2007/03/23/105706.html