JAVA如何调用C函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA如何调用C函数相关的知识,希望对你有一定的参考价值。

参考技术A 要在java中调用c语言的库,需要使用Java提供了JNI。\\x0d\\x0a举例说明\\x0d\\x0a在c语言中定义一个voidsayHello()函数(打印HelloWorld);然后在Java中调用这个函数显示HelloWord.\\x0d\\x0a现在分别从Java和C语言两部分说明:\\x0d\\x0a1.Java部分\\x0d\\x0a首先定义一个HelloNative,在其中申明sayHello函数,函数要申明为Native类型的.如下:\\x0d\\x0apublicclassHelloNative\\x0d\\x0apublicnativevoidsayHello();\\x0d\\x0a\\x0d\\x0a\\x0d\\x0a编译这个类,生成class文件:\\x0d\\x0ajavacHelloWorld.java\\x0d\\x0a\\x0d\\x0a利用javah生成需要的h文件\\x0d\\x0ajavahHelloNative\\x0d\\x0a\\x0d\\x0a生成的h文件大概如下:\\x0d\\x0a\\x0d\\x0a/*DONOTEDITTHISFILE-itismachinegenerated*/\\x0d\\x0a#include\\x0d\\x0a/*HeaderforclassHelloNative*/\\x0d\\x0a\\x0d\\x0a#ifndef_Included_HelloNative\\x0d\\x0a#define_Included_HelloNative\\x0d\\x0a#ifdef__cplusplus\\x0d\\x0aextern"C"\\x0d\\x0a#endif\\x0d\\x0a/*\\x0d\\x0a*Class:HelloNative\\x0d\\x0a*Method:sayHello\\x0d\\x0a*Signature:()V\\x0d\\x0a*/\\x0d\\x0aJNIEXPORTvoidJNICALLJava_HelloNative_sayHello\\x0d\\x0a(JNIEnv*,jobject);\\x0d\\x0a\\x0d\\x0a#ifdef__cplusplus\\x0d\\x0a\\x0d\\x0a#endif\\x0d\\x0a#endif\\x0d\\x0a\\x0d\\x0a可以看一下上面自动生成的程序,程序include了jni.h,这个头文件在$JAVA_HOME下的include文件夹下.还可以发现生成的函数名是在之前的函数名前面加上了Java_HelloNative。\\x0d\\x0a2.C语言部分\\x0d\\x0a根据上面生成的h文件编写相应的代码实现,建立一个HelloNative.cpp用来实现显示HelloWorld的函数.如下:\\x0d\\x0a\\x0d\\x0a#include\\x0d\\x0a#include"HelloNative.h"\\x0d\\x0a\\x0d\\x0aJNIEXPORTvoidJNICALLJava_HelloNative_sayHello(JNIEnv*,jobject)\\x0d\\x0a\\x0d\\x0aprintf("HelloWorld!\\n");\\x0d\\x0a\\x0d\\x0a\\x0d\\x0a代码编写完成之后,我们再用gcc编译成库文件,命令如下;\\x0d\\x0agcc-fPIC-I/usr/lib/jvm/java-7-openjdk-i386/include-I/usr/lib/jvm/java-7-openjdk-i386/include/linux-shared-olibHelloNative.soHelloNative.cpp\\x0d\\x0a\\x0d\\x0a这样就会在当前目录下生成一个libHelloNative.so的库文件.这时需要的库已经生成,在C语言下的工作已经完成了.\\x0d\\x0a接下来需要在Java中编写一个程序测试一下.在程序前,需要将我们的库载入进去.载入的方法是调用Java的System.loadLibrary("HelloNative");\\x0d\\x0a\\x0d\\x0apublicclassTestNative\\x0d\\x0a\\x0d\\x0astatic\\x0d\\x0atry\\x0d\\x0aSystem.loadLibrary("HelloNative");\\x0d\\x0a\\x0d\\x0acatch(UnsatisfiedLinkErrore)\\x0d\\x0aSystem.out.println("Cannotloadhellolibrary:\\n"+e.toString());\\x0d\\x0a\\x0d\\x0a\\x0d\\x0apublicstaticvoidmain(String[]args)\\x0d\\x0aHelloNativetest=newHelloNative();\\x0d\\x0atest.sayHello();\\x0d\\x0a\\x0d\\x0a\\x0d\\x0a\\x0d\\x0a但是再编译后,运行的时候,问题又出现了.\\x0d\\x0aCannotloadhellolibrary:\\x0d\\x0ajava.lang.UnsatisfiedLinkError:noHelloNativeinjava.library.path\\x0d\\x0aExceptioninthread"main"java.lang.UnsatisfiedLinkError:HelloNative.sayHello()V\\x0d\\x0aatHelloNative.sayHello(NativeMethod)\\x0d\\x0aatTestNative.main(TestNative.java:13)\\x0d\\x0a\\x0d\\x0a载入库失败,但是库明明就是放在当前文件夹下的,怎么会载入失败呢?\\x0d\\x0a用System.getProperty("java.library.path")查看,发现java.library.path中并不u存在当前的目录.主要有以下的几个解决办法:\\x0d\\x0a1)将生成的库复制到java.library.path有的路径中去,当然这样不是很好\\x0d\\x0a2)设置环境变量exportLD_LIBRARY_PATH=.:$LD_LIBRARY_PATH,将当前的目录加入到LD_LIBRARY_PATH中\\x0d\\x0a3)设置java的选项,将当前的目录加入到其中.java-Djava.library.path=.$LD_LIBRARY_PATH\\x0d\\x0a这样之后程序就能够成功的运行了.可以看见显示的"HelloWorld!"了

