import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.Enumeration;
import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* A helper to copy resources from a JAR file into a directory. source :
* https://stackoverflow.com/a/58318009
*/
public final class ResourceCopy {
/**
* URI prefix for JAR files.
*/
private static final String JAR_URI_PREFIX = "jar:file:";
/**
* The default buffer size.
*/
private static final int BUFFER_SIZE = 8 * 1024;
/**
* Copies a set of resources into a temporal directory, optionally
* preserving the paths of the resources.
*
* @param preserve
* Whether the files should be placed directly in the directory
* or the source path should be kept
* @param paths
* The paths to the resources
* @return The temporal directory
* @throws IOException
* If there is an I/O error
*/
public File copyResourcesToTempDir(final boolean preserve, final String... paths) throws IOException {
final File parent = new File(System.getProperty("java.io.tmpdir"));
File directory;
do {
directory = new File(parent, String.valueOf(System.nanoTime()));
} while (!directory.mkdir());
return this.copyResourcesToDir(directory, preserve, paths);
}
/**
* Copies a set of resources into a directory, preserving the paths and
* names of the resources.
*
* @param directory
* The target directory
* @param preserve
* Whether the files should be placed directly in the directory
* or the source path should be kept
* @param paths
* The paths to the resources
* @return The temporal directory
* @throws IOException
* If there is an I/O error
*/
public File copyResourcesToDir(final File directory, final boolean preserve, final String... paths)
throws IOException {
for (final String path : paths) {
final File target;
if (preserve) {
target = new File(directory, path);
target.getParentFile().mkdirs();
} else {
target = new File(directory, new File(path).getName());
}
this.writeToFile(Thread.currentThread().getContextClassLoader().getResourceAsStream(path), target);
}
return directory;
}
/**
* Copies a resource directory from inside a JAR file to a target directory.
*
* @param source
* The JAR file
* @param path
* The path to the directory inside the JAR file
* @param target
* The target directory
* @throws IOException
* If there is an I/O error
*/
public void copyResourceDirectory(final JarFile source, final String path, final File target) throws IOException {
final Enumeration<JarEntry> entries = source.entries();
final String newpath = String.format("%s/", path);
while (entries.hasMoreElements()) {
final JarEntry entry = entries.nextElement();
if (entry.getName().startsWith(newpath) && !entry.isDirectory()) {
final File dest = new File(target, entry.getName().substring(newpath.length()));
final File parent = dest.getParentFile();
if (parent != null) {
parent.mkdirs();
}
this.writeToFile(source.getInputStream(entry), dest);
}
}
}
/**
* The JAR file containing the given class.
*
* @param clazz
* The class
* @return The JAR file or null
* @throws IOException
* If there is an I/O error
*/
public Optional<JarFile> jar(final Class<?> clazz) throws IOException {
final String path = String.format("/%s.class", clazz.getName().replace('.', '/'));
final URL url = clazz.getResource(path);
Optional<JarFile> optional = Optional.empty();
if (url != null) {
final String jar = url.toString();
final int bang = jar.indexOf('!');
if (jar.startsWith(ResourceCopy.JAR_URI_PREFIX) && bang != -1) {
optional = Optional.of(new JarFile(jar.substring(ResourceCopy.JAR_URI_PREFIX.length(), bang)));
}
}
return optional;
}
/**
* Writes an input stream to a file.
*
* @param input
* The input stream
* @param target
* The target file
* @throws IOException
* If there is an I/O error
*/
private void writeToFile(final InputStream input, final File target) throws IOException {
final OutputStream output = Files.newOutputStream(target.toPath());
final byte[] buffer = new byte[ResourceCopy.BUFFER_SIZE];
int length = input.read(buffer);
while (length > 0) {
output.write(buffer, 0, length);
length = input.read(buffer);
}
input.close();
output.close();
}
}
# 2 楼答案
假设我有库foo和库barbar依赖于foo;它还依赖于baz,我们是而不是与JNA的映射:
public class Foo {
public static final boolean LOADED;
static {
Native.register("foo");
LOADED = true;
}
public static native void call_foo();
}
public class Bar {
static {
// Reference "Foo" so that it is loaded first
if (Foo.LOADED) {
System.loadLibrary("baz");
// Or System.load("/path/to/libbaz.so")
Native.register("bar");
}
}
public static native void call_bar();
}
public interface Foo extends Library {
Foo INSTANCE = (Foo)Native.loadLibrary("foo");
}
public interface Bar extends Library {
// Reference Foo prior to instantiating Bar, just be sure
// to reference the Foo class prior to creating the Bar instance
Foo FOO = Foo.INSTANCE;
Bar INSTANCE = (Bar)Native.loadLibrary("bar");
}
Context class loader classpath. Deployed native libraries may be
installed on the classpath under ${os-prefix}/LIBRARY_FILENAME, where
${os-prefix} is the OS/Arch prefix returned by
Platform.getNativeLibraryResourcePrefix(). If bundled in a jar file,
the resource will be extracted to jna.tmpdir for loading, and later
removed (but only if jna.nounpack is false or not set).
# 1 楼答案
我也遇到过类似的情况,处理多平台和几个依赖库,但只需要加载一个。这是我的照片
假设您得到一组32/64 win/linux库,其中包含依赖项。 假设您只需要为
libapi
拥有一个JNA绑定你需要像这样将它们组织到你的罐子中:
你可以:
确定是否从JAR文件执行(从您最喜欢的IDE执行时避免执行该操作;请参见How to get the path of a running JAR file?)
使用JNA来确定当前的执行平台
将所有适当的库文件提取到java temp文件夹中(使用此答案中的元素:https://stackoverflow.com/a/58318009/7237062(或相关答案)应该可以做到这一点)
告诉JNA查看新创建的临时文件夹
瞧
代码示例中缺少的是应用程序关闭时的目录清理,但我将其留给您
主要部分应该是这样的:
主课。爪哇
资源拷贝。java(为完整起见,请复制此处;摘自https://stackoverflow.com/a/58318009)
# 2 楼答案
假设我有库
foo
和库bar
bar
依赖于foo
;它还依赖于baz
,我们是而不是与JNA的映射:只有当
baz
既不在库加载路径上(分别是PATH
/LD_LIBRARY_PATH
,对于windows/linux),也不在与bar
相同的目录下(仅限windows)时,才需要调用System.load/loadLibrary
编辑
您还可以通过接口映射来实现这一点:
# 3 楼答案
从JAR资源加载带有JNA的库临时依赖项
我的资源文件夹res:
-
API爆炸: 原因:java。lang.UnsatifiedLinkError:加载共享库libdependency时出错。所以:没有这样的文件或目录
可以通过手动提前加载依赖项来解决:
基本上,你必须自己动手,反向建立依赖关系树
我建议设置
此外,设置jna。图书馆到资源的路径不起作用,因为JNA提取到文件系统,然后加载lib。文件系统上的Lib无法访问jar中的其他Lib
Javadoc
RTFM和快乐编码。JNA v.4.1.0