`
hcx_2008
  • 浏览: 122200 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Jni开发时,dll文件放置的路径处理方式

    博客分类:
  • J2SE
阅读更多
刚到新公司,就接到一个棘手的任务。想了很多办法,最后想使用Java COM桥来解决。JACOB是一个较成熟的开源项目,可以很方便的调用COM组件。搞过JNI的都知道,本地库要放到系统path中,这样,Java进程在运行中才能找到本地库并动态加载。我们可以通过环境变量System.getProperty("java.library.path")来查看当前JVM搜索本地库的路径。

这时,就会遇到一个问题,部署应用的时候要记住将本地库拷贝到环境变量path指定的路径中。一般在windows平台上直接copy到C:\WINDOWS\System32目录下了事。但要换一台机器部署怎么办?除了要把Java程序拿过去,还要记的把本地库也copy到正确的目录,真麻烦。于是想看看有什么好办法来解决这个问题。

首先,最容易想到的是,把本地库和class文件放在一起,利用Class.getResource(str)找到路径,然后加到环境java.library.path中:

代码
URL url = Foo.class.getResource("Foo.class");  
String path = (new File(url.getPath())).getParent();  
System.setProperty("java.library.path", path); 

看上去很好,但却不能工作。查了一下ClassLoader的源代码,原来它把搜索路径定义为静态变量并只初始化一次,后面再设置java.library.path就没有用了。ClassLoader代码片断:
代码
// The paths searched for libraries  
static private String usr_paths[];  
static private String sys_paths[];  
...  
if (sys_paths == null) {  
    usr_paths = initializePath("java.library.path");  
    sys_paths = initializePath("sun.boot.library.path");  


正在一筹莫展是,翻看JACOB的源代码,忽然有了惊喜的发现。
代码
try 
{  
    //Finds a stream to the dll. Change path/class if necessary  
    InputStream inputStream = getClass().getResource("/jacob.dll").openStream();  
    //Change name if necessary  
    File temporaryDll = File.createTempFile("jacob", ".dll");  
    FileOutputStream outputStream = new FileOutputStream(temporaryDll);  
    byte[] array = new byte[8192];  
    for (int i = inputStream.read(array); i != -1; i = inputStream.read(array)) {  
                outputStream.write(array, 0, i);  
        }  
    outputStream.close();  
    temporaryDll.deleteOnExit();  
    System.load(temporaryDll.getPath());  
    return true;  
}  
catch(Throwable e)  
{  
    e.printStackTrace();  
    return false;  


高,真是好办法。和我一样,把dll放在classpath中,用Class.getResource(str).openStream()读取这个dll,然后写到temp目录中,最后用System.load(path)来动态加载。多说一句,为什么得到了jacob.dll的URL不直接去加载呢?想想看,如果把dll和class一起打成Jar包,ClassLoader还是不能加载本地库,因为System.load(path)需要的是dll的完整路径,但并不支持jar协议。还不明白,看看下面的代码:
代码
URL url = Foo.class.getResource("/java/lang/String.class");  
System.out.println(url.toExternalForm());  
System.out.println(url.getFile()); 

在我的机器上的运行结果是:
代码
jar:file:/D:/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/String.class 
file:/D:/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/String.class 

ClassLoader中用new File(name),当然会找不到文件。同时,看看我的第一种方法,就算能设置成功环境java.library.path,如果dll是在jar包中,还是加载不了。


到现在,你是不是觉得问题已经解决了?还没呢!jacob的很多源文件中已经写了下面的代码:

代码
static {  
    System.loadLibrary("jacob");  


除非我去掉这一句重新编译jacob的源代码,否则系统还是会报错。不过,既然有了上面的想法,稍微变通一下,就可以巧妙的解决。首先找到环境java.library.path,然后把dll拷贝到其中一个路径中就行了。
代码
static {  
    try {  
        String libpath = System.getProperty("java.library.path");  
        if ( libpath==null || libpath.length() == 0 ) {  
            throw new RuntimeException("java.library.path is null");  
        }  
              
        String path = null;  
        StringTokenizer st = new StringTokenizer(libpath, System.getProperty("path.separator"));  
        if ( st.hasMoreElements() ) {  
            path = st.nextToken();  
        } else {  
            throw new RuntimeException("can not split library path:" + libpath);  
        }  
              
        InputStream inputStream = Foo.class.getResource("jacob.dll").openStream();  
        final File dllFile = new File(new File(path), "jacob.dll");  
        if (!dllFile.exists()) {  
            FileOutputStream outputStream = new FileOutputStream(dllFile);  
            byte[] array = new byte[8192];  
            for (int i = inputStream.read(array); i != -1; i = inputStream.read(array)) {  
                outputStream.write(array, 0, i);  
            }  
            outputStream.close();  
        }  
        //dllFile.deleteOnExit();     
        Runtime.getRuntime().addShutdownHook(new Thread(){  
            public void run() {  
                if ( dllFile.exists() ) {  
                    boolean delete = dllFile.delete();  
                    System.out.println("delete : " + delete);  
                }  
            }  
        });  
        } catch (Throwable e) {  
            throw new RuntimeException("load jacob.dll error!", e);  
    }  


唯一的美中不足,在系统关闭的时候删除dll总是不能成功,试了两种办法都不行。想想也对,dll正被程序使用,当然不能删除。翻了一下API,Java好像没用提供unload本地库的功能,只好做罢。
解决了这么个小问题,罗罗嗦嗦一大篇,罪过罪过。后来这个项目又没有使用jacob,真对不起各位观众。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1772149
分享到:
评论

相关推荐

    Java JNI调用DLL方法

    这可以通过设置`java.library.path`系统属性来实现,或者将库文件放置在系统默认的库路径下。 为了在VC中调试JNI工程,你需要配置项目的调试设置。在程序参数(Program arguments)中,指定Java类路径,例如: ``` ...

    使用JNI,vs2010 生成dll, JSP中调用dll

    最后,要在JSP中调用这个DLL,我们需要将DLL放置在Java的系统路径(`java.library.path`)中,或者直接在JVM启动时指定其位置。在JSP中,我们可以使用`System.loadLibrary`加载DLL: ```jsp System.loadLibrary(...

    sigar的jar包及dll文件

    当Java应用调用Sigar的API时,这些DLL会被加载并执行相应的系统查询。 4. **Linux环境下的库**: 对于Linux,尽管没有明确的"DLL"文件,但会有类似功能的共享库,如`.so`文件。在Linux上,你可能需要`libsigar.so`...

    jacob-1.18的jar包以及.dll文件

    6. **使用Jacob**:在Java项目中使用Jacob时,需要将Jacob的.jar文件添加到项目的类路径中,并根据系统的架构选择合适的.dll文件放置在正确的位置,通常是系统的PATH环境变量所包含的目录下。然后,通过导入Jacob...

    JNI开发入门1

    4. **嵌入式开发支持**:在嵌入式系统中,往往需要与硬件紧密集成,JNI提供了一种可行的方式。 #### 二、JNI开发流程详解 ##### 1. 新建Java文件 首先,创建一个简单的Java类`HelloJni`,用于演示JNI的基本用法。...

    jiffie的DLL文件

    在处理DLL文件时,需要特别注意版本兼容性,因为不同版本的DLL可能提供不同的函数实现或接口。此外,如果DLL文件出现问题,可能会导致程序崩溃、错误或功能缺失。因此,对DLL文件的管理和维护是系统管理员和开发者的...

    gdal.jar, gdalconstjni.dll, gdaljni.dll, ogrjni.dll

    在配置GDAL环境时,需要将这些文件放置在Java的类路径(classpath)和系统路径(PATH)中,确保Java虚拟机(JVM)能够找到并加载它们。此外,根据应用需求,可能还需要其他依赖库,例如支持特定数据格式的DLL文件。 ...

    jacob相关jar包及dll文件

    在部署应用时,确保这个dll文件在系统路径下可找到,或者将其放置在与Java应用相同的目录下。 使用Jacob操作Word文档的基本步骤如下: 1. **初始化COM**:在Java代码中,首先需要通过` JacobObject.init(new ...

    java的jni方式调用C++封装的库文件

    最后,将生成的DLL库放置在Java应用程序的类路径下,或者指定的系统路径,Java程序可以通过`ProtocolInterface`类调用C++库的方法。 总结:使用JNI调用C++库的过程涉及Java和C++的协同工作,包括Java环境配置、JNI...

    TSCLIB.DLL windows 32/64位下载

    首先,将DLL文件放置在系统路径下的一个可访问目录,或者将其复制到Java应用的运行目录。然后,在Java代码中通过System.loadLibrary()方法加载该库,例如: ```java System.loadLibrary("TSCLIB"); ``` 在调用...

    jacob导出dll文件

    2. **Jacob的安装与配置**:使用Jacob时,需要将对应的DLL文件放置在系统路径(PATH)中,或者将DLL文件复制到Java的bin目录下。此外,还需要在Java代码中通过System.loadLibrary()方法加载DLL。 3. **使用示例**:...

    Java调用Delphi开发的Dll小结.pdf

    - 编译Delphi DLL并将其放置在Java项目的类路径下,然后运行Java代码,Java将通过JNI调用Delphi函数。 2. 使用JNA调用Delphi开发的DLL: JNA提供了一种更简单的方式来调用非Java代码,无需像JNI那样创建C接口。...

    Java调用Delphi开发的Dll小结[定义].pdf

    - 编译DLL,生成`testDll.dll`,并将该文件放置到Java项目的类路径中。 - 在Java代码中,使用`System.loadLibrary()`加载DLL,并声明对应的本地方法,如`native void printText()`。 - 编译并运行Java代码,如果...

    JNA调用DLL完整实例demo

    **正文** 在Java编程中,有时我们需要调用操作系统底层的动态链接库(DLL)功能,以便利用C++或C编写的高效代码。...在处理“JNA调用DLL完整实例demo”时,理解上述概念并参考给定的资源将有助于完成实际的开发任务。

    JNI完全手册.doc

    完成C/C++代码实现后,需要编译生成库文件(.dll或.so),并将库文件放置在Java可访问的路径下,这样Java就能调用C/C++实现的功能。 总结起来,JNI的工作流程包括: 1. 在Java中声明本地库和本地方法。 2. 使用`...

    JAVA如何调用dll:用JNI调用C或C++动态联接库

    - 对于Windows系统,将`JNativeCpp.dll`复制到`%SYSTEMROOT%\system32`目录,对于Linux系统,将`libJNativeCpp.so`放置在系统库路径中。 - 将`JNative.jar`添加到Java项目的类路径中,可以将它导入到工程的LIB中,...

    JAVA调用DLL方法 JAVA调用DLL方

    在Java中调用DLL文件主要通过Java Native Interface (JNI)、JAWINJNative和JNA等技术来实现。这些技术允许Java程序与本地代码进行交互,从而实现对DLL文件的调用。 #### JNI (Java Native Interface) JNI是Java...

    Java JNI调用动态库(Linux、Windows)的实现步骤

    具体来说,对于 Windows 平台,通常需要将 `.dll` 文件放在项目的类路径下或系统的搜索路径中;对于 Linux 平台,则需要将 `.so` 文件放在 `/usr/lib` 或其他合适的位置,并确保它们对所有用户都可读。 #### 五、...

    opencv-java401相关的jar和dll文件,sikuli要用到

    2. **环境配置**:将OpenCV的dll文件放置在系统路径下,确保Java运行时能够找到它们。同时,将Sikuli的jar文件添加到项目的类路径中。 3. **编程接口**:在Java代码中,通过import语句引入OpenCV和Sikuli的类,然后...

Global site tag (gtag.js) - Google Analytics