放在开头的说明:
这里只写关于开发海康视频SDK中可能会遇到的问题,要想知道怎么调用这套SDK可以直接看开发文档。
在哪找?
开发包里面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里面,像这样
说一下为什么放这儿。没有为什么,放其他地方也可以,只不过放在这里待会打包过后这个文件夹就会出现在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
先这样,还有什么坑的话之后再加。毕竟我倒腾两周了已经…