java通过c调用python


最近在做一个项目,主要是用到python下的一个库(sympy),之前通过java通过jython调用python,速度达不到要求,后面把python单独拿出来,做成一个本地服务,通过socket与java通信,速度上去了,但是很不方便

现在是通过c调用python,然后利用java调用c(这方面的资料网上很多,下面主要说说细节问题)

1,因为java调用c,要是使用64位,所以对应的python必须下载64位版的,

2,然后在vs生成dll文件的时候,要设置为64位,我是用vs2010写的



3.注意引入python的库文件和头文件




生成dll的工程:




下面是头文件 mydll.h代码

#ifndef _MYDLL_H_
#define _MYDLL_H_

#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include "jni.h"
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *, jobject, jstring, jstring);


JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *, jobject, jstring, jstring, jstring);

#ifdef __cplusplus
}
#endif
#endif //_MYDLL_H_
注:jni.h是Jni自动生成的,奇怪的东西是jni自动生成的,直接复制过来用就是了,这里主要定义了2个接口函数,第一个参数是对应python里面的函数名,第二个参数和第三个函数是该对应函数的参数,(如果该函数只要1个参数,就是调用的第一个,利用函数重载完成),


testdlladd.cpp代码清淡,主要是实现上面的2个接口(我承认我的文件命名很奇怪)

注释中的Add函数就是c调用python中的东西,其中pDict是全局变量,后面会提到

// testdlladd.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "mydll.h"

using namespace std;

string int2str(int &);


/*
char* Add(char* a, char* b)
{
	printf("pDict:%d\n",pDict);
	PyObject *pFunc, *pArgs, *pRetVal;

    pFunc = PyDict_GetItemString(pDict, "add");
    if ( !pFunc||!PyCallable_Check(pFunc) )
    {
        printf("can't find function [add]");
        getchar();
        return 0;
    }
    // 参数进栈
    pArgs = PyTuple_New(2);

    // PyObject* Py_BuildValue(char *format, ...)
    // 把C++的变量转换成一个Python对象。当需要从
    // C++传递变量到Python时,就会使用这个函数。此函数
    // 有点类似C的printf,但格式不同。常用的格式有
    // s 表示字符串,
    // i 表示整型变量,
    // f 表示浮点数,
    // O 表示一个Python对象。
	//string a = int2str(plus1);
	//string b= int2str(plus2);
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",a)); 
	PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",b)); 
    // 调用Python函数
    pRetVal = PyObject_CallObject(pFunc, pArgs);

	char* res=PyString_AsString(pRetVal);

 
    return res;
}
*/
JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv *env, jobject _obj, jstring funcName, jstring param1)
  {
      const char* fName = env->GetStringUTFChars(funcName,0);
      const char* parameter = env->GetStringUTFChars(param1,0);
      PyObject *pFunc, *pArgs, *pRetVal;
      pFunc = PyDict_GetItemString(pDict, fName);
      if ( !pFunc||!PyCallable_Check(pFunc) )
      {
          printf("can't find function %s",fName);
          return 0;
      }
    // 参数进栈
      pArgs = PyTuple_New(1);
    // PyObject* Py_BuildValue(char *format, ...)
    // 把C++的变量转换成一个Python对象。当需要从
    // C++传递变量到Python时,就会使用这个函数。此函数
    // 有点类似C的printf,但格式不同。常用的格式有
    // s 表示字符串,
    // i 表示整型变量,
    // f 表示浮点数,
    // O 表示一个Python对象。
	//string a = int2str(plus1);
	//string b= int2str(plus2);
      PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",parameter));
	//PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",b));
    // 调用Python函数
      pRetVal = PyObject_CallObject(pFunc, pArgs);
	  char* res=PyString_AsString(pRetVal);
      env->ReleaseStringUTFChars(funcName,fName);
      env->ReleaseStringUTFChars(param1,parameter);

      return env->NewStringUTF(res);
  }
  JNIEXPORT jstring JNICALL Java_sympy_SympyJavaJNI_invokingSympy__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
  (JNIEnv * env, jobject _obj, jstring funcName, jstring param1, jstring param2)
  {
      const char* fName = env->GetStringUTFChars(funcName,0);
      const char* p1 = env->GetStringUTFChars(param1,0);
      const char* p2 = env->GetStringUTFChars(param2,0);
      PyObject *pFunc, *pArgs, *pRetVal;
      pFunc = PyDict_GetItemString(pDict, fName);
      if ( !pFunc||!PyCallable_Check(pFunc) )
      {
          printf("can't find function %s",fName);
          return 0;
      }
    // 参数进栈
      pArgs = PyTuple_New(2);
    // PyObject* Py_BuildValue(char *format, ...)
    // 把C++的变量转换成一个Python对象。当需要从
    // C++传递变量到Python时,就会使用这个函数。此函数
    // 有点类似C的printf,但格式不同。常用的格式有
    // s 表示字符串,
    // i 表示整型变量,
    // f 表示浮点数,
    // O 表示一个Python对象。
      PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",p1));
	  PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",p2));
    // 调用Python函数
      pRetVal = PyObject_CallObject(pFunc, pArgs);
	  char* res=PyString_AsString(pRetVal);
      env->ReleaseStringUTFChars(funcName,fName);
      env->ReleaseStringUTFChars(param1,p1);
      env->ReleaseStringUTFChars(param2,p2);

      return env->NewStringUTF(res);
  }
