linux下海康SDK开发(JAVA),及库文件的导入打包

放在开头的说明:

  1. 系统环境 Ubuntu 18.04
  2. 编译工具 IDEA
  3. maven仓库管理依赖
  4. 海康摄像头 普通的枪击网络摄像头

这里只写关于开发海康视频SDK中可能会遇到的问题,要想知道怎么调用这套SDK可以直接看开发文档。

(一)、 导入jna和examples两个jar包

两个jar包
在哪找?
开发包里面LinuxJavaDemo(也就是开发实例)目录下
怎么导入,以及项目打包时怎么附加?
命令行
mvn install:install-file -DgroupId=com.sun -DartifactId=jna -Dversion=1.0 -Dpackaging=jar -Dfile= jar包的完整路径加包名,像这样 /jarlibs/jna.jar
同理install examples.jar,
mvn install:install-file -DgroupId=com.sun.jna -DartifactId=examples -Dversion=1.0.0 -Dpackaging=jar -Dfile=
之后再添加下面依赖就行了。

		
            com.sun
            jna
            1.0
        
        
            com.sun.jna
            examples
            1.0
        

如果你是用maven自带的package打包,添加下面这一段可以在打包可执行jar包时把这两个jar包以及其他所有依赖涵盖。当然也可以用其他打包方式

	
        
            
                maven-assembly-plugin
                
                       
                        jar-with-dependencies
                    
                    
                        
                            
                        
                    
                
                
                    
                        make-assembly
                        package
                        
                            single
                        
                    
                
            
        
    

(二)、库文件导入,及相对路径导入

如果你只是在当前电脑用这个项目,那配置 /etc/ld.so.conf 即系统默认so文件加载路径,是一种很便捷的方式。(这个只需要在文件末尾添加库文件及库文件里面的HCNetSDKCom的绝对路径)
但是如果想要将项目打包,则需要按照以下方法(网上别的文章绝对没有的方法):
先将整个库文件放在resources目录下的lib里面,像这样
linux下海康SDK开发(JAVA),及库文件的导入打包_第1张图片说一下为什么放这儿。没有为什么,放其他地方也可以,只不过放在这里待会打包过后这个文件夹就会出现在jar包里面的最外层目录,很容易找到。

添加一个获取加载路径的方法:

import java.io.UnsupportedEncodingException;

/**
 * @Author ws
 * @Date 2019/03/05
 */
