当前位置:首页>>开发编程>>JAVA>>新闻内容  
如何用Java程序改变系统环境变量
作者: 发布时间:2006-8-7 11:32:59 | 【字体:

    最近在做一个项目的时候,遇到一个要在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"));

    }

}


文章来源:
·Java开发技术十年的回顾与展望
·用java程序调用ffmpeg执行视频文件格式转换flv
·JavaBean与Enterprise JavaBean的区别
·Java开发人员的十大戒律
·JavaFX Script将终结AJAX?还是另一种选择?
·Eclipse五岁了:Java程序员的Eclipse情结
·审查Java代码的十一种常见错误
·Core JavaScript Guide
·Thinking In Java英文版
·在无线J2ME设备上实现超文本传输协议
 放生
 愚爱
 够爱
 触电
 白狐
 葬爱
 光荣
 画心
 火花
 稻香
 小酒窝
 下雨天
 右手边
 安静了
 魔杰座
 你不像她
 边做边爱
 擦肩而过
 我的答铃
 怀念过去
 等一分钟
 放手去爱
 冰河时代
 你的承诺
 自由飞翔
 原谅我一次
 吻的太逼真
 左眼皮跳跳
 做你的爱人
 一定要爱你
 飞向别人的床
 爱上别人的人
 感动天感动地
 心在跳情在烧
 玫瑰花的葬礼
 有没有人告诉你
 即使知道要见面
 爱上你是一个错
 最后一次的温柔
 爱上你是我的错
 怎么会狠心伤害我
 不是因为寂寞才想
 亲爱的那不是爱情
 难道爱一个人有错
 寂寞的时候说爱我