如何调用从 Java 代码返回 TABLE 类型的 postgresql 函数?

【中文标题】如何调用从 Java 代码返回 TABLE 类型的 postgresql 函数?【英文标题】:How to call postgresql function that returns TABLE type from Java code? 【发布时间】:2021-03-14 04:04:13 【问题描述】:

我有一个带有这个签名的 postgresql 函数...

create function getProductsPerCodes(p_c_prodcodes VARCHAR(1000))
RETURNS 
    table (prodcode VARCHAR(1000), prodname VARCHAR(1000), prodline VARCHAR(1000), prodvendor VARCHAR(1000), quantity_in_stock int)
AS

函数返回TABLE类型。

从 SQL 客户端,我可以这样调用这个函数:

select getProductsPerCodes('''c1'',''c4'',') rec

它可以很好地打印记录。

现在,如何从 Java 代码调用此函数并访问该函数返回的数据? 我需要访问表记录并访问构成表记录的所有字段。

【问题讨论】:

【参考方案1】:

你应该使用“表上下文语法”

SELECT * FROM getProductsPerCodes($$'c1','c4',$$)

当您的字符串包含引号 ' 时,您可以使用 Postgres 的自定义字符串分隔符,例如 $$。这样就不需要双引号,代码可读性更强。

【讨论】:

谢谢。我不熟悉“表上下文语法”。会查的。行情不是这里的问题。我不知道如何处理函数返回 TABLE 类型的事实。 @SamSarkar - 您可以像调用任何其他查询一样调用此查询【参考方案2】:

处理集合返回函数的结果与处理常规select * from some_table 命令的结果没有什么不同。

但您不应将参数作为 SQL 字符串的一部分传递。请改用PreparedStatement

PreparedStatement pstmt = connection.prepareStatement("select * from getproductspercode(?,?)");
pstmt.setString(1, "c1");
pstmt.setString(2, "c4");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) 
  String code = rs.getString("prodcode");
  String name = rs.getString("prodname");
  ... 
  int stock = rs.getInt("quantity_in_stock");

【讨论】:

【参考方案3】:

我整理了一个小的demo 来强化@a_horse_with_no_name 的声明,即“设置返回函数与处理常规选择的结果没有什么不同”。这个演示定义并填充了一个模仿你的小表格排序。它包含 2 个 TABLE 返回函数。然后它运行一个标准查询和每个函数,都具有相同的参数。您可以看到它们产生相同的结果。 (我使用逗号分隔的列表 :( 而不是您所拥有的 2 个参数。不必处理嵌套引号。(而且我最初误读了您的参数列表并且不想重做它们。)。

然后我用不同的参数值 (c3,c1) 运行其中一个。它产生了以下内容:

+----------------+-------------+--------------+
|    pc_name     | pc_code_set | pc_code_grp  |
+----------------+-------------+--------------+
| Test col n= 01 | c1          | Group Low    |
| Test col n= 03 | c3          | Group Low    |
| Test col n= 06 | c1          | Group Medium |
| Test col n= 08 | c3          | Group High   |
| Test col n= 11 | c1          | Group High   |
| Test col n= 13 | c3          | Group High   |
+----------------+-------------+--------------+

但运行的是哪一个,你无法判断。所以这里给你一个测试。在您的环境中构建它们并试一试。您将需要更改调用的内容,但不处理结果。

【讨论】:

以上是关于JAVA如何调用C函数的主要内容,如果未能解决你的问题,请参考以下文章

JAVA中如何调用API函数?

从 Java 调用 c 函数

当多个线程调用相同的函数时,Java/C#如何分配内存

使用 Eclipse 从 Android 中的 C 代码调用 Java 函数而不调用 Java

java里面,c里面都有回调函数,回调函数都是啥东西啊???

在 Java Spring Maven Web 应用程序中调用 C/C++ 函数