public class Hkpath {
    // 库文件目录
    public static String DLL_PATH;
    static {
        String path = (Hkpath.class.getResource("/").getPath()).replaceAll("%20", " ").substring(1);
        String[] p = path.split("/");
        StringBuilder pa = new StringBuilder();
        for (int i=0;i

再修改HCNetSDK.java里面加载库文件这段代码:

//修改之前
HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary( "hcnetsdk", HCNetSDK.class);
//修改之后
String path = System.getProperty("user.name").equals("你自己的用户名") ?
            Hkpath.DLL_PATH + "/libhcnetsdk.so" : System.getProperty("user.dir") + "/libhcnetsdk.so";
    HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(path, HCNetSDK.class);

目的是判断这是不是在你自己电脑上运行的,因为在其他地方运行jar包时路径是不一样的。(额刚刚想到,如果你在自己电脑上运行这个jar包这里应该会报错…
这样就可以加载到了。
什么?失败了?错误码是107加载预览组件失败?那继续下面的步骤
新建一个方法

import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


/**
 * @Author ws
 * @Date 2019/03/11
 */
@Slf4j
public class CopyDirectory {
    String url1 = System.getProperty("user.dir");
    // 拷贝普通文件
    public void copy() throws IOException {
        //String url1 = Hkpath.SO_PATH;
        String url1 = Objects.requireNonNull(this.getClass().getClassLoader().getResource("lib")).getPath();
        String url2 = System.getProperty("user.dir");
        copy(url1, url2);
    }
    // 拷贝jar文件里面的东西
    public void copy2Natives() throws IOException {
        File hcfile = new File(url1 + File.separator + "HCNetSDKCom");
        if (!hcfile.exists()) {
            hcfile.mkdirs();
        }
         URL url = this.getClass().getClassLoader().getResource("lib");
        assert url != null;
        Path nativePath = Paths.get(url1);
        if (!Files.exists(nativePath)) {
            Files.createDirectories(nativePath);
        }
        if (url.toString().contains("!/")) {
            String jarPath = url.toString().substring(0, url.toString().indexOf("!/") + 2);
            URL jarUrl = new URL(jarPath);
            JarURLConnection jarCon = (JarURLConnection) jarUrl.openConnection();
            JarFile jarFile = jarCon.getJarFile();
            Enumeration jarEntrys = jarFile.entries();
            final String filePref = "lib";
            while (jarEntrys.hasMoreElements()) {
                JarEntry entry = jarEntrys.nextElement();
                String name = entry.getName();
                if (name.startsWith(filePref) && !entry.isDirectory()) {
                    String fileName = name.substring(filePref.length());
                    Path destFile = Paths.get(nativePath.toAbsolutePath().toString() + File.separator + fileName);
                    if (!Files.exists(destFile)) {
                        //不存在就复制
                      Files.copy(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream(name)), destFile);
                    }
                }
            }
        }
    }

    // url1源文件夹
    // url2目标文件夹
    // 文件夹最后不加斜杠
    public void copy(String url1, String url2) throws IOException {
        // 创建目标文件夹
        File file2 = new File(url2);
        if (!file2.exists()) {
            file2.mkdirs();
        }
        // 获取源文件夹当前下的文件或目录
        File[] file = (new File(url1)).listFiles();
        for (int i = 0; i < file.length; i++) {
            if (file[i].isFile()) {
                // 复制文件
                copyFile(file[i], new File(url2 + File.separator + file[i].getName()));
            }
            if (file[i].isDirectory()) {
                // 复制目录
                String targetDir = url2 + File.separator + file[i].getName();
                String sourceDir = url1 + File.separator + file[i].getName();
                copy(sourceDir, targetDir);
            }
        }
    }

    // 复制文件
    public static void copyFile(File sourceFile, File targetFile)
            throws IOException {
        // 新建文件输入流并对它进行缓冲
        FileInputStream input = new FileInputStream(sourceFile);
        BufferedInputStream inBuff = new BufferedInputStream(input);

        // 新建文件输出流并对它进行缓冲
        FileOutputStream output = new FileOutputStream(targetFile);
        BufferedOutputStream outBuff = new BufferedOutputStream(output);

        // 缓冲数组
        byte[] b = new byte[1024 * 5];
        int len;
        while ((len = inBuff.read(b)) != -1) {
            outBuff.write(b, 0, len);
        }
        // 刷新此缓冲的输出流
        outBuff.flush();

        //关闭流
        inBuff.close();
        outBuff.close();
        output.close();
        input.close();
    }
}

再在你海康初始化之前加入这样的代码

// 复制库文件
        try {
            if (System.getProperty("user.name").equals("自己的用户名")){
                (new CopyDirectory()).copy();
            }else{
                (new CopyDirectory()).copy2Natives();
            }
        } catch (IOException e) {
            log.info("Copy .so files failed.", e);
        }

如果运行jar包时提示加载类错误。也就是
java.lang.NoClassDefFoundError: Could not initialize class xxx.HCNetSDK
这个的意思就是打包之前还可以加载到 HCNetSDK.java这个类的,但是打包过后在类路径(class path 里面就加载不到HCNetSDK.class了。具体原因我也不太明白,不过既然找不到路径,那我们帮它找到不就好了。所以再添加下面一段

 System.setProperty("java.class.path",
                System.getProperty("java.class.path") +
                        System.getProperty("path.separator") +
Objects.requireNonNull(this.getClass().getClassLoader().getResource("com")).getPath());

那为什么要复制库文件出去呢?
因为如果不复制一下库文件,报错信息会提示你【.//HKNetSDKCom/libCPreview.so】加载失败了,错误码107,预览组件加载失败。而其中的 ./就是项目根目录的意思,意思就是它还是从根目录获取这个文件夹里面的so文件了。我们之前配置的对这个文件目录下的so文件没起作用,而这个复制文件就是将库文件全部复制到了它能找到的地方。这样也能避免jar包在不同地方引用的时候库文件加载路径不尽相同的问题。

如果是错误码47,用户不存在,则参考我另一篇文章
https://blog.csdn.net/qq_41789316/article/details/88391031

先这样,还有什么坑的话之后再加。毕竟我倒腾两周了已经…

你可能感兴趣的:(linux下海康SDK开发(JAVA),及库文件的导入打包)