string int2str(int &i) {
	string s;
	stringstream ss(s);
	ss << i;
	return ss.str();
}




stdafx.h文件代码清单

这里定义了3个全局变量,主要是因为我们要频繁调用python里的库(1秒估计要几百次吧,还没考虑高并发),所以第一次加载的时候,先把DLL文件加载的里面,避免每次调用python的时候,都去加载那个dll文件,效率就十分十分十分十分的慢

#ifndef _STDAFX_H_
#define _STDAFX_H_


#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息
// Windows 头文件:

#include <windows.h>
#include<stdio.h>
#include "jni.h"
#include "jni_md.h"
#include <Python.h>
extern PyObject *pDict,*pName,*pModule;


#endif




下面是dllmain.cpp,dll的入口函数,我觉得该写个destroy函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
PyObject *pDict=NULL;
PyObject *pName=NULL;
PyObject *pModule=NULL;




static int init(void)
{
<span style="white-space:pre">	</span>// 初始化Python
    //在使用Python系统前,必须使用Py_Initialize对其
    //进行初始化。它会载入Python的内建模块并添加系统路
    //径到模块搜索路径中。这个函数没有返回值,检查系统
    //是否初始化成功需要使用Py_IsInitialized。<span style="white-space:pre">	</span>
    Py_Initialize();
    // 检查初始化是否成功
    if ( !Py_IsInitialized() ) 
    {
<span style="white-space:pre">		</span>printf("Py_Initialize()  error");
        return 0;
    }


    // 载入名为pytest的脚本(注意:不是pytest.py)
    pName = PyString_FromString("sympyInvoke");
    pModule = PyImport_Import(pName);
    if ( !pModule )
    {
        printf("can't find pytest.py");
        return 0;
    }
    pDict= PyModule_GetDict(pModule);
    if ( !pDict ) 
    {<span style="white-space:pre">	</span>
<span style="white-space:pre">		</span>printf("can't find Method!!");
        return 0;
    } 


<span style="white-space:pre">	</span>


}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
<span style="white-space:pre">					</span> )
{
<span style="white-space:pre">	</span> 
<span style="white-space:pre">	</span>switch (ul_reason_for_call)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">	</span>case DLL_PROCESS_ATTACH:init();printf("DLL in");break; 
<span style="white-space:pre">	</span>case DLL_THREAD_ATTACH:
<span style="white-space:pre">	</span>case DLL_THREAD_DETACH:
<span style="white-space:pre">	</span>case DLL_PROCESS_DETACH:printf("DLL out");break;


<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>return TRUE;
}


至于Jni,怎么调用这个dll,网上一查一大堆,就不在赘述了!

这样生成的dll文件就可以用在我们的java工程中去啦!(注意要安装python64位)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值