导航:首页 > 编程语言 > 打印jstring

打印jstring

发布时间:2024-06-16 12:21:23

❶ 用java怎么调用C语言已经编写好的DLL

1.用System.getProperty("user.dir"),获取程序抄的路径,估计你的应该是 E:\\测试程序不清楚打印一下就可以了。System.getProperty("user.dir") + "\\DLL\\CardAPI"2.unsigned char 用char就可以了unsigned int 用int就可以了,java的int值很大.....C的无符号的记得是65535 unsigned char*、和unsigned int* 这两个是指针,第一个是取1位地址内容的,第二个根据系统而定,一般是取4位地址值的,用java 的String对应,应该可以 。

❷ 如何在C/C++中调用Java

如何在C/C++中调用Java

java跨平台的特性使Java越来越受开发人员的欢迎,但也往往会听到不少的抱怨:用Java开发的图形用户窗口界面每次在启动的时候都会跳出一个控制台窗口,这个控制台窗口让本来非常棒的界面失色不少。怎么能够让通过Java开发的GUI程序不弹出Java的控制台窗口呢?其实现在很多流行的开发环境例如JBuilder、Eclipse都是使用纯Java开发的集成环境。这些集成环境启动的时候并不会打开一个命令窗口,因为它使用了JNI(Java Native Interface)的技术。通过这种技术,开发人员不一定要用命令行来启动Java程序,可以通过编写一个本地GUI程序直接启动Java程序,这样就可避免另外打开一个命令窗口,让开发的Java程序更加专业。
JNI答应运行在虚拟机的Java程序能够与其它语言(例如C和C++)编写的程序或者类库进行相互间的调用。同时JNI提供的一整套的API,答应将Java虚拟机直接嵌入到本地的应用程序中。图1是Sun站点上对JNI的基本结构的描述。
如何在C/C++中调用Java 三联
本文将介绍如何在C/C++中调用Java方法,并结合可能涉及到的问题介绍整个开发的步骤及可能碰到的难题和解决方法。本文所采用的工具是Sun公司创建的 Java Development Kit (JDK) 版本 1.3.1,以及微软公司的Visual C++ 6开发环境。
环境搭建
为了让本文以下部分的代码能够正常工作,我们必须建立一个完整的开发环境。首先需要下载并安装JDK 1.3.1,其下载地址为“http://java.sun.com”。假设安装路径为C:JDK。下一步就是设置集成开发环境,通过Visual C++ 6的菜单Tools→Options打开选项对话框如图2。

