C读写配置文件
在项目开发中,经常需要读取应用配置文件的初始化参数,用于应用在启动前进行一些初始化配置。比如:Eclipse,参数项包含主题、字体大小、颜色、Jdk安装位置、自动提示等。Eclispe配置的文件格式是以键值对的方式存储的,即:key=value的形式,下面是Eclipse部份设置参数:
/instance/org.eclipse.jdt.ui/useQuickDiffPrefPage=true
/instance/org.eclipse.jdt.ui/content_assist_proposals_foreground=0,0,0
/instance/org.eclipse.egit.core/GitRepositoriesView.GitDirectories=/Users/yangxin/Downloads/kakaolink-android/.git\:/Users/yangxin/Documents/workspace_web/tfyj/.git\:
/instance/org.eclipse.wst.jsdt.ui/fontPropagated=true
/instance/org.eclipse.debug.core/org.eclipse.debug.core.USE_STEP_FILTERS=true
/instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
/instance/org.eclipse.ui.workbench/org.eclipse.jface.textfont=1|Monaco|14.0|0|COCOA|1|Monaco;
@org.eclipse.jdt.ui=3.8.2.v20130107-165834
/instance/org.eclipse.cdt.ui/spelling_locale_initialized=true
从Eclipse配置文件中可以看出,都是以xxxx=xxxxx,如最后一个配置项,key为/instance/org.eclipse.cdt.ui/spelling_locale_initialized,值为:true。在项目开发当中的也经常采用这种方式,笔者参考了Java的java.util.Properties类,设计了一个C的配置文件读写接口,供大家学习和使用。
1、定义接口头文件(Properties.h)
//
// Properties.h
// 读写配置文件
//
// Created by 杨信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
// #ifndef _______Properties_h
#define _______Properties_h #ifdef _cplusplus
extern "C" {
#endif // 初始化环境,成功返回0,失败返回非0值
int init(const char *filepath,void **handle); // 根据KEY获取值,找到返回0,如果未找到返回非0值
int getValue(void *handle, const char *key, char *value); // 修改key对应的属性值,修改成功返回0,失败返回非0值
int setValue(void *handle, const char *key, const char *value); // 添加一个属性,添加成功返回0,失败返回非0值
int add(void *handle, const char *key, const char *value); // 删除一个属性,删除成功返回0,失败返回非0值
int del(void *handle, const char *key); // 获取属性文件中所有的key,获取成功返回0,失败返回非0值
int getKeys(void *handle, char ***keys, int *keyscount); // 释放所有key的内存空间,成功返回0,失败返回非0值
int free_keys(char ***keys,int *keyscount); // 获取属性文件中所有的值,成功返回0,失败返回非0值
int getValues(void *handle, char ***values, int *valuescount); // 释放所有value的内存空间,成功返回0,失败返回非0值
int free_values(char ***values, int *valuescount); // 获取属性数量,成功返回0,失败返回非0值
int getCount(void *handle, int *count); // 释放环境资源,成功返回0,失败返回非0值
int release(void **handle); #ifdef _cplusplus
}
#endif #endif
2、实现头文件的接口(Properteis.c)
//
// Properties.c
// 读写配置文件
//
// Created by 杨信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
// #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include "Properties.h" #define KEY_SIZE 128 // key缓冲区大小
#define VALUE_SIZE 128 // value缓冲区大小 #define LINE_BUF_SIZE 256 // 读取配置文件中每一行的缓冲区大小 typedef struct Properties {
char *key;
char *value;
struct Properties *pNext;
}Properties; typedef struct PROPS_HANDLE {
Properties *pHead; // 属性链表头节点
char *filepath; // 属性文件路径
}PROPS_HANDLE; static int createPropsNode(Properties **props); // 创建一个节点
static int trimeSpace(const char *src,char *dest); // 去空格
static int saveConfig(const char *filepath,Properties *head); // 将修改或保存后的配置项保存到文件 // 初始化环境,成功返回0,失败返回非0值
int init(const char *filepath,void **handle)
{
int ret = 0;
FILE *fp = NULL;
Properties *pHead = NULL,*pCurrent = NULL, *pMalloc = NULL;
PROPS_HANDLE *ph = NULL;
char line[LINE_BUF_SIZE]; // 存放读取每一行的缓冲区
char keybuff[KEY_SIZE] = { 0 }; // 存放key的缓冲区
char valuebuff[VALUE_SIZE] = { 0 }; // 存放value的缓冲区
char *pLine = NULL; // 每行缓冲区数据的指针 if(filepath == NULL || handle == NULL)
{
ret = -1;
printf("fun init error:%d from (filepath == NULL || handler == NULL)\n",ret);
return ret;
} ph = (PROPS_HANDLE *)malloc(sizeof(PROPS_HANDLE));
if (ph == NULL) {
ret = -2;
printf("fun init malloc handle error:%d",ret);
return ret;
}
memset(ph, 0, sizeof(PROPS_HANDLE)); // 打开文件
fp = fopen(filepath, "r");
if (!fp) {
ret = -3;
printf("fun init open file error:%d from %s\n",ret,filepath);
return ret;
} // 创建头节点
ret = createPropsNode(&pHead);
if (ret != 0) {
fclose(fp); // 关闭文件
printf("fun init create head node error:%d\n",ret);
return ret;
}
memset(pHead, 0, sizeof(Properties)); // 保存链表头节点和文件路径到handle中
ph->pHead = pHead;
ph->filepath = (char *)malloc(strlen(filepath) + 1);
strcpy(ph->filepath, filepath); pCurrent = pHead; // 读取配置文件中的所有数据
while (!feof(fp)) {
if(fgets(line, LINE_BUF_SIZE, fp) == NULL)
{
break;
} // 找等号
if ((pLine = strstr(line, "=")) == NULL) { // 没有等号,继续读取下一行
continue;
} // 循环创建节点
ret = createPropsNode(&pMalloc);
if (ret != 0) {
fclose(fp); // 关闭文件
release((void **)&ph); // 创建节点失败,释放所有资源
printf("create new node error:%d\n",ret);
return ret;
} // 设置Key
memcpy(keybuff, line, pLine-line);
trimeSpace(keybuff, pMalloc->key); // 将keybuff去空格后放到pMallock.key中 // 设置Value
pLine += 1;
trimeSpace(pLine, valuebuff);
strcpy(pMalloc->value, valuebuff); // 将新节点入链表
pMalloc->pNext = NULL;
pCurrent->pNext = pMalloc;
pCurrent = pMalloc; // 当前节点下移 // 重置key,value
memset(keybuff, 0, KEY_SIZE);
memset(valuebuff, 0, VALUE_SIZE);
} // 设置环境句柄给调用者
*handle = ph; // 关闭文件
fclose(fp); return ret;
} // 获取属性数量,成功返回0,失败返回非0值
int getCount(void *handle, int *count)
{
int ret = 0,cn = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || count == NULL) {
ret = -1;
printf("fun getCount error:%d from (handle == NULL || count == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
cn++;
pCurrent = pCurrent->pNext;
} *count = cn; return ret;
} // 根据KEY获取值,找到返回0,如果未找到返回非0值
int getValue(void *handle, const char *key, char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("getValue error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
} ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
if (strcmp(pCurrent->key,key) == 0) {
break;
}
pCurrent = pCurrent->pNext;
} if (pCurrent == NULL) {
ret = -2;
printf("fun getValue warning: not found the key:%s\n",key);
return ret;
} strcpy(value, pCurrent->value); return ret;
} // 修改key对应的属性值,修改成功返回0,失败返回非0值
int setValue(void *handle, const char *key, const char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("fun setValue error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
} // 获得环境句柄
ph = (PROPS_HANDLE *)handle; // 从环境句柄中获取头节点
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
if (strcmp(pCurrent->key, key) == 0) { // 找到
break;
}
pCurrent = pCurrent->pNext;
} if (pCurrent == NULL) { // 未找到key
ret = -2;
printf("fun setValue warning: not found the key:%s\n",key);
return ret;
} // 修改key的value
strcpy(pCurrent->value, value);
if (strchr(value, '\n') == NULL) { // 加一个换行符
strcat(pCurrent->value, "\n");
} // 将修改的配置项写入到文件
ret = saveConfig(ph->filepath, ph->pHead); return ret;
} // 添加一个属性,添加成功返回0,失败返回非0值
int add(void *handle, const char *key, const char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("fun add error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
} ph = (PROPS_HANDLE *)handle; //-----------如果key存在链表中,则直接修改,否则添加到链表中-----------//
pCurrent = ph->pHead;
while (pCurrent->pNext != NULL) {
if (strcmp(pCurrent->pNext->key,key) == 0) {
break;
}
pCurrent = pCurrent->pNext;
} if (pCurrent->pNext != NULL) {
return setValue(handle, key, value);
} //-----------key不存在,创建一个新的配置项,添加到链表中-----------//
Properties *pMalloc;
ret = createPropsNode(&pMalloc);
if (ret != 0) {
printf("fun add error:%d from malloc new node.",ret);
return ret;
} strcpy(pMalloc->key, key);
if (strchr(pCurrent->value,'\n') == NULL) {
strcat(pCurrent->value, "\n");
}
strcpy(pMalloc->value, value);
if (strchr(value, '\n') == NULL) { // 加一个换行符
strcat(pMalloc->value, "\n");
}
pCurrent->pNext = pMalloc; // 新配置项入链表 // 将新配置项写入到文件
ret = saveConfig(ph->filepath, ph->pHead); return ret;
} // 删除一个属性,删除成功返回0,失败返回非0值
int del(void *handle, const char *key)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL, *pPrev = NULL;
if (handle == NULL || key == NULL) {
ret = -1;
printf("fun del error:%d from (handle == NULL || key == NULL)\n",ret);
return ret;
} ph = (PROPS_HANDLE *)handle;
pPrev = ph->pHead;
pCurrent = ph->pHead->pNext; while (pCurrent != NULL) {
if (strcmp(pCurrent->key, key) == 0) {
break;
}
pPrev = pCurrent; // 上一个节点下移
pCurrent = pCurrent->pNext; // 当前节点下移
} if (pCurrent == NULL) { // 没有找到
ret = -2;
printf("fun del warning:not found the key:%s\n",key);
return ret;
} pPrev->pNext = pCurrent->pNext; // 从链表中删除
free(pCurrent); // 释放内存
pCurrent = NULL; // 保存到文件
ret = saveConfig(ph->filepath, ph->pHead); return ret;
} // 获取属性文件中所有的key,获取成功返回0,失败返回非0值
int getKeys(void *handle, char ***keys, int *keyscount)
{
int ret = 0, count = 0, index = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
char **pKeys = NULL;
if (handle == NULL || keys == NULL || keyscount == NULL) {
ret = -1;
printf("fun getKeys error:%d from (handle == NULL || keys == NULL || keyscount == NULL) \n",ret);
return ret;
} // 获取配置项数量
ret = getCount(handle, &count);
if (ret != 0) {
printf("fun getKeys error:%d from getCount \n",ret);
return ret;
} ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext; // 根据链表长度,申请内存空间
pKeys = (char **)malloc(sizeof(char *) * count);
if (pKeys == NULL) {
ret = -2;
printf("fun getKeys error:%d from malloc keys\n",ret);
return ret;
} pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
pKeys[index] = pCurrent->key;
pCurrent = pCurrent->pNext;
index++;
} *keys = pKeys;
*keyscount = count; return ret;
} // 释放所有key的内存空间,成功返回0,失败返回非0值
int free_keys(char ***keys,int *keyscount)
{
int ret = 0;
if (keys == NULL || keyscount == NULL) {
ret = -1;
printf("fun free_keys error:%d from (keys == NULL || keyscount == NULL) \n",ret);
return ret;
} free(*keys);
*keys = NULL;
*keyscount = 0; return ret;
} // 获取属性文件中所有的值,成功返回0,失败返回非0值
int getValues(void *handle, char ***values, int *valuescount)
{
int ret = 0, count = 0, index = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
char **pValues = NULL;
if (handle == NULL || values == NULL || valuescount == NULL) {
ret = -1;
printf("fun getValues error:%d from (handle == NULL || values == NULL || valuescount == NULL)\n",ret);
return ret;
} // 获取配置项数量
ret = getCount(handle, &count);
if (ret != 0) {
printf("fun getValues error:%d from getCount \n",ret);
return ret;
} // 申请内存空间,存放所有的value
pValues = (char **)malloc(sizeof(char *) * count);
if (pValues == NULL) {
ret = -2;
printf("fun getValues error:%d from malloc values\n",ret);
return ret;
} ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
pValues[index] = pCurrent->value;
pCurrent = pCurrent->pNext;
index++;
} *values = pValues;
*valuescount = count; return ret;
} // 释放所有value的内存空间,成功返回0,失败返回非0值
int free_values(char ***values, int *valuescount)
{
int ret = 0;
if (values == NULL || valuescount == NULL) {
ret = -1;
printf("fun free_values error:%d from (values == NULL || valuescount == NULL) \n",ret);
return ret;
} free(*values);
*values = NULL;
*valuescount = 0; return ret;
} // 释放环境资源,成功返回0,失败返回非0值
int release(void **handle)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
if(handle == NULL)
{
ret = -1;
printf("release error:%d from (handler == NULL)\n",ret);
return ret;
} ph = (PROPS_HANDLE *)*handle; // 释放链表内存资源
Properties *pCurr = ph->pHead;
Properties *pTemp = NULL; while (pCurr != NULL) {
if (pCurr->key != NULL) {
free(pCurr->key);
pCurr->key = NULL;
} if (pCurr->value != NULL) {
free(pCurr->value);
pCurr->value = NULL;
} pTemp = pCurr->pNext; free(pCurr); pCurr = pTemp;
} // 释放存放配置文件路径分配的内存空间
if(ph->filepath != NULL)
{
free(ph->filepath);
ph->filepath = NULL;
} // 释放环境句柄本身
free(ph);
*handle = NULL; // 避免野指针 return ret;
} // 去空格
static int trimeSpace(const char *src,char *dest)
{
int ret = 0;
if (src == NULL || dest == NULL) {
ret = -1;
printf("trimeSpace error:%d from (src == NULL || dest == NULL)\n",ret);
return ret;
} const char *psrc = src;
unsigned long i = 0,j = strlen(psrc) - 1,len;
while (psrc[i] == ' ')
{
i++;
} while (psrc[j] == ' ') {
j--;
} len = j - i + 1; memcpy(dest,psrc+i,len);
*(dest+len) = '\0'; return ret;
} // 创建一个节点
static int createPropsNode(Properties **props)
{
int ret = 0;
Properties *p = NULL;
if (props == NULL) {
ret = -100;
printf("createProps error:%d from (props == NULL)\n",ret);
return ret;
} p = (Properties *)malloc(sizeof(Properties));
if (p == NULL) {
ret = -200;
printf("createProps malloc %ld bytes error:%d\n",sizeof(Properties),ret);
return ret;
}
p->key = (char *)malloc(KEY_SIZE);
p->value = (char *)malloc(VALUE_SIZE);
p->pNext = NULL; *props = p; return ret;
} // 保存到文件
static int saveConfig(const char *filepath,Properties *head)
{
int ret = 0,writeLen = 0;
FILE *fp = NULL;
Properties *pCurrent = NULL;
if (filepath == NULL || head == NULL) {
ret = -100;
printf("fun saveConfig error:%d from (filepath == NULL || head == NULL)\n",ret);
return ret;
} fp = fopen(filepath,"w");
if (fp == NULL) {
ret = -200;
printf("fun saveConfig:open file error:%d from %s\n",ret,filepath);
return ret;
} pCurrent = head->pNext;
while (pCurrent != NULL) {
writeLen = fprintf(fp, "%s=%s",pCurrent->key,pCurrent->value); // 返回写入的字节数,出现错误返回一个负值
if (writeLen < 0) { //TODO 如果写入失败,如何将写入的数据回退???
ret = -300;
printf("fun saveConfig err:%d from (%s=%s)\n",ret,pCurrent->key,pCurrent->value);
break;
}
pCurrent = pCurrent->pNext;
} fclose(fp); // 关闭文件 return ret;
}
3、测试代码(需要在项目根目录创建props.txt)
//
// main.c
// 读写配置文件
//
// Created by 杨信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
// #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Properties.h" int main(int argc, const char * argv[])
{
int ret;
void *handle;
const char *filepath = "/Users/yangxin/Desktop/props.txt";
// 初始化
ret = init(filepath, &handle);
if (ret != 0) {
printf("env init error:%d\n",ret);
return 0;
} char valuebuf[128];
// 测试获取配置项
ret = getValue(handle, "host", valuebuf);
if (ret == 0) {
printf("value=%s\n",valuebuf);
}
else {
printf("获取值host的值失败\n");
} // 测试修改配置项
ret = setValue(handle, "version", "1.2.3");
if (ret == 0) {
printf("修改成功!\n");
}
else{
printf("修改失败\n");
} // 测试添加配置项
ret = add(handle, "pool_connection_countxx", "2000");
if (ret == 0) {
printf("添加成功!\n");
}
else{
printf("添加失败\n");
} // 测试删除配置项
ret = del(handle, "connectionMax");
if (ret == 0) {
printf("删除成功!\n");
}
else{
printf("删除失败\n");
} // 测试获取所有配置项的key
char **keys = NULL;
int keyscount;
ret = getKeys(handle, &keys, &keyscount);
if (ret == 0) {
printf("一共有%d个Key\n",keyscount);
for (int i =0; i<keyscount; i++) {
printf("%s\n",keys[i]);
}
}
// 释放内存
ret = free_keys(&keys, &keyscount);
if (ret == 0) {
printf("keys释放内存成功!\n");
} // 测试获取所有配置项的value
char **values = NULL;
int valuescount;
ret = getValues(handle, &values, &valuescount);
if (ret == 0) {
printf("一共有%d个Value\n",valuescount);
for (int i = 0; i < valuescount; i++) {
printf("%s",values[i]);
}
}
// 释放内存
ret = free_values(&values, &valuescount);
if (ret == 0) {
printf("values释放内存成功!\n");
} // 释放资源
ret = release(&handle);
if (ret != 0) {
printf("env release error:%d\n",ret);
} return 0;
}
测试配置文件:
username=root
password=root123456
host=192.168.1.100
port=9090
connectionMax=200
version=1.0
测试结果:
源码下载地址:git@github.com:xyang0917/RWAppProperites.git
C读写配置文件的更多相关文章
- 用ConfigParser模块读写配置文件——Python
对于功能较多.考虑用户体验的程序,配置功能是必不可少的,如何存储程序的各种配置? 1)可以用全局变量,不过全局变量具有易失性,程序崩溃或者关闭之后配置就没了,再者配置太多,将变量分配到哪里也是需要考虑 ...
- 使用ConfigurationManager类读写配置文件
使用ConfigurationManager类 读写配置文件app.config,以下为代码: view plaincopy to clipboard print? using System; usi ...
- Python自动化测试 (二) ConfigParser模块读写配置文件
ConfigParser 是Python自带的模块, 用来读写配置文件, 用法及其简单. 直接上代码,不解释,不多说. 配置文件的格式是: []包含的叫section, section 下有op ...
- Python自动化测试 -ConfigParser模块读写配置文件
C#之所以容易让人感兴趣,是因为安装完Visual Studio, 就可以很简单的直接写程序了,不需要做如何配置. 对新手来说,这是非常好的“初体验”, 会激发初学者的自信和兴趣. 而有些语言的开发环 ...
- python:实例化configparser模块读写配置文件
之前的博客介绍过利用python的configparser模块读写配置文件的基础用法,这篇博客,介绍下如何实例化,方便作为公共类调用. 实例化的好处有很多,既方便调用,又降低了脚本的维护成本,而且提高 ...
- python:利用configparser模块读写配置文件
在自动化测试过程中,为了提高脚本的可读性和降低维护成本,将一些通用信息写入配置文件,将重复使用的方法写成公共模块进行封装,使用时候直接调用即可. 这篇博客,介绍下python中利用configpars ...
- python-ConfigParser模块【读写配置文件】
对python 读写配置文件的具体方案的介绍 1,函数介绍 import configParser 如果Configparser无效将导入的configParser 的C小写 1.1.读取配置文件 - ...
- python 读写配置文件
使用python读写配置文件,写个demo测试一下. #!/usr/bin/env python import os import ConfigParser # 如果文件不存在,就穿件文件. if o ...
- Java读写配置文件——Properties类的简要使用笔记
任何编程语言都有自己的读写配置文件的方法和格式,Java也不例外. 在Java编程语言中读写资源文件最重要的类是Properties,功能大致如下: 1. 读写Properties文件 2. 读写XM ...
随机推荐
- python如何使用 os.path.exists()--Learning from stackoverflow 分类: python 2015-04-23 20:48 139人阅读 评论(0) 收藏
Q&A参考连接 Problem:IOError: [Errno 2] No such file or directory. os.path.exists() 如果目录不存在,会返回一个0值. ...
- C++使用Json作为数据包装格式的通信
出处:http://adebugger.cn/2009/11/cpp-json-data-communication/ http://hi.baidu.com/tibelf/item/6be2accd ...
- 项目FAQ
报错: Conversion from String Literal to Char* is deprecated http://stackoverflow.com/questions/1369030 ...
- Java基础知识强化之集合框架笔记48:产生10个1~20之间的随机数(要求:随机数不能重复) 简洁版
1. 编写一个程序,获取10个1至20的随机数,要求随机数不能重复. 分析: A: 创建随机数对象 B: 创建一个HashSet集合 C: 判断集合的长度是不是小于10 是:就创建一个随机 ...
- jquery判断浏览器版本插件,jquery-browser.js
jquery判断浏览器版本插件,jquery-browser.js,jquery 判断是否为ie浏览器插件 >>>>>>>>>>>&g ...
- Spring声明式事务(xml配置事务方式)
Spring声明式事务(xml配置事务方式) >>>>>>>>>>>>>>>>>>>& ...
- 过滤器(filter)实现用户登录拦截
过滤器(filter)实现用户登录拦截 >>>>>>>>>>>>>>>>>>>> ...
- pc机安装centos6.5,提示sda必须有一个GPT磁盘标签处理
1.在进入安装界面,也就出现图形界面时,对它命令首先创建gpt --按ctrl+alt+f2的组合键,然后进入命令行 --进行如下操作输入parted输入mklabel gpt /dev/sda在提示 ...
- jar打包通过exe4j转换成exe文件
去年的时候有用过,最近写java的时候偶然用到,mark一下,方便以后看 下载链接后面附上 首先我们在eclipse上打包成jar文件,我这里只把简单的截图贴出来,详细的可以自行百度 打包jar文件: ...
- js - get-the-value-from-the-url-parameter(可以在非模态对话框中使用)
ref: http://stackoverflow.com/questions/979975/how-to-get-the-value-from-the-url-parameter 函数: funct ...