将目录C:JDKinclude和C:JDKincludewin32加入到开发环境的Include Files目录中,同时将C:JDKlib目录添加到开发环境的Library Files目录中。这三个目录是JNI定义的一些常量、结构及方法的头文件和库文件。集成开发环境已经设置完毕,同时为了执行程序需要把Java虚拟机所用到的动态链接库所在的目录C:JDK jreinclassic设置到系统的Path环境变量中。这里需要提出的是,某些开发人员为了方便直接将JRE所用到的DLL文件直接拷贝到系统目录下。这样做是不行的,将导致初始化Java虚拟机环境失败(返回值-1),原因是Java虚拟机是以相对路径来寻找所用到的库文件和其它一些相关文件的。至此整个JNI的开发环境设置完毕,为了让此次JNI旅程能够顺利进行,还必须先预备一个Java类。在这个类中将用到Java中几乎所有有代表性的属性及方法,如静态方法与属性、数组、异常抛出与捕捉等。我们定义的Java程序(Demo.java)如下,本文中所有的代码演示都将基于该Java程序,代码如下:
package jni.test; /** * 该类是为了演示JNI如何访问各种对象属性等 * @author liudong */ public class Demo { //用于演示如何访问静态的基本类型属性 public static int COUNT = 8; //演示对象型属性 public String msg; PRivate int[] counts; public Demo() { this("缺省构造函数"); } /** * 演示如何访问构造器 */ public Demo(String msg) { System.out.println(":" + msg); this.msg = msg; this.counts = null; } /** * 该方法演示如何访问一个访问以及中文字符的处理 */ public String getMessage() { return msg; } /** * 演示数组对象的访问 */ public int[] getCounts() { return counts; } /** * 演示如何构造一个数组对象 */ public void setCounts(int[] counts) { this.counts = counts; } /** * 演示异常的捕捉 */ public void throwExcp() throws IllegalaccessException { throw new IllegalAccessException("exception occur."); } }
初始化虚拟机
本地代码在调用Java方法之前必须先加载Java虚拟机,而后所有的Java程序都在虚拟机中执行。为了初始化Java虚拟机,JNI提供了一系列的接口函数Invocation API。通过这些API可以很方便地将虚拟机加载到内存中。创建虚拟机可以用函数 jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args)。对于这个函数有一点需要注重的是,在JDK 1.1中第三个参数总是指向一个结构JDK1_ 1InitArgs, 这个结构无法完全在所有版本的虚拟机中进行无缝移植。在JDK 1.2中已经使用了一个标准的初始化结构JavaVMInitArgs来替代JDK1_1InitArgs。下面我们分别给出两种不同版本的示例代码。
在JDK 1.1初始化虚拟机:
#include int main() { JNIEnv *env; JavaVM *jvm; JDK1_1InitArgs vm_args; jint res; /* IMPORTANT: 版本号设置一定不能漏 */ vm_args.version = 0x00010001; /*获取缺省的虚拟机初始化参数*/ JNI_GetDefaultJavaVMInitArgs(&vm_args); /* 添加自定义的类路径 */ sprintf(classpath, "%s%c%s", vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH); vm_args.classpath = classpath; /*设置一些其他的初始化参数*/ /* 创建虚拟机 */ res = JNI_CreateJavaVM(&jvm,&env,&vm_args); if (res < 0) { fprintf(stderr, "Can't create Java VM "); exit(1); } /*释放虚拟机资源*/ (*jvm)->DestroyJavaVM(jvm); }
JDK 1.2初始化虚拟机:
/* invoke2.c */ #include int main() { int res; JavaVM *jvm; JNIEnv *env; JavaVMInitArgs vm_args; JavaVMOption options[3]; vm_args.version=JNI_VERSION_1_2;//这个字段必须设置为该值 /*设置初始化参数*/ options[0].optionString = "-Djava.compiler=NONE"; options[1].optionString = "-Djava.class.path=."; options[2].optionString = "-verbose:jni";//用于跟踪运行时的信息 /*版本号设置不能漏*/ vm_args.version = JNI_VERSION_1_2; vm_args.nOptions = 3; vm_args.options = options; vm_args.ignoreUnrecognized = JNI_TRUE; res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); if (res < 0) { fprintf(stderr, "Can't create Java VM "); exit(1); } (*jvm)->DestroyJavaVM(jvm); fprintf(stdout, "Java VM destory. "); }
为了保证JNI代码的可移植性,建议使用JDK 1.2的方法来创建虚拟机。JNI_CreateJavaVM函数的第二个参数JNIEnv *env,就是贯穿整个JNI始末的一个参数,因为几乎所有的函数都要求一个参数就是JNIEnv *env。
访问类方法
初始化了Java虚拟机后,就可以开始调用Java的方法。要调用一个Java对象的方法必须经过几个步骤:
1.获取指定对象的类定义(jclass)
有两种途径来获取对象的类定义:第一种是在已知类名的情况下使用FindClass来查找对应的类。但是要注重类名并不同于平时写的Java代码,例如要得到类jni.test.Demo的定义必须调用如下代码:
jclass cls = (*env)->FindClass(env, "jni/test/Demo");//把点号换成斜杠
然后通过对象直接得到其所对应的类定义:
jclass cls = (*env)-> GetObjectClass(env, obj); //其中obj是要引用的对象,类型是jobject
2.读取要调用方法的定义(jmethodID)
我们先来看看JNI中获取方法定义的函数:
jmethodID (JNICALL *GetMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig); jmethodID (JNICALL *GetStaticMethodID)(JNIEnv *env, jclass class, const char *name, const char *sig);
这两个函数的区别在于GetStaticMethodID是用来获取静态方法的定义,GetMethodID则是获取非静态的方法定义。这两个函数都需要提供四个参数:env就是初始化虚拟机得到的JNI环境;第二个参数class是对象的类定义,也就是第一步得到的obj;第三个参数是方法名称;最重要的是第四个参数,这个参数是方法的定义。因为我们知道Java中答应方法的多态,仅仅是通过方法名并没有办法定位到一个具体的方法,因此需要第四个参数来指定方法的具体定义。但是怎么利用一个字符串来表示方法的具体定义呢?JDK中已经预备好一个反编译工具javap,通过这个工具就可以得到类中每个属性、方法的定义。下面就来看看jni.test.Demo的定义:
打开命令行窗口并运行 javap -s -p jni.test.Demo 得到运行结果如下:
Compiled from Demo.java public class jni.test.Demo extends java.lang.Object { public static int COUNT; /* I */ public java.lang.String msg; /* Ljava/lang/String; */ private int counts[]; /* [I */ public jni.test.Demo(); /* ()V */ public jni.test.Demo(java.lang.String); /* (Ljava/lang/String;)V */ public java.lang.String getMessage(); /* ()Ljava/lang/String; */ public int getCounts()[]; /* ()[I */ public void setCounts(int[]); /* ([I)V */ public void throwExcp() throws java.lang.IllegalAccessException; /* ()V */ static {}; /* ()V */ }
我们看到类中每个属性和方法下面都有一段注释。注释中不包含空格的内容就是第四个参数要填的内容(关于javap具体参数请查询JDK的使用帮助)。下面这段代码演示如何访问jni.test.Demo的getMessage方法:
/* 假设我们已经有一个jni.test.Demo的实例obj */ jmethodID mid; jclass cls = (*env)-> GetObjectClass (env, obj);//获取实例的类定义 mid=(*env)->GetMethodID(env,cls,"getMessage"," ()Ljava/lang/String; "); /*假如mid为0表示获取方法定义失败*/ jstring msg = (*env)-> CallObjectMethod(env, obj, mid); /* 假如该方法是静态的方法那只需要将最后一句代码改为以下写法即可: jstring msg = (*env)-> CallStaticObjectMethod(env, cls, mid); */
3.调用方法
为了调用对象的某个方法,可以使用函数CallMethod或者CallStaticMethod(访问类的静态方法),根据不同的返回类型而定。这些方法都是使用可变参数的定义,假如访问某个方法需要参数时,只需要把所有参数按照顺序填写到方法中就可以。在讲到构造函数的访问时,将演示如何访问带参数的构造函数。
访问类属性
访问类的属性与访问类的方法大体上是一致的,只不过是把方法变成属性而已。
1.获取指定对象的类(jclass)
这一步与访问类方法的第一步完全相同,具体使用参看访问类方法的第一步。
2.读取类属性的定义(jfieldID)
在JNI中是这样定义获取类属性的方法的:
jfieldID (JNICALL *GetFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig); jfieldID (JNICALL *GetStaticFieldID) (JNIEnv *env, jclass clazz, const char *name, const char *sig);
这两个函数中第一个参数为JNI环境;clazz为类的定义;name为属性名称;第四个参数同样是为了表达属性的类型。前面我们使用javap工具获取类的具体定义的时候有这样两行:
public java.lang.String msg; /* Ljava/lang/String; */
其中第二行注释的内容就是第四个参数要填的信息,这跟访问类方法时是相同的。
3.读取和设置属性值
有了属性的定义要访问属性值就很轻易了。有几个方法用来读取和设置类的属性,它们是:GetField、SetField、GetStaticField、SetStaticField。比如读取Demo类的msg属性就可以用GetObjectField,而访问COUNT用GetStaticIntField,相关代码如下:
jfieldID field = (*env)->GetFieldID(env,obj,"msg"," Ljava/lang/String;"); jstring msg = (*env)-> GetObjectField(env, cls, field);//msg就是对应Demo的msg jfieldID field2 = (*env)->GetStaticFieldID(env,obj,"COUNT","I"); jint count = (*env)->GetStaticIntField(env,cls,field2);
访问构造函数
很多人刚刚接触JNI的时候往往会在这一节碰到问题,查遍了整个jni.h看到这样一个函数NewObject,它应该是可以用来访问类的构造函数。但是该函数需要提供构造函数的方法定义,其类型是jmethodID。从前面的内容我们知道要获取方法的定义首先要知道方法的名称,但是构造函数的名称怎么来填写呢?其实访问构造函数与访问一个普通的类方法大体上是一样的,惟一不同的只是方法名称不同及方法调用时不同而已。访问类的构造函数时方法名必须填写“”。下面的代码演示如何构造一个Demo类的实例:
jclass cls = (*env)->FindClass(env, "jni/test/Demo"); /** 首先通过类的名称获取类的定义,相当于Java中的Class.forName方法 */ if (cls == 0) jmethodID mid = (*env)->GetMethodID(env,cls,"","(Ljava/lang/String;)V "); if(mid == 0) jobject demo = jenv->NewObject(cls,mid,0); /** 访问构造函数必须使用NewObject的函数来调用前面获取的构造函数的定义 上面的代码我们构造了一个Demo的实例并传一个空串null */
数组处理
创建一个新数组
要创建一个数组,我们首先应该知道数组元素的类型及数组长度。JNI定义了一批数组的类型jArray及数组操作的函数NewArray,其中就是数组中元素的类型。例如,要创建一个大小为10并且每个位置值分别为1-10的整数数组,编写代码如下:
int i = 1; jintArray array;//定义数组对象 (*env)-> NewIntArray(env, 10); for(; i<= 10; i++) (*env)->SetIntArrayRegion(env, array, i-1, 1, &i);
访问数组中的数据
访问数组首先应该知道数组的长度及元素的类型。现在我们把创建的数组中的每个元素值打印出来,代码如下:
int i; /* 获取数组对象的元素个数 */ int len = (*env)->GetArrayLength(env, array); /* 获取数组中的所有元素 */ jint* elems = (*env)-> GetIntArrayElements(env, array, 0); for(i=0; i< len; i++) printf("ELEMENT %d IS %d ", i, elems[i]);
中文处理
中文字符的处理往往是让人比较头疼的事情,非凡是使用Java语言开发的软件,在JNI这个问题更加突出。由于Java中所有的字符都是Unicode编码,但是在本地方法中,例如用VC编写的程序,假如没有非凡的定义一般都没有使用Unicode的编码方式。为了让本地方法能够访问Java中定义的中文字符及Java访问本地方法产生的中文字符串,我定义了两个方法用来做相互转换。
· 方法一,将Java中文字符串转为本地字符串
/** 第一个参数是虚拟机的环境指针第二个参数为待转换的Java字符串定义第三个参数是本地存储转换后字符串的内存块第三个参数是内存块的大小 */ int JStringToChar(JNIEnv *env, jstring str, LPTSTR desc, int desc_len) { int len = 0; if(desc==NULLstr==NULL) return -1; //在VC中wchar_t是用来存储宽字节字符(UNICODE)的数据类型 wchar_t *w_buffer = new wchar_t[1024]; ZeroMemory(w_buffer,1024*sizeof(wchar_t)); //使用GetStringChars而不是GetStringUTFChars wcscpy(w_buffer,env->GetStringChars(str,0)); env->ReleaseStringChars(str,w_buffer); ZeroMemory(desc,desc_len); //调用字符编码转换函数(Win32 API)将UNICODE转为ASCII编码格式字符串 //关于函数WideCharToMultiByte的使用请参考MSDN len = WideCharToMultiByte(CP_ACP,0,w_buffer,1024,desc,desc_len,NULL,NULL); //len = wcslen(w_buffer); if(len>0 && len
· 方法二,将C的字符串转为Java能识别的Unicode字符串
jstring NewJString(JNIEnv* env,LPCTSTR str) { if(!env !str) return 0; int slen = strlen(str); jchar* buffer = new jchar[slen]; int len = MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,slen); if(len>0 && len < slen) buffer[len]=0; jstring js = env->NewString(buffer,len); delete [] buffer; return js; }
异常
由于调用了Java的方法,因此难免产生操作的异常信息。这些异常没有办法通过C++本身的异常处理机制来捕捉到,但JNI可以通过一些函数来获取Java中抛出的异常信息。之前我们在Demo类中定义了一个方法throwExcp,下面将访问该方法并捕捉其抛出来的异常信息,代码如下:
/** 假设我们已经构造了一个Demo的实例obj,其类定义为cls */ jthrowable excp = 0;/* 异常信息定义 */ jmethodID mid=(*env)->GetMethodID(env,cls,"throwExcp","()V"); /*假如mid为0表示获取方法定义失败*/ jstring msg = (*env)-> CallVoidMethod(env, obj, mid); /* 在调用该方法后会有一个IllegalAccessException的异常抛出 */ excp = (*env)->ExceptionOccurred(env); if(excp){ (*env)->ExceptionClear(env); //通过访问excp来获取具体异常信息 /* 在Java中,大部分的异常信息都是扩展类java.lang.Exception,因此可以访问excp的toString 或者getMessage来获取异常信息的内容。访问这两个方法同前面讲到的如何访问类的方法是相同的。 */ }
线程和同步访问
有些时候需要使用多线程的方式来访问Java的方法。我们知道一个Java虚拟机是非常消耗系统的内存资源,差不多每个虚拟机需要内存大约在20MB左右。为了节省资源要求每个线程使用的是同一个虚拟机,这样在整个的JNI程序中只需要初始化一个虚拟机就可以了。所有人都是这样想的,但是一旦子线程访问主线程创建的虚拟机环境变量,系统就会出现错误对话框,然后整个程序终止。
其实这里面涉及到两个概念,它们分别是虚拟机(JavaVM *jvm)和虚拟机环境(JNIEnv *env)。真正消耗大量系统资源的是jvm而不是env,jvm是答应多个线程访问的,但是env只能被创建它本身的线程所访问,而且每个线程必须创建自己的虚拟机环境env。这时候会有人提出疑问,主线程在初始化虚拟机的时候就创建了虚拟机环境env。为了让子线程能够创建自己的env,JNI提供了两个函数:AttachCurrentThread和DetachCurrentThread。下面代码就是子线程访问Java方法的框架:
DWord WINAPI ThreadProc(PVOID dwParam) { JavaVM jvm = (JavaVM*)dwParam;/* 将虚拟机通过参数传入 */ JNIEnv* env; (*jvm)-> AttachCurrentThread(jvm, (void**)&env, NULL); ......... (*jvm)-> DetachCurrentThread(jvm); }
时间
关于时间的话题是我在实际开发中碰到的一个问题。当要发布使用了JNI的程序时,并不一定要求客户要安装一个Java运行环境,因为可以在安装程序中打包这个运行环境。为了让打包程序利于下载,这个包要比较小,因此要去除JRE(Java运行环境)中一些不必要的文件。但是假如程序中用到Java中的日历类型,例如java.util.Calendar等,那么有个文件一定不能去掉,这个文件就是[JRE]lib zmappings。它是一个时区映射文件,一旦没有该文件就会发现时间操作上经常出现与正确时间相差几个小时的情况。下面是打包JRE中必不可少的文件列表(以Windows环境为例),其中[JRE]为运行环境的目录,同时这些文件之间的相对路径不能变。
文件名目录 hpi.dll [JRE]in ioser12.dll [JRE]in java.dll [JRE]in net.dll [JRE]in verify.dll [JRE]in zip.dll [JRE]in jvm.dll [JRE]inclassic rt.jar [JRE]lib tzmappings [JRE]lib
由于rt.jar有差不多10MB,但是其中有很大一部分文件并不需要,可以根据实际的应用情况进行删除。例如程序假如没有用到Java Swing,就可以把涉及到Swing的文件都删除后重新打包。

❸ JNI传递类对象的问题,如何获取long类型

你的JNI接口定义抄错误,在Java层传袭入了4个参数,你的JNI接口只有一个参数。

JNIEXPORTjintJNICALLJava_org_jniInterface_CommitTask_myReceiveMsg
(JNIEnv*env,jclassobj,jinit,jint,jstring,jobjectjobj)

前两个参数是默认的,从第三个开始是你需要对应的java接口的参数

❹ 如何用Java程序改变系统环境变量

最近在做一个项目的时候,遇到一个要在java程序中改变linux的PATH环境变量的问题。我们知道在linux中PATH环境变量保存在用户根目录下的“.bashrc”和“.bash_profile这两个隐藏文件中。用户登录的过程中便会把这两个文件中的PATH路径记录的该用户的shell中。如果用户已经登录,这时可通过命令 export PATH=add_path:$PATH来增加一个路径为add_path的路径。但通过此种方式增加的PATH路径只在当前shell中有效(也就是说,当用户通过另一个shell登录时,PATH又变成了原来的值)。在windows中用户已经登录的情况下则是通过命令set来更改环境变量的。

Java语言是一门跨平台的语言,具有一次编写到处运行的特点。在java的1.0版本中有System.getenv(String key)可以来取得操作系统的环境变量,但由于getenv()具有与操作系统紧密相关的特性,这与java的跨平台的跟本特征相冲突,所以在java1.2中该方法被不推荐使用。而程序员在编程的过程中经常需要用到getenv(),所以在java1.5中getenv()又重新回来了。虽然可以通过getenv()来取得系统的环境变量,但是却没有与getenv()相对应的setenv()函数来改变系统的环境变量。

C语言是一门与平台相关的语言,在多年的发展中积累了数量相当可观的库函数,在stdlib.h函数库中就有getenv(参数省略)与setenv(参数省略)来获取和改变系统的环境变量,这就给我们一个提示:能不能在java语言中调用C语言的函数库?JNI(java本地接口)正给了我们这样一个选择。

1.首先生成ChangeEnv.java文件

/**
* @author sgh
* @version 1.0.0 06/07/21
*/
public class ChangeEnv {

/**
* @param args
*/
static {
try{
System.loadLibrary("change_env");//声明欲加载的动态链接库
}
catch(UnsatisfiedLinkError e ){
System.err.println("Can not load library "+e.toString());

}
}
public native void setEnv(String name ,String value, int replace);//声明一个本地调用接口

}

说明:

1. 动态链接库在windows中是.dll文件,在linux中则是.so文件,但在System.loadLibrary("change_env")中不需要把后缀写出 ,程序会自己判断。
2. 本地接口声明方式为在普通函数前加native关键字
2. 编译java文件 :Javac ChangeEnv.java
3. 使用命令 javah ChangeEnv 生成ChangeEnv.h文件(ChangeEnv.h文件由程序自动生成,程序员不需要作任何改动)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ChangeEnv */

#ifndef _Included_ChangeEnv
#define _Included_ChangeEnv
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ChangeEnv
* Method: setEnv
* Signature: (Ljava/lang/String;Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL Java_ChangeEnv_setEnv
(JNIEnv *, jobject, jstring, jstring, jint);

#ifdef __cplusplus
}
#endif
#endif

说明:

1.JNIEXPORT void JNICALL Java_ChangeEnv_setEnv
(JNIEnv *, jobject, jstring, jstring, jint)是本地接口函数的声明需要在.cpp文件中实现它

4.编写ChangeEnv.cpp

#include"ChangeEnv.h"
#include<stdio.h>
#include<stdlib.h>
//与ChangeEnv.h中函数声明相同
JNIEXPORT void JNICALL Java_ChangeEnv_setEnv(JNIEnv * env, jobject obj, jstring name, jstring value, jint replace)
{
////从instring字符串取得指向字符串UTF编码的指针
const char * name_char =(const char *) env->GetStringUTFChars(name ,JNI_FALSE);
const char * value_char =(const char *) env->GetStringUTFChars(value ,JNI_FALSE);
//实际调用的C库函数
setenv(name_char,value_char,replace);
//通知虚拟机本地代码不再需要通过name_char访问Java字符串,否则会
//造成内存泄露
env->ReleaseStringUTFChars(name,(const char *)name_char);
env->ReleaseStringUTFChars(value,(const char *)value_char);
return ;
}
5.编译ChangeEnv.cpp文件,生成libchange_env.so文件
gcc -I/home/disk4/sgh/sgh/jrockit/include -I/home/disk4/sgh/sgh/jrockit/include/linux -shared -o libchange_env.so ChangeEnv.cpp
说明:
1. Linux下链接库名称必须以lib开头,否则会无法识别
6. 编写测试程序test.java
import java.io.InputStreamReader;
import java.io.LineNumberReader;

public class test {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(System.getenv("PATH"));//打印改变之前的PATH路径
String pathPer = System.getProperty("java.library.path");
pathPer+=":.";
System.setProperty("java.library.path",pathPer);//把当前目录加到动态链接库路径中
ChangeEnv changePath = new ChangeEnv ();//生成一个ChangeEnv对象
changePath.setEnv("PATH","$PATH:/home/disk4/sgh/sgh/soft/slurm34/bin:/home/disk4/sgh/sgh/soft/slurm34/sbin",1);
System.out.println(System.getenv("PATH"));//打印改变之后的PATH路径

}

}
说明:
1. 可以看到PATH路径发生了变化

JNI在windows下的使用
既然所有的.h ,.cpp文件都已写好,我们不防顺便编译以下windows下的动态链接库.dll文件。
这时我们发现在windows下的vc环境中没有setenv(char * name ,char * value ,int replace),而只有putenv(char * key_value)函数,所以我们必须重写ChangeEnv.cpp,为了使ChangeEnv.class对外接口保持一致性,所以我们没有改写ChangeEnv.java中本地函数借口的声明。
1. 重写ChangeEnv.cpp函数
#include"ChangeEnv.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//与ChangeEnv.h中函数声明相同
JNIEXPORT void JNICALL Java_ChangeEnv_setEnv(JNIEnv * env, jobject obj, jstring name, jstring value, jint replace)
{
if(replace==0)//如果replace==0表示不发生置换,直接退出
return ;
////从instring字符串取得指向字符串UTF编码的指针
const char * name_char =(const char *) env->GetStringUTFChars(name ,JNI_FALSE);
const char * value_char =(const char *) env->GetStringUTFChars(value ,JNI_FALSE);
//实际调用的C库函数,把环境变量写成key=value格式
char * key_value=(char *)name_char;
strcat(key_value, "=");
strcat(key_value, value_char);
putenv(key_value);
//通知虚拟机本地代码不再需要通过name_char访问Java字符串,否则会
//造成内存泄露
env->ReleaseStringUTFChars(name,(const char *)name_char);
env->ReleaseStringUTFChars(value,(const char *)value_char);
return ;
}
2. 在vc6中新建一个动态链接库工程,添加ChangeEnv.h和ChangeEnv.cpp到该工程中去
3. 在“工具”----〉“选项-”----〉“目录”中添加java的include路径
C:\Program Files\Java\jdk1.5.0_06\include和C:\Program Files\Java\jdk1.5.0_06\include\win32
4. 单击“运行”,把生成的change_env.dll拷贝到ChangeEnv.java所在的工程目录中
5. 在ChangeEnv.java所在工程中新建一个测试程序test.java
import java.io.InputStreamReader;
import java.io.LineNumberReader;

public class test {

/**
* @param args
*/
public static void main(String[] args) {

ChangeEnv changePath = new ChangeEnv();
changePath.setEnv("PATH", "%PATH%;c:\\", 1);
System.out.println(System.getenv("PATH"));

}

}
转载

❺ 如何在 Swift 中优雅地处理 JSON

SwiftyJSON的使用十分的简单:
典型的NSURLSessionTask抓取Twitter的API将产生dataFromNetwork: NSData!:
你首先应该做的事情是初始化JSONValue:
let json = JSONValue(dataFromNetwork)
JSONValue是一个枚举类型表示一个典型的JSON数据结构。
你能使用subscripts检索不同的值从原始的JSONValue中,像这样:
let userName:JSONValue = json[0]["user"]["name"]
注意userName仍然是一个JSONValue。那怎样得到一个字符串呢?
你能用.string属性得到JSON数据表示的真正值。
let userNameString = userName.string!
对每一种JSON类型, JSONValue都提供了一种属性检索它:
var string: String?
var number: NSNumber?
var bool: Bool?
var array: Array<JSONValue>?
var object: Dictionary<String, JSONValue>?
注意每一种属性都是一个Optional值。这是因为JSON数据能包含任何它定义的有效类型。
因此,建议的方式是用Optional绑定检索值:
if let name = userName.string{
//This could avoid lots of crashes caused by the unexpected data types
}

if let name = userName.number{
//As the value of the userName is Not a number. It won't execute.
.number属性产生一个NSNumber值,在Swift中这通常不是很有用。你能用.double或者.integer得到一个Double值或者一个Int值。
if let intValue = numberValue.integer{
count += intValue
}
枚举(Enumeration)
在Swift中JSONValue实际上是一个枚举:
enum JSONValue {

case JNumber(NSNumber)
case JString(String)
case JBool(Bool)
case JNull
case JArray(Array<JSONValue>)
case JObject(Dictionary<String,JSONValue>)
case JInvalid(NSError)

}
你可以使用一个switch子句去更有效地获取值:
let json = JSONValue(jsonObject)
switch json["user_id"]{
case .JString(let stringValue):
let id = stringValue.toInt()
case .JNumber(let numberValue):
let id = numberValue.integerValue
default:
println("ooops!!! JSON Data is Unexpected or Broken")
下标(Subscripts)
注意,在JSON中一个数组结构被包装成intoArray<JSONVlaue>,它意味着数组里的每一个元素都是一个JSONValue。甚至你从JSONValue中取出一个数组,你仍然可以使用基本的属性去获取元素的值:
if let array = json["key_of_array"].array{
if let string = array[0].string{
//The array[0] is still a JSONValue!
}
}
对象也是一样。因此,推荐的方式是访问每一个数组和对象时使用JSONValue的下标。
if let string = json["key_of_array"][0].string{

}
实际上,你可以用下标访问一个JSONValue,还不用担心运行时错误导致的崩溃:
let userName = json[99999]["wrong_key"]
如果你使用推荐的方式去取数据,它是安全的:
if let userName = json[99999]["wrong_key"]["name"].string{
//It's always safe
}
打印
JSONValue遵守Printable协议.所以很容易在原始字符串中得到JSON数据:
let json = JSONValue(dataFromNetwork)
println(json)
/*You can get a well printed human readable raw JSON string:
{
"url": {
"urls": [
{
"expanded_url": null,
"url": "http://bit.ly/oauth-dancer",
"indices": [
0,
26
],
"display_url": null
}
]
}
*/
如果你不想打印出来,你可以使用.description属性来得到上述字符串。
let printableString = json.description
调试与错误处理
要是JSON数据出错或者我们错误地检索数据,那会怎么样呢?你可以使用if语句来测试:
let json = JSONValue(dataFromNetworking)["some_key"]["some_wrong_key"]["wrong_name"]
if json{
//JSONValue it self conforms to Protocol "LogicValue", with JSONValue.JInvalid stands for false and others stands true
}
如果我们尝试使用错误的键值或索引来访问数据,description属性会高数你KeyPath在哪里出错了.
let json = JSONValue(dataFromNetworking)["some_key"]["some_wrong_key"]["wrong_name"]
if json{

} else {
println(json)
//> JSON Keypath Error: Incorrect Keypath "some_wrong_key/wrong_name"
//It always tells you where your key went wrong
switch json{
case .JInvalid(let error):
//An NSError containing detailed error information
}
}

阅读全文

与打印jstring相关的资料

热点内容
网络人绿色版 浏览:450
linux服务器启动oracle 浏览:621
win10怎么语音呼唤小娜 浏览:456
qq飞车银天使 浏览:612
骑车赚钱app 浏览:111
怎么从电脑上下编程 浏览:508
linux如何复制到其他文件夹 浏览:70
碧蓝航线文件找不到怎么办 浏览:937
苹果备份的文件夹怎么恢复 浏览:941
看小黄APP有哪些 浏览:206
怎样在手机看264文件 浏览:80
常熟有哪里学编程的 浏览:162
我的下载的文件在哪里 浏览:563
文本显示器编程教程 浏览:942
电脑应用如何设置密码 浏览:336
怎么编程搜狗指南 浏览:155
代聊微信号 浏览:623
linux切换用户执行脚本 浏览:841
局内人未删减版本 浏览:159
app计步器软件如何同步支付宝 浏览:979

友情链接