2011年11月8日
Java遍历Map
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
Java遍历Set
对 set 的遍历
1.迭代遍历:
Set<String> set = new HashSet<String>();
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String str = it.next();
System.out.println(str);
}
2.for循环遍历:
for (String str : set) {
System.out.println(str);
}
优点还体现在泛型 假如 set中存放的是Object
Set<Object> set = new HashSet<Object>();
for循环遍历:
for (Object obj: set) {
if(obj instanceof Integer){
int aa= (Integer)obj;
}else if(obj instanceof String){
String aa = (String)obj
}
........
}
当一个人找不到出路的时候,最好的办法就是将当前能做好的事情做到极致,做到无人能及。
今天在研究了一下关于ORACLE的导入导出的功能,周五快要下班的时候给同事新建一个表空间,将同一个数据库中的某个用户下的表导入新的表空间上,建好表空间和用户后,直接用 exp ,imp 来导入数据到新的表空间,查是发现后来导入的数据还在原来的表空间上,(周五那天的我是用工具编辑DMP文件,修改里的表空间名后导入的),后来想起来了eygle的书上写了关于这个的问题,于是今天就来试验了一下。
第一种:修改用户的一些权限。
首先使用sytem帐户登陆
--创建新表空间的用户
SQL> create user pangzi identified by pangzi default tablespace pangzi temporary tablespace temp;
用户已创建。
--授给新用户一般的权限
SQL> grant export full database to pangzi;
授权成功。
SQL> grant import full database to pangzi;
授权成功。
SQL> grant connect,resource to pangzi;
授权成功。
SQL> grant create procedure to pangzi;
授权成功。
SQL> grant create job to pangzi;
授权成功。
SQL> grant create view to pangzi;
授权成功。
SQL> grant create synonym to pangzi;
授权成功。
--从这里开始将是增加的,为了使导入的数据,不放在原来的表空间上
SQL> grant dba to pangzi;
--收回用户的umlimited tablespace权限
SQL> revoke unlimited tablespace from pangzi;
--设置新创建的用户可使用syb表空间的大小0(原数据所在的表空间为syb)
SQL> alter user pangzi quota 0 on syb;
--设置新创建的用户可使用pangzi表空间的大小不限制
SQL> alter user pangzi quota unlimited on pangzi;
--收回DBA权限
SQL> revoke dba from pangzi;
执行导入数据
C:\Users\dyspangzi>imp pangzi/pangzi@testdev file=syb.dmp full=y
Import: Release 10.2.0.3.0 - Production on 星期六 4月 21 17:48:54 2012
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
经由常规路径由 EXPORT:V10.02.01 创建的导出文件
警告: 这些对象由 SYB 导出, 而不是当前用户
已经完成 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集中的导入
. 正在将 SYB 的对象导入到 PANGZI
. . 正在导入表 "ALL_SALES"导入了 360 行
. . 正在导入表 "COUPONS"导入了 6 行
. . 正在导入表 "CUSTOMERS"导入了 5 行
. .中间部分内容省略,都是导入的信息
. . 正在导入表 "REG_EXPS"导入了 1 行
. . 正在导入表 "SALARY_GRADES"导入了 4 行
即将启用约束条件...
成功终止导入, 没有出现警告。
导入成功,我们看导的表已经在新的表空间中了
SQL> show user
USER 为 "PANGZI"
SQL> select table_name,tablespace_name from user_tables;
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
DYSPANGZI PANGZI
CUSTOMERS PANGZI
PRODUCT_TYPES PANGZI
PRODUCTS PANGZI
PURCHASES PANGZI
EMPLOYEES PANGZI
SALARY_GRADES PANGZI
PURCHASES_WITH_TIMESTAMP PANGZI
PURCHASES_TIMESTAMP_WITH_TZ PANGZI
PURCHASES_WITH_LOCAL_TZ PANGZI
COUPONS PANGZI
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
PROMOTIONS PANGZI
ORDER_STATUS PANGZI
PRODUCT_CHANGES PANGZI
MORE_PRODUCTS PANGZI
MORE_EMPLOYEES PANGZI
DIVISIONS PANGZI
JOBS PANGZI
EMPLOYEES2 PANGZI
ALL_SALES PANGZI
PRODUCT_PRICE_AUDIT PANGZI
REG_EXPS PANGZI
已选择22行。
第二种:使用EXPDP和IMPDP来导入和导出
使用expdp来导出,首先要为一个参数来指定一个路径——directory,expdp是在服务器端工作,导出的文件需要放在本地目录,这个参数就是保存导出文件的位置。这个可以自己创建,也可以是默认的,我自己创建了一个,名字是expdir
SQL> CREATE OR REPLACE DIRECTORY expdir AS '/var/backup';
目录已创建。
SQL> select * from dba_directories;
OWNER DIRECTORY_NAME DIRECTORY_PATH
------------------- ------------------------------- -----------------------------------------
SYS ADMIN_DIR /ade/aime_10.2_lnx_push/oracle/md/admin
SYS DATA_PUMP_DIR /usr/app/oracle/product/10.2.0/db_1/rdbms/log/
SYS WORK_DIR /ade/aime_10.2_lnx_push/oracle/work
SYS EXPDIR /var/backup
--给用户授予读写权限
SQL> grant read,write on directory expdir to syb;
开始导出数据
[oracle@dyspangzi ~]$ expdp dumpfile=syb.dmp directory=expdir;
Export: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:06:46
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Starting "SYB"."SYS_EXPORT_SCHEMA_01": dumpfile=syb.dmp directory=expdir
Estimate in progress using BLOCKS method...
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 1.375 MB
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/COMPILE_PACKAGE/PACKAGE_SPEC/ALTER_PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/ALTER_FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_BODY
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/TRIGGER
. . exported "SYB"."DYSPANGZI" 48.50 KB 659 rows
. . exported "SYB"."ALL_SALES" 13.68 KB 360 rows
中间导出信息省略
. . exported "SYB"."REG_EXPS" 5.437 KB 1 rows
. . exported "SYB"."SALARY_GRADES" 5.710 KB 4 rows
. . exported "SYB"."PRODUCT_PRICE_AUDIT" 0 KB 0 rows
Master table "SYB"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for SYB.SYS_EXPORT_SCHEMA_01 is:
/var/backup/syb.dmp
Job "SYB"."SYS_EXPORT_SCHEMA_01" successfully completed at 18:07:11
导出成功后查看一下刚才创建目录里边的内容
[root@dyspangzi var]# cd backup
[root@dyspangzi backup]# ls -l
总计 720
-rw-r--r-- 1 oracle oinstall 3472 04-21 18:07 export.log
-rw-r----- 1 oracle oinstall 729088 04-21 18:07 syb.dmp
多了两个文件,一个是日志文件一个是导出的数据文件,在导入的时候需要这两个文件。下面开始导入。
===================================================================================
出现了第一个错误
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:45:35
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
ORA-39002: invalid operation
ORA-39070: Unable to open the log file.
ORA-39087: directory name EXPDIR is invalid
出现了错误,后来发现这个是因为新用户pangzi没有对目录的读写权限造成的,于是加上权限
SQL> grant read,write on directory expdir to pangzi;
授权成功。
==================================================================================
出现了第二个错误
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:47:38
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
ORA-31655: no data or metadata objects selected for job
ORA-39154: Objects from foreign schemas have been removed from import
Master table "PANGZI"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "PANGZI"."SYS_IMPORT_FULL_01": pangzi/******** dumpfile=syb.dmp directory=expdir remap_tablespace=syb:pangzi
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Job "PANGZI"."SYS_IMPORT_FULL_01" successfully completed at 18:47:41
这个是由于原来的用户和现在的不一样了,加上这个参数就好了 remap_schema=syb:pangzi
=====================================================================================================
下面是没有任何错误的导入了
[oracle@dyspangzi ~]$ impdp pangzi/pangzi dumpfile=syb.dmp directory=expdir remap_schema=syb:pangzi remap_tablespace=syb:pangzi
Import: Release 10.2.0.1.0 - Production on Saturday, 21 April, 2012 18:49:24
Copyright (c) 2003, 2005, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
Master table "PANGZI"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "PANGZI"."SYS_IMPORT_FULL_01": pangzi/******** dumpfile=syb.dmp directory=expdir remap_schema=syb:pangzi remap_tablespace=syb:pangzi
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "PANGZI"."DYSPANGZI" 48.50 KB 659 rows
. . imported "PANGZI"."ALL_SALES" 13.68 KB 360 rows
中间部分导入信息省略
. . imported "PANGZI"."PURCHASES_WITH_TIMESTAMP" 5.609 KB 1 rows
. . imported "PANGZI"."REG_EXPS" 5.437 KB 1 rows
. . imported "PANGZI"."SALARY_GRADES" 5.710 KB 4 rows
. . imported "PANGZI"."PRODUCT_PRICE_AUDIT" 0 KB 0 rows
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/COMPILE_PACKAGE/PACKAGE_SPEC/ALTER_PACKAGE_SPEC
Processing object type SCHEMA_EXPORT/FUNCTION/ALTER_FUNCTION
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/PACKAGE/PACKAGE_BODY
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/TRIGGER
Job "PANGZI"."SYS_IMPORT_FULL_01" successfully completed at 18:49:37
成功导入!!!!
查看默认的表空间
SQL> select table_name,tablespace_name from user_tables;
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
DYSPANGZI PANGZI
CUSTOMERS PANGZI
PRODUCT_TYPES PANGZI
PRODUCTS PANGZI
PURCHASES PANGZI
EMPLOYEES PANGZI
SALARY_GRADES PANGZI
PURCHASES_WITH_TIMESTAMP PANGZI
PURCHASES_TIMESTAMP_WITH_TZ PANGZI
PURCHASES_WITH_LOCAL_TZ PANGZI
COUPONS PANGZI
TABLE_NAME TABLESPACE_NAME
------------------------------ ------------------------------
PROMOTIONS PANGZI
ORDER_STATUS PANGZI
PRODUCT_CHANGES PANGZI
MORE_PRODUCTS PANGZI
MORE_EMPLOYEES PANGZI
DIVISIONS PANGZI
JOBS PANGZI
EMPLOYEES2 PANGZI
ALL_SALES PANGZI
PRODUCT_PRICE_AUDIT PANGZI
REG_EXPS PANGZI
已选择22行。
此表空间中没有索引,所以第一种方法也没有报错,如果出现有索引的第一种方法还得增加几步,等我明天找到周五那个数据再来再着做试验。
-----------------------------------------------------------
今天特意去公司找来了那天导的数据库,回来做实验。采用第一种方法不可行,虽然说可以使用IMP 加indexs参数来导出一些索引,但是导入的时候总有莫名其妙的错误,估计还是我没弄好,所以为了省事还是直接用第二种吧,方便,无错。
1.在Oracle中可以用下面两种:
01:
create table newtable as select * from oldtable;//用于复制前未创建新表newtable不存在的情况
02:
insert into newtable select * from oldtable;//已经创建了新表newtable 的情况
注意:第一种方式只是复制了表结构,但是主键什么的并没有复制进去,所以用的时候要小心在意。
2.如果想简单快速的复制表结构,而不需要oldtable里面的数据,可以用下面的语句:
create table newtable as select * from oldtable where 1=2;(把数据过滤掉)
3.如过newtable 和oldtable的表结构不同,可以使用下面的方式:
create table newtable as select s.c1,s.c2 from oldtable s;
4.如果想重新命名newtable的列名:
在oracle中:
create table newtable(id,name1) as select s.c1,s.c2 from oldtable s;
或者
create table newtable as select s.c1 ,s.c2 from oldtable s;
在mysql中恐怕只能用第二种方式了。
5.如果是只需要把一部分的oldtable中的数据添加到newtable中。可以这样:
create table newtable as (select * from oldtable where ...);//加where过滤条件
6.最常见的情况是id列新表中要用,并且和旧表中的不同,使用下面的语句就可以了(我们可以重新建一个sequence)
create table yang(id,name) as select hibernate_sequence.nextval,t.ename from emp t;
7.要注意,导出表的时候不能用select...into语句。
方法1:在shell中执行LANG=en 将语言设为英语就可以了.SSH下很多中文都不支持.
方法2:
在使用ssh远程控制redhat服务器时,中文显示为乱码。这个问题困扰了好久,后来发现修改i18n这个文件能够修正乱码。
方法如下:修改/etc/sysconfig/i18n文件,将其改成以下内容:
LANG="zh_CN.GB18030"
LANGUAGE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"
SUPPORTED="zh_CN.UTF-8:zh_CN:zh:en_US.UTF-8:en_US:en"
SYSFONT="lat0-sun16"
重启机器,问题应该解决了。
方法3:
如果你用的是putty ,你只要在字符编码里选择utf-8就正常了
补充:这样做的后果是,在linux启动时,那些提示文字中文都变成了“?”符号。如果不习惯的话将ssh显示端改成英文吧。如下:
LANG=en_US
一、java实现DES加密算法为了实现一对密钥对整个项目所有加密解密文件都适用的方法,采用先生成一对密钥.保存到xml文件中,以后获得私匙和公钥只需要从xml文件中取得就可以了./*** 把成生的一对密钥保存到DesKey.xml文件中*/public static void saveDesKey(){ try { SecureRandom sr = new SecureRandom(); //为我们选择的DES算法生成一个KeyGenerator对象 KeyGenerator kg = KeyGenerator.getInstance ("DES" ); kg.init (sr); FileOutputStream fos = new FileOutputStream("C:/DesKey.xml"); ObjectOutputStream oos = new ObjectOutputStream(fos); //生成密钥 Key key = kg.generateKey(); oos.writeObject(key); oos.close(); } catch (Exception e) { e.printStackTrace(); }}获取密钥方法如下:
/*** 获得DES加密的密钥。在交易处理的过程中应该定时更* 换密钥。需要JCE的支持,如果jdk版本低于1.4,则需要* 安装jce-1_2_2才能正常使用。* @return Key 返回对称密钥*/ public static Key getKey() { Key kp = null; try { String fileName = "conf/DesKey.xml"; InputStream is = DesUtil.class.getClassLoader() .getResourceAsStream(fileName); ObjectInputStream oos = new ObjectInputStream(is); kp = (Key) oos.readObject(); oos.close(); } catch (Exception e) { e.printStackTrace(); } return kp; }文件采用DES算法加密文件
/**
* 文件file进行加密并保存目标文件destFile中
* @param file
* 要加密的文件 如c:/test/srcFile.txt
* @param destFile
* 加密后存放的文件名 如c:/加密后文件.txt
*/
public static void encrypt(String file, String destFile) throws Exception {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, getKey());
InputStream is = new FileInputStream(file);
OutputStream out = new FileOutputStream(dest);
CipherInputStream cis = new CipherInputStream(is, cipher);
byte[] buffer = new byte[1024];
int r;
while ((r = cis.read(buffer)) > 0) {
out.write(buffer, 0, r);
}
cis.close();
is.close();
out.close();
}文件采用DES算法解密文件
/**
* 文件file进行加密并保存目标文件destFile中
* @param file
* 已加密的文件 如c:/加密后文件.txt
* @param destFile
* 解密后存放的文件名 如c:/ test/解密后文件.txt
*/
public static void decrypt(String file, String dest) throws Exception { Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.DECRYPT_MODE, getKey()); InputStream is = new FileInputStream(file); OutputStream out = new FileOutputStream(dest); CipherOutputStream cos = new CipherOutputStream(out, cipher); byte[] buffer = new byte[1024]; int r; while ((r = is.read(buffer)) >= 0) { cos.write(buffer, 0, r); } cos.close(); out.close(); is.close(); }
1、查看操作系统版本和内核版本#uname –a
#more /etc/redhat-release
2、创建相关目录/usr/src/redhat/SOURCES //存放源代码,补丁,图标等文件。
/usr/src/redhat/SPECS //存放用于管理rpm制作进程的spec文件。
/usr/src/redhat/BUILD //解压后的文件存放在这里。
/usr/src/redhat/RPMS //存放由rpmbuild制作好的二进制包。
/usr/src/redhat/SRPMS //存放由rpmbuild制作好的源码包。
#mkdir -p /usr/src/redhat/
#cd /usr/src/redhat/
#mkdir SOURCES SPECS BUILD RPMS SRPMS
3、下载Nginx源码包下载源码包到SOURCES目录,不需要解压
#wget http://nginx.org/download/nginx-1.3.9.tar.gz
4、手工创建SPEC文件由于spec文件是由spec语言编写的,请注意spec语言的语法。
#cd /usr/src/redhat/SPECS/
#cat < nginx.spec > EOC
Summary: High Performance Web Server Name: nginx Version: 1.3.9 Release: el5 License: GPL Group: Applications/Server Source: http://nginx.org/download/nginx-1.3.9.tar.gz URL: http://nginx.org/ Distribution: Linux Packager: JingSheng <jingsheng1@staff.sina.com.cn> %description nginx [engine x] is a HTTP and reverse proxy server %prep useradd nginx -s /sbin/nologin rm -rf $RPM_BUILD_DIR/nginx-1.3.9 zcat $RPM_SOURCE_DIR/nginx-1.3.9.tar.gz | tar -xvf - %build cd $RPM_BUILD_DIR/nginx-1.3.9 ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx/ --with-http_stub_status_module --with-http_ssl_module make %install cd $RPM_BUILD_DIR/nginx-1.3.9 make install %preun if [ -z "`ps aux | grep nginx | grep -v grep`" ];then killall nginx >/dev/null exit 0 fi %files /usr/local/nginx |
#:以#开头是注释,rpm会忽略它。
Summary:简单描述软件。
Name :定义rpm的名称。
Version: 定义软件版本
Release: 发行版本
License: 定义许可证
Group: 软件分类
Source: 源码下载地址
URL: 源码相关网站
Distribution: 发行版系列
Packager: 打包人的信息
scription:软件详细描述,可多行
%prep :软件编译之前的处理,如解压。
%build :开始编译软件,如make
%install :开始安装软件,如make install
%files :指定哪些文件需要被打包,如/usr/local/nginx
%preun :定义卸载之前的动作,如杀掉进程。
5、开始RPM制作在制作RPM包之前,需要安装必要的编译工具
#yum install -y gcc rpm-build pcre-devel
开始编译生成rpm包
# rpmbuild-bb nginx.spec
注意:如果安装生成报错,请将安装过的东东全部去除,再重新打包
# rpm –qpl *.rpm 查看rpm包含哪些
最近一直在折腾linux,centos、redhat装了又装,到最后还是装了redhat。
以前多少接触过linux,但是都不深入(这次虽然也是皮毛,但是稍微知道了一些东东,现在就卖了),这次从零开始自己折腾linux,确实是被linux折腾了。linux跟windows确实有很多不同,有机会再继续介绍,这次先说一下使用Xmanager远程连接Redhat的经历。
Xmanager不多说了,是一款非常不错的管理工具。但是,如果要让Xmanager远程连接redhat,其实远程连接,主要还是想要做成跟windows的远程桌面一样的东西,图形界面方便啦!
只是这次配置Xmanager相当痛苦,按照网上各种资料对redhat进行配置,然后不停的reboot,但是,xmanager总是连不上。
这其中,修改的文件包括:
/usr/share/gdm/defaults.conf这个gdm的配置文件,主要是以下内容:
Enable=true
DisplaysPerHost=10
Port=177
还有/etc/inittab文件,主要是首先默认级别为5,这个文件貌似在安装的时候就已经默认为5了。id:5:initdefault:
然后最后一行的“x:5:respawn:/etc/X11/prefdm -nodaemon”调整为:
x:5:respawn:/usr/sbin/gdm
当然,还得改!
依然是/usr/share/gdm/defaults.conf,在[security]中调整以下的值:
AllowRoot=true
AllowRemoteRoot=true
AllowRemoteAutoLogin=true
如果开着防火墙,那还是要放开177端口,我暂时把防火墙关了。
reboot!reboot总是很重要的!
如果上述调整完成之后,依然无法连接,我就是这样的情况,连接不上啊!!!!
又随便找了几篇文章,也许跟hosts文件有关系哦!
打开/etc/hosts文件一看,空的!!!
在其中加上127.0.0.1 localhost,reboot,我总是喜欢reboot,这样比较干净!比较彻底!
在Xstart中配置好相应的参数,一定要在Commond中选择“GNOME”,这样再Run,Xbrowser将久违的redhat桌面打开了!
今天开发的同事,和我说
SecureCRT连接到IDC服务器,老超时断开,影响工作了
研究了下。
因为客户端与服务器之间存在路由器,防火墙以及为了本身的安全性,在超过特定的时间后就会把空闲连接断开。或者是服务器端设置了断开空闲连接。
解决方法:
既然会断开超时的空闲连接,那么我们就应该让客户端与服务器之间的连接“忙”起来,方法有两个:
从服务器方面入手:
修改/etc/ssh/sshd_config配置文件 ClientAliveInterval 300(默认为0)
这个参数的是意思是每5分钟,服务器向客户端发一个消息,用于保持连接
service sshd reload 生效
从客户端入手:
上面是配置需要服务器权限,如果没有服务器权限则可以使用这个方法,其思想是:客户端向服务器发一个消息,用于保持连接
secureCRT在选项 终端 反空闲 中设置每隔多少秒发送一个字符串,或者是NO-OP协议包
putty:putty -> Connection -> Seconds between keepalives ( 0 to turn off ), 默认为0, 改为300
CentOS 5远程SSH连接超时设定
操作系统:CentOS 5.6 SSH版本:OpenSSH_4.3p2
网上很多文章都说,远程SSH连接的超时设定是在/etc/ssh/sshd_config里,使用ClientAliveInterval和ClientAliveCountMax选项,我原来也这么认为的,不过一直没配置过超时。
今天配置了一下,发现这个是不对的,正确的配置是在/etc/profile里,使用TMOUT选项进行控制,如TMOUT=300,设定超时间隔为300秒。
远程桌面服务使局域网 (LAN) 上的计算机可以连接到服务器(也称为远程计算机)并运行位于服务器上的程序。这可以只需要在1台机器上安装应用程序,其他机器共享使用。远程桌面连接使用远程桌面服务技术,使一台计算机可远程控制另一台计算机。
windows 远程终端服务是单用户的,也就是说通过远程登录到服务器时,服务器本地将黑屏。如何做到不管用本地登录还是远程登录,同一时刻容许多个用户操作服务器计算机。
首先:
要安装工具包,需要从微软下载(远程服务器管理工具 http://www.microsoft.com/downloads/zh-cn/details.aspx?displaylang=zh-cn&FamilyID=7d2f6ad7-656b-4313-a005-4e344e43997d ),安装升级包后,在控制面板--程序和功能--打开或关闭WINDOWS功能---远程服务器管理工具--角色管理工具--远程桌面服务工具,选中前面的选择框。
在开始--命令框输入cmd,在弹出的Dos界面输入netstat -na ,如果出现 3389 端口,就说明远程终端已经启动了。
然后:
1, 下载 补丁UniversalTermsrvPatch,功能就是去除单用户登陆的限制,允许多人多用户同时并行访问登录。
2, 根据你的系统运行对应的程序:
32位系统请运行 UniversalTermsrvPatch-x86.exe;
64位系统请运行 UniversalTermsrvPatch-x64.exe。
3, 需要管理员权限。右键点程序,选择以管理员身份运行。
4, 破解后需要重启生效。
5, 备份文件: \windows\system32\termsrv.dll.backup.(如果想还原设置 请将备份文件改名为termsrv.dll替换破解的文件即可)
远程桌面的其它可能的设置:
运行gpedit.msc打开组策略,计算机配置-管理模板-Windows组件-远程桌面服务-远程桌面会话主机-连接-“限制连接数量”,如果将状态设置为“禁用”或“未配置”,则在“组策略”级别上不强制限制连接的数量。
在Windows 2003系统上的远程桌面实际上就是终端服务,虽然远程桌面最初在Windows XP上就已经存在,但由于Windows XP的远程桌面功能,只能提供一个用户使用计算机,因此使用率并不高。而Windows 2003提供的远程桌面功能则可供多用户同时使用,在其上可以运行程序、保存文件和使用网络资源,在很多方面可以像使用终端一样,并且在管理及配置方面比原来的终端服务更方便。要更好地发挥远程桌面的作用就要对远程桌面进行相应的配置。 www.2cto.com
组策略编译器(gpedit.msc)配置
使用组策略编译器配置用户远程连接数以及用户会话数,
1,“开始”—>“运行”输入gpedit.msc回车打开组策略编译器->“计算机配置”->“管理模板”->“
windows组件”->“终端服务”,右侧鼠标右键选择“限制连接数”打开属性,选择“设置”—>选择“已启用”, “TS 允许的最大连接数”填写你所需要的数量,例如:20。确定完成最大连接数限制设置。双击“会话”->选择“为断开的会话设置时间限制”右键选择属性-》“设置”->xuanze选择“已启用”-》“结束断开连接会话”填写合适的时间,五分钟为好。
终端服务配置(Tscc.msc)的使用
使用终端服务配置可以更改本地计算机上该连接的属性、添加新连接或设置服务器。打开“控制面板”—〉“管理工具”,单击“终端服务器配置”启动终端服务配置窗口。
1 单击左边窗口的“连接”项,右边窗口即出现可选的RDP-TCP连接,右击“RDP-TCP”,选“属性”出现RDP-Tcp属性对话框,主要配置有:
(1)连接数设置:可在“网卡”选项中更改。设置更多地连接数可使更多的用户同时登录服务器。默认最多同时两个用户连接,如果想要使3个以上的用户同时使用远程桌面功能,则必须安装终端服务,安装后就可以任意设定用户数制。 www.2cto.com
安装终端服务可通过Windows的“添加/删除程序”—〉“添加/删除Windows组件”中,选中“终端服务器”来添加,根据需要完成相应配置,完成终端服务安装,重启机器生效。
由于每个用户连接远程桌面后最小占用12MB左右的内存,因此可根据服务器内存大小来设定用户数,一般用户数不要太多,以免影响性能。如256MB内存可设定用户数8个左右,512MB内存可设定20~30个。
(2)调整颜色分辨率(颜色深度):在“客户端设置”项中。限制颜色深度可以增强连接性能,尤其是对于慢速链接,并且还可以减轻服务器负载。“远程桌面”连接的当前默认最大颜色深度设置为 16 位。
选中“颜色深度最大值”,可修改限定的最大颜色深度为8、15、16或24位。若不选中,则使用登录的客户端颜色设置。
(3)让客户自动登录:在“登录设置”选项卡上。这对普通应用非常方便,可加快登录速度,提高服务效率。
要使用自动登录,需选中“总是使用下列登录信息”,在“用户名”中,键入允许自动登录到服务器的用户的名称,在“密码”和“确认密码”中,键入该用户的密码。 这样客户端连接时将不用再输入用户名和密码,而自动进入Windows 2003桌面(注意:若此后再有用户登录,那么原来的连接将被断开)。若输入不完整,则登录时还会要求输入用户名或密码。
如要想更安全的使用服务器,则应选中“总是提示密码”以指定该用户在登录到服务器之前始终要被提示输入密码,从而限制客户端的自动登录。
(4)对连接自动限制管理:单击“会话”项来设定。主要用来设定超时的限制,以便释放会话所占用的资源,“结束已断开的会话”和“空闲会话限制”的时间,一般应用设为5分钟较好。对安全性要求高的也可设定“活动会话限制”的时间。“达到会话限制或者连接被中断时”下的选项,最好选“结束会话”,这样连接所占的资源就会被释放。
(5)设置加密级别:单击“常规”项,可指定在终端服务会话期间,对于客户端与远程计算机之间发送的所有数据是否强制加密级别。分四个级别:符合 FIPS(最高级别的加密)、高(加密数据经过强 128 位加密。)、客户端兼容(加密数据经过客户端支持的最大密钥强度加密)和低(从服务器发送到客户端的数据将不会被加密)。
(6)启用终端客户音频:在“客户端设置”项下边,默认为禁用,以节约服务器资源。当用户少时 ,单击“音频映射”去掉被禁用的选项,使终端客户能使用多媒体设备。当然,客户端计算机也必须装有声卡。 www.2cto.com
如果有多个用户连接到相同的服务器,则会以同一个用户名登录。
(7)启用驱动器映射;此项可方便终端与服务器磁盘间文件的相互传送。启用后本地驱动器将作为网络驱动器显示在终端中。
同样还有打印机、剪贴板、com端口等也可设置映射。但每设置一个都要占用一定的系统资源;所以,一般用户最好禁用。
(8)服务器的安全设置:在“权限”项,可选择组或用户,限制其对终端的配置权限。另外,由于只有Administrators 和 Remote Desktop Users 组的成员可以使用终端服务连接与远程计算机连接,所以可对不同用户分组管理,对于要求安全性高的,可利用NTFS分区设置不同用户的权限。
“服务器设置”—》“限制每个用户使用一个会话”右键选择属性,去除“限制每个用户使用一个会话”的勾选,确认完成设置。
整个多用户的远程连接设置到此结束。
在远程管理方面,Windows Server 2003系统一个最明显的进步就是增加了“远程桌面”功能。这样一来,从Windows 2000保留下来的终端服务似乎就显得有点多余了。然而情况并不是这样,因为在不安装“终端服务器”的前提下,“远程桌面”功能的可管理性比较有限。搭建终端服务器以后,对Windows 2000 Server和Windows Server 2003系统的远程管理操作将更加灵活。
在Windows Server 2003(SP1)中默认没有安装终端服务器组件,用户需要手动添加该组件。安装终端服务组件的步骤如下所述:
步骤/方法
第1步,在开始菜单中依次单击“控制面板”→“添加或删除程序”菜单项,打开“添加或删除程序”窗口。然后单击“添加/删除Windows组件”按钮,打开“Windows组件向导”对话框。在“组件”列表中选中“终端服务器”复选框,如图2008112107所示。
图2008112107 选中“终端服务器”复选框
第2步,打开“配置警告”对话框,提示用户关于IE安全配置方面的信息。因为配置终端服务器的目的主要是为了远程管理Windows Server 2003服务器,对于浏览Internet方面的要求并不高,因此直接单击“是”按钮。返回“Windows组件”对话框,选中“终端服务器授权”复选框,并单击“下一步”→“下一步”按钮即可,如图2008112108所示。
图2008112108 “配置警告”对话框
第3步,在打开的为应用程序兼容性选择默认权限对话框中列出两种安装模式,即“完整安全模式”和“宽松安全模式”。选择不同的模式会应用到Windows Server 2003系统的不同安全级别。选中“完整安全模式”单选框,并单击“下一步”按钮,如图2008112109所示。
图2008112109 选中“完整安全模式”单选框
第4步,打开指定终端服务器许可证服务器对话框,提示用户该终端服务器必须在120天内与Windows Server 2003终端服务器许可证服务器连接才能保证正常使用。由于在“Windows组件”对话框中选中了“终端服务器授权”复选框,则意味着这台Windows Server 2003终端服务器将同时作为许可证服务器。因此选中“使用下列许可证服务器”单选框,并在编辑框中输入这台服务器的名称或IP地址。设置完毕单击“下一步”按钮,如图2008112110所示。
图2008112110 输入许可证服务器IP地址
第5步,在打开的终端服务器授权模式对话框中,要求用户指定这台终端服务器使用的授权模式。选中“每设备授权模式”单选框,并单击“下一步”按钮,如图2008112111所示。
图200811211 选中“每设备授权模式”单选框
第6步,打开“终端服务器授权安装程序”对话框,要求用户选择安装许可证服务器数据库的路径。一般可以保持默认路径,并单击“下一步”按钮,如图2008112112所示。
图2008112112 选择许可证服务器数据库路径
第7步,Windows组件向导开始安装终端服务器和终端服务器授权组件,在安装过程中要求提供Windows Server 2003(SP1)系统的安装光盘或指定安装程序路径。完成安装后单击“完成”按钮关闭Windows组件向导,并按照提示重新启动计算机。
package com;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX解析XML,事件驱动
* 只有两种节点
* Element Node元素节点
* Text Node文本节点
*/
public class SaxResolveXML {
public static void main(String[] args){
try {
SaxResolveXML saxResolveXML = new SaxResolveXML();
InputStream inStream = new FileInputStream("D:\\xml.xml");
List<Person> list = saxResolveXML.getList(inStream);
for(Person person : list){
System.out.println(person.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public List<Person> getList(InputStream inStream) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parse = factory.newSAXParser();
SaxResolve saxResolve = new SaxResolve();
parse.parse(inStream, saxResolve);
inStream.close();
return saxResolve.getPerson();
}
private final class SaxResolve extends DefaultHandler {
private List<Person> list = null;
private Person person = null;
private String tag = null;
public List<Person> getPerson(){
return list;
}
//开始文档事件
public void startDocument() throws SAXException {
//初始化
list = new ArrayList<Person>();
}
//开始元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名、属性
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
if("person".equals(qName)){
person = new Person();
person.setId(Integer.parseInt(atts.getValue(0)));
}
tag = qName;
}
//触发文本节点事件 参数说明:整个xml内容的字符串、当前读到文本类型的开始位置、当前读到文本的数据长度
public void characters(char[] ch, int start, int length)
throws SAXException {
if(tag != null){
String data = new String(ch, start, length);
if(tag.equals("name")){
person.setName(data);
}else if(tag.equals("age")){
person.setAge(Integer.parseInt(data));
}
}
}
//结束元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("person".equals(qName)){
list.add(person);
person = null;
//对象设为空
}
tag = null;
}
}
/*//开始文档事件
public void startDocument() throws SAXException {
}
//开始元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名、属性
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
}
//触发文本节点事件 参数说明:整个xml内容的字符串、当前读到文本类型的开始位置、当前读到文本的数据长度
public void characters(char[] ch, int start, int length)
throws SAXException {
}
//结束元素语法事件 参数说明:命名空间、不带命名空间的标签名、含有命名空间前缀的标签名
public void endElement(String uri, String localName, String qName)
throws SAXException {
}
public void endDocument() throws SAXException {
}
public void endPrefixMapping(String prefix) throws SAXException {
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
}
public void processingInstruction(String target, String data)
throws SAXException {
}
public void setDocumentLocator(Locator locator) {
}
public void skippedEntity(String name) throws SAXException {
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
}*/
}
xml文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="1">
<name>liming</name>
<age>23</age>
</person>
<person id="2">
<name>lixiangmei</name>
<age>24</age>
</person>
</persons>
export LD_LIBRARY_PATH=/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/runtime/glnx86:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/os/glnx86:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386/native_threads:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386/server:/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/sys/java/jre/glnx86/jre/lib/i386
export XAPPLRESDIR=/usr/local/MATLAB/MATLAB_Compiler_Runtime/v716/X11/app-defaults
把以上两行加入系统的环境变量里面:具体操作如下:
vi /etc/profile
按 i 就可以编辑这个文件,开始复制
把上面两行拷贝到这个文件的最下面然后保存就可以了!
保存退出时先按一下“ESC”,然后再按“:wq”就可以保存退出了!
/**
* 从数据库中查询IRI和KLO模型的数据,并下载到本地
* @param dataTime 时次
* @param outIRIFilePath IRI文件下载到本地的路径
* @param outKLOFilePath KLO文件下载到本地的路径
* @param outAnaFilePath 插值文件下载到本地的路径
*/
@SuppressWarnings("static-access")
public static void selectBlogInfo(String dataTime, String outIRIFilePath, String outKLOFilePath, String outAnaFilePath) {
try {
Connection con = DBConnectionManager.getInstance().getConnection();
Statement st = con.createStatement();
String sql = "select * from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24')";
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
Blob blod = rs.getBlob("IRIDATA");
InputStream reader = blod.getBinaryStream();
dataTime = dataTime.replaceAll("-", "");
dataTime = dataTime.replaceAll(" ", "");
String iriFilePath = outIRIFilePath+"\\"+dataTime+"0000.iri.grd";
File file = new File(iriFilePath);
OutputStream writer;
writer = new BufferedOutputStream(new FileOutputStream(file));
byte buf[] = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
blod = rs.getBlob("IRIDATA");
reader = blod.getBinaryStream();
String kloFilePath = outKLOFilePath+"\\"+dataTime+"0000.klo.grd";
file = new File(kloFilePath);
writer = new BufferedOutputStream(new FileOutputStream(file));
buf = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
blod = rs.getBlob("ANADATA");
reader = blod.getBinaryStream();
String anaFilePath = outAnaFilePath+"\\"+dataTime+"0000.grd";
file = new File(anaFilePath);
writer = new BufferedOutputStream(new FileOutputStream(file));
buf = new byte[1024];
for (int i = 0; (i = reader.read(buf)) > 0;) {
writer.write(buf, 0, i);
}
writer.close();
reader.close();
}
DBConnectionManager.closeConnection();
if(con!=null){con.close();}
if(st!=null){st.close();}
if(rs!=null){rs.close();}
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 把IRI和KLO模型的文件上传到数据库中
* @param dataTime 时次
* @param iriFilePath 要上传IRI文件的绝对路径
* @param kloFilePath 要上传KLO文件的据对路径
* @param ANAFilePath 要上传插值文件的据对路径
*/
@SuppressWarnings("static-access")
public static void insertBlogInfo(String dataTime, String IRIFilePath, String KLOFilePath, String ANAFilePath) {
try {
Connection con = DBConnectionManager.getInstance().getConnection();
// 处理事务
boolean defaultCommit;
defaultCommit = con.getAutoCommit();
con.setAutoCommit(false);
Statement st = con.createStatement();
String sql = "select * from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24')";
ResultSet rs = st.executeQuery(sql);
if(rs.next()){
System.out.println(dataTime+"时次已经入库!");
return ;
}
// 插入一个空对象
sql = "insert into MODELTEC(ID, DATATIME, IRIDATA, KLODATA, ANADATA) values(" +
"SEQU_MODEL_ID.nextval, " +
"to_date('"+dataTime+"','YYYY-mm-dd HH24'), " +
"empty_blob(), " +
"empty_blob(), " +
"empty_blob())";
st.executeUpdate(sql);
// 用for update方式锁定数据行
sql = "select IRIDATA,KLODATA,ANADATA from MODELTEC where DATATIME=to_date('"+dataTime+"', 'YYYY-mm-dd HH24') for update";
rs = st.executeQuery(sql);
if (rs.next()) {
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
BLOB blob = (BLOB) rs.getBlob("IRIDATA");
// 到数据库的输出流
OutputStream outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
InputStream fin = new FileInputStream(new File(IRIFilePath));
// 将输入流写到输出流
byte[] b = new byte[blob.getBufferSize()];
int len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
blob = (BLOB) rs.getBlob("KLODATA");
// 到数据库的输出流
outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
fin = new FileInputStream(new File(IRIFilePath));
// 将输入流写到输出流
b = new byte[blob.getBufferSize()];
len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
// 得到java.sql.Blob对象,然后Cast为oracle.sql.BLOB
blob = (BLOB) rs.getBlob("ANADATA");
// 到数据库的输出流
outStream = blob.getBinaryOutputStream();
// 这里用一个文件模拟输入流
fin = new FileInputStream(new File(ANAFilePath));
// 将输入流写到输出流
b = new byte[blob.getBufferSize()];
len = 0;
while ((len = fin.read(b)) != -1) {
outStream.write(b, 0, len);
}
// 依次关闭(注意顺序)
fin.close();
outStream.flush();
outStream.close();
con.commit();
/* 恢复原提交状态 */
con.setAutoCommit(defaultCommit);
DBConnectionManager.closeConnection();
if(con!=null){con.close();}
if(st!=null){st.close();}
if(rs!=null){rs.close();}
}
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
// date类型转换为String类型
// formatType格式为yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 HH时mm分ss秒
// data Date类型的时间
public static String dateToString(Date data, String formatType) {
return new SimpleDateFormat(formatType).format(data);
}
// long类型转换为String类型
// currentTime要转换的long类型的时间
// formatType要转换的string类型的时间格式
public static String longToString(long currentTime, String formatType)
throws ParseException {
Date date = longToDate(currentTime, formatType); // long类型转成Date类型
String strTime = dateToString(date, formatType); // date类型转成String
return strTime;
}
// string类型转换为date类型
// strTime要转换的string类型的时间,formatType要转换的格式yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日
// HH时mm分ss秒,
// strTime的时间格式必须要与formatType的时间格式相同
public static Date stringToDate(String strTime, String formatType)
throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat(formatType);
Date date = null;
date = formatter.parse(strTime);
return date;
}
// long转换为Date类型
// currentTime要转换的long类型的时间
// formatType要转换的时间格式yyyy-MM-dd HH:mm:ss//yyyy年MM月dd日 HH时mm分ss秒
public static Date longToDate(long currentTime, String formatType)
throws ParseException {
Date dateOld = new Date(currentTime); // 根据long类型的毫秒数生命一个date类型的时间
String sDateTime = dateToString(dateOld, formatType); // 把date类型的时间转换为string
Date date = stringToDate(sDateTime, formatType); // 把String类型转换为Date类型
return date;
}
// string类型转换为long类型
// strTime要转换的String类型的时间
// formatType时间格式
// strTime的时间格式和formatType的时间格式必须相同
public static long stringToLong(String strTime, String formatType)
throws ParseException {
Date date = stringToDate(strTime, formatType); // String类型转成date类型
if (date == null) {
return 0;
} else {
long currentTime = dateToLong(date); // date类型转成long类型
return currentTime;
}
}
// date类型转换为long类型
// date要转换的date类型的时间
public static long dateToLong(Date date) {
return date.getTime();
}
1、新建用户
useradd 用户名(gpsin) -g 当前登录用户(root) -d 根目录(/home/weiss) -s /sbin/nologin(不是用于登录)
passwd 用户名(为该用户创建密码)
2、删除用户
userdel 用户名(gpsin)
3、修改用户根目录
usermod -d 新目录(/home/wei) 用户名(gpsin)
window:需要两个文件
一个要执行的bat文件 test.bat
文件内容:ftp -n -s:C:\\config.txt 127.0.0.1
另一个操作ftp的命令文件 config.txt
文件内容:
user user
pass
ls
put ......
get ......
bye
linux:只需要一个文件即可也就是sh文件
test.sh
文件内容:ftp -i -n 127.0.0.1
user user pass
bin
ls
put ......
get ......
bye
ftp -nv 127.0.0.1 <<EOF
user user pass
bin
prompt
lcd /home
put ......
get ......
quit
package db;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DBPool {
private ComboPooledDataSource dataSource;
public static Connection con;
public DBPool() {
try {
dataSource = new ComboPooledDataSource();
dataSource.setUser("test");
dataSource.setPassword("test");
dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:orcl");
dataSource.setDriverClass("oracle.jdbc.driver.OracleDriver");
dataSource.setInitialPoolSize(2);
dataSource.setMinPoolSize(1);
dataSource.setMaxPoolSize(10);
dataSource.setMaxStatements(50);
dataSource.setMaxIdleTime(60);
dataSource.setAcquireRetryAttempts(3);
} catch (PropertyVetoException e) {
}
}
public final static DBPool getInstance() {
return new DBPool();
}
public final Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
return null;
}
}
//测试方法
public static void main(String[] args) throws SQLException {
con = DBPool.getInstance().getConnection();
System.out.println(con);
try {
if (con != null){con.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
} //初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 initialPoolSize
cpds.setInitialPoolSize(initialPoolSize);
//连接池中保留的最大连接数。Default: 15 maxPoolSize
cpds.setMaxPoolSize(maxPoolSize);
//连接池中保留的最小连接数。
cpds.setMinPoolSize(minPoolSize);
//获得连接的最大等待毫秒数。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(acquireRetryDelay);
//最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 maxIdleTime
cpds.setMaxIdleTime(maxIdleTime);
//当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 acquireIncrement
//cpds.setAcquireIncrement(3);
//每60秒检查所有连接池中的空闲连接。Default: 0 idleConnectionTestPeriod
//cpds.setIdleConnectionTestPeriod(60);
//连接关闭时默认将所有未提交的操作回滚。Default: false autoCommitOnClose
//cpds.setAutoCommitOnClose(true);
//JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
//cpds.setMaxStatements(1);
//maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数
//cpds.setMaxStatementsPerConnection(100);
//定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:测试的表必须在初始数据源的时候就存在。Default: null preferredTestQuery
//cpds.setPreferredTestQuery("select sysdate from dual");
// 因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
// 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
// 等方法来提升连接测试的性能。Default: false testConnectionOnCheckout
//cpds.setTestConnectionOnCheckout(true);
//如果设为true那么在取得连接的同时将校验连接的有效性。Default: false testConnectionOnCheckin
//cpds.setTestConnectionOnCheckin(true);
//定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 acquireRetryAttempts
//cpds.setAcquireRetryAttempts(30);
//获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
//保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
//获取连接失败后该数据源将申明已断开并永久关闭。Default: false breakAfterAcquireFailure
//cpds.setBreakAfterAcquireFailure(false);
//两次连接中间隔时间,单位毫秒。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(60000);
java.lang.AbstractMethodError: oracle.jdbc.driver.OracleResultSetImpl.getClob(异常解决办法
最近遇到了一个头痛的问题,可能大家也遇到过。经过多番的询问与查找,终于知道问题原因的所在:异常内容如下:
java.lang.AbstractMethodError: oracle.jdbc.driver.OracleResultSetImpl.getClob(Ljava/lang/String;)Ljava/sql/Clob;
问题原因:Oracle驱动版本不对
解决办法:在Oracle服务器上找到这个驱动,然后cp到Apache的lib目录下,并同是修改环境变量classpath,保证这个lib/classes12.jar在最前面;修改完后,重新启动服务,问题就可以解决。
(ojdbc14.jar在classes12.jar前面)
useradd gpsin -g root -d /inraw -s /sbin/nologin #该用户仅用来支持FTP服务,因此不必让他登录系统
gpsin是ftp登录的用户名,root指定哪个用户可以使用该ftp用户,-d /inraw 指定ftp的根目录,-s /sbin/nologin不用于登录
passwd gpsin 给gpsin用户设置密码
1.下载
rarlinux-3.7.1.tar.zip
#unzip rarlinux-3.7.1.tar.zip
#cd rar
#make
#make install
运行 rar --help 可以看到帮助信息,如果出现下列信息:
#rar: /lib/tls/libc.so.6: version `GLIBC_2.4' not found (required by rar)
#rar: /lib/tls/libc.so.6: version `GLIBC_2.7' not found (required by rar)
则执行:
#cp -f rar_static /usr/local/bin/rar
这样就可以使用rar 命令了。
一、卸载jdk1.4
由于Redhat Enterprise Linux 5.6 中自带安装了jdk1.4.2的,所以在安装jdk1.6前我把jdk1.4.2的卸了,步骤如下:
1、打开终端输入 yum remove java
终端显示 Is this ok [y/N]:
输入y ,按回车。
终端显示 Complete! 此时jdk1.4已被卸了。
二、安装jdk1.6
1.下载:jdk-1_5_0_06-linux-i586-rpm.bin
地址:http://java.sun.com/j2se/1.5.0/download.jsp
2.给文件加上可执行权限
[root@esprit java]# chmod +x jdk-1_5_0_06-linux-i586-rpm.bin
chmod +x jdk-6u31-linux-i586-rpm.bin
3.执行jdk-1_5_0_06-linux-i586-rpm.bin
[root@esprit java]# ./jdk-1_5_0_06-linux-i586-rpm.bin
./jdk-6u31-linux-i586-rpm.bin
执行后生成jdk-6u31-linux-i586.rpm
4.安装jdk-6u31-linux-i586.rpm
rpm -ivh jdk-6u31-linux-i586.rpm
########################################### [100%]
package jdk-1.6.0_31-fcs is already installed
这里我jdk安装在/usr/java目录下
三、配置java环境变量
环境变量配置有三种方法(分别是:修改/etc/profile文件,修改用户目录下的.bashrc文件,直接在shell下修改)
这里我只讲我用到的修改/etc/profile文件
[root@esprit java]# vi /etc/profile
打开文件后,按 I 键,在文件后添加:
JAVA_HOME =/ usr / java / jdk1.6.0_31
PATH = $JAVA_HOME / bin:$PATH
CLASSPATH = .:$JAVA_HOME / lib / tools.jar:$JAVA_HOME / lib / dt.jar:$JAVA_HOME/lib
export JAVA_HOME PATH CLASSPATH
按esc 键
输入:wq 保存退出。
重新登入
四、检查jdk是否装好
在命令行输入: java -version
如果显示版本信息,表示已经安装配置成功
五、卸载jdk1.6
输入 rpm -qa|grep jdk
显示 jdk-1.6.0_24-fcs
卸载 rpm -e –nodeps jdk-1.6.0_24-fcs
package com.ky.ui.util;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import javax.imageio.ImageIO;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
/**
Email:
上午11:18:19
*/
public final class ImgRead{
// public final static String getPressImgPath(){
// return ApplicationContext.getRealPath("/template/data/util/shuiyin.gif");
// }
/** *//**
* 把图片印刷到图片上
* @param pressImg -- 水印文件
* @param targetImg -- 目标文件
* @param x
* @param y
*/
public final static void pressImage(String pressImg, String targetImg, int x, int y){
try {
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// 水印文件
File _filebiao = new File(pressImg);
Image src_biao = ImageIO.read(_filebiao);
int wideth_biao = src_biao.getWidth(null);
int height_biao = src_biao.getHeight(null);
g.drawImage(src_biao, wideth - wideth_biao - x, height - height_biao -y, wideth_biao,
height_biao, null);
// /
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
e.printStackTrace();
}
}
/** *//**
* 打印文字水印图片
* @param pressText --文字
* @param targetImg -- 目标图片
* @param fontName -- 字体名
* @param fontStyle -- 字体样式
* @param color -- 字体颜色
* @param fontSize -- 字体大小
* @param x -- 偏移量
* @param y
*/
public static void pressText(String pressText, String targetImg, String fontName,int fontStyle, int color, int fontSize, int x, int y){
try{
File _file = new File(targetImg);
Image src = ImageIO.read(_file);
int wideth = src.getWidth(null);
int height = src.getHeight(null);
BufferedImage image = new BufferedImage(wideth, height,
BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
g.drawImage(src, 0, 0, wideth, height, null);
// String s="www.qhd.com.cn";
g.setColor(Color.RED);
g.setFont(new Font(fontName, fontStyle, fontSize));
g.drawString(pressText, wideth - fontSize - x, height - fontSize/2 - y);
g.dispose();
FileOutputStream out = new FileOutputStream(targetImg);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
} catch (Exception e){
System.out.println(e);
}
}
public static void main(String[] args){
pressImage("C:/foot_05.gif", "c:/Chart.jpg", 20 ,20);
}
}
// 获取屏幕的边界
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
// 获取底部任务栏高度
int taskBarHeight = screenInsets.bottom;
1、 下载vsftpd
# wget ftp://vsftpd.beasts.org/users/cevans/vsftpd-2.3.2.tar.gz
2、 解压、安装vsftpd
# tar xvfz vsftpd-2.3.2.tar.gz
# cd vsftpd-2.3.2
# make
make命令成功执行后,您将看到vsftpd文件获得当前目录中创建。
# ls -l vsftpd
3、 安装 vsftpd d到 Linux
# make install
在make install,确保vsftpd文件复制到/ usr / local / sbin目录。
# ls -l /usr/local/sbin/vsftpd
4、 复制vsftpd手册页到/usr/share/man/man8,man5
# cp vsftpd.8 /usr/share/man/man8/
# cp vsftpd.conf.5 /usr/share/man/man5/
5、 拷贝vsftpd.cond配置文件
# cp vsftpd.conf /etc
6、 设置Anonymouse FTP访问vsftpd
# mkdir /var/ftp/
# chown root.root /var/ftp
# chmod og-w /var/ftp
ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
在这个阶段,如果你试图登录与任何其他账户(除了匿名,和ftp),它就会失败,如下所示
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
530 This FTP server is anonymous only.
Login failed.
ftp>
7、 允许LINIX登录使用vsftp
# cp RedHat/vsftpd.pam /etc/pam.d/ftp
#local_enable=YES
# ftp localhost
Connected to dotcom.
220 (vsFTPd 2.3.2)
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (localhost:root): ramesh
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
切记再每次修改完vsftpd.conf文件之后要重启一下vsftpd
# ps -ef | grep vsftpd
# kill -9 {vsftpd-pid}
# /usr/local/sbin/vsftpd &
如果还不能登录成功,那么要关闭系统其他的ftp服务和防火墙
Service xinetd stop
Service iptables stop
摘要: 各种排序算法:冒择路(入)兮(稀)快归堆,桶式排序,基数排序 冒泡排序,选择排序,插入排序,稀尔排序,快速排序,归并排序,堆排序,桶式排序,基数排序 一、冒泡排序(BubbleSort) 1. 基本思想: 两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。 2. 排序过程: 设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气...
阅读全文
摘要: Java反射机制是Java语言被视为准动态语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
也许你使用Java已经很长时间了,可是几乎不会用到Java反射机制。你会嗤之以鼻地告诉我,Java反射机制没啥用...
阅读全文
1.使用mysqladmin修改mysql密码
C:\>mysqladmin -udbuser -p password newpassEnter password: oldpass当然用此命令的前提是你把mysql加入了环境变量,如果没有加入环境变量的话那只能在命令行下cd到mysqladmin所在的目录下与此那个次命令了!
-----------------------------------------
2.重置root密码
方法一:
在my.ini的[mysqld]字段加入:
skip-grant-tables
重启mysql服务,这时的mysql不需要密码即可登录数据库
然后进入mysql
mysql>use mysql;mysql>update user set password=password('新密码') WHERE User='root'; mysql>flush privileges;运行之后最后去掉my.ini中的skip-grant-tables,重启mysqld即可。
修改mysql密码方法二:
不使用修改my.ini重启服务的方法,通过非服务方式加skip-grant-tables运行mysql来修改mysql密码
停止mysql服务
打开命令行窗口,在bin目录下使用mysqld-nt.exe启动,即在命令行窗口执行: mysqld-nt --skip-grant-tables
然后另外打开一个命令行窗口,登录mysql,此时无需输入mysql密码即可进入。
按以上方法修改好密码后,关闭命令行运行mysql的那个窗口,此时即关闭了mysql,如果发现mysql仍在运行的话可以结束掉对应进程来关闭。
启动mysql服务
-----------------------------------------
记住此方法,走遍天下无mysql密码
先假设一个ftp地址 用户名 密码
FTP Server: home4u.at.china.com
User: yepanghuang
Password: abc123
打开windows的开始菜单,执行“运行”命令,在对话框中输入ftp,按下“确定”按钮将会切换至DOS窗口,出现命令提示符
ftp>键入命令连接FTP服务器
:
ftp> open home4u.at.china.com (回车)
稍等片刻,屏幕提示连接成功:
ftp> connected to home4u.china.com
接下来服务器询问用户名和口令,分别输入yepanghuang和abc123,待认证通过即可。
windows下ftp上传文件:
比如要把 D:\index.html上传至服务器的根目录中,可以键入:
ftp> put D:\index.html (回车)
当屏幕提示你已经传输完毕,可以键入相关命令查看:
ftp> dir (回车)
windows下ftp上传下载:
假设要把服务器\images目录中的所有.jpg文件下载至本机中,可以输入指令:
ftp> cd images(回车) [注:进入\images目录]
ftp> mget *.jpg
windows下ftp上传与下载工作完毕,键入bye中断连接。
ftp> bye(回车)
下面是一些常用的FTP命令:
1. open:与服务器相连接;
2. send(put):上传文件;
3. get:下载文件;
4. mget:下载多个文件;
5. cd:切换目录;
6. dir:查看当前目录下的文件;
7. del:删除文件;
8. bye:中断与服务器的连接。
如果想了解更多,可以键入
ftp> help (回车)
查看命令集:
ascii: 设定以ASCII方式传送文件(缺省值)
bell: 每完成一次文件传送,报警提示
binary: 设定以二进制方式传送文件
bye: 终止主机FTP进程,并退出FTP管理方式
case: 当为ON时,用MGET命令拷贝的文件名到本地机器中,全部转换为小写字母
cd: 同UNIX的CD命令
cdup: 返回上一级目录
chmod: 改变远端主机的文件权限
close: 终止远端的FTP进程,返回到FTP命令状态,所有的宏定义都被删除
delete: 删除远端主机中的文件
dir [remote-directory] [local-file]: 列出当前远端主机目录中的文件.如果有本地文件,就将结果写至本地文件
get [remote-file] [local-file]: 从远端主机中传送至本地主机中
help [command]: 输出命令的解释
lcd: 改变当前本地主机的工作目录,如果缺省,就转到当前用户的HOME目录
ls [remote-directory] [local-file]: 同DIR
其实在网上也看到过一些文章,介绍如何让java程序以window服务的方式启动。
今天有空,就想用c写一个window服务,在服务启动时来启动一个java程序。
因为在c方面,我十足菜鸟,先到网上搜索了一下关于如何用c写出windows服务,找到一篇介绍的相当详细,参照介绍写了一个window服务。
测试的过程中遇到一个问题,由于我的java程序启动时会在系统托盘显示一个小图标,但通过c写的window服务启运这个java程序后,系统托盘里没有显示小图标。
再搜索,原来:
windows服务程序默认是工作于WinLogon桌面的,服务启动时不会显示GUI界面.可以打开控制面板->服务,查看服务的属性->[登录]-[允许服务与桌面交互],打上钩后,系统托盘就能显示在任务栏。
用C写一个windows服务:
来源:http://www.vckbase.com/document/viewdoc/?id=1474
摘要
Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务。为了学习这种控制台应用程序的基础知识,C(不是C++)是最佳选择。本文将建立并实现一个简单的服务程序,其功能是查询系统中可用物理内存数量,然后将结果写入一个文本文件。最后,你可以用所学知识编写自己的 Windows 服务。
当初我写第一个 NT 服务时,我到 MSDN 上找例子。在那里我找到了一篇 Nigel Thompson 写的文章:“Creating a Simple Win32 Service in C++”,这篇文章附带一个 C++ 例子。虽然这篇文章很好地解释了服务的开发过程,但是,我仍然感觉缺少我需要的重要信息。我想理解通过什么框架,调用什么函数,以及何时调用,但 C++ 在这方面没有让我轻松多少。面向对象的方法固然方便,但由于用类对底层 Win32 函数调用进行了封装,它不利于学习服务程序的基本知识。这就是为什么我觉得 C 更加适合于编写初级服务程序或者实现简单后台任务的服务。在你对服务程序有了充分透彻的理解之后,用 C++ 编写才能游刃有余。当我离开原来的工作岗位,不得不向另一个人转移我的知识的时候,利用我用 C 所写的例子就非常容易解释 NT 服务之所以然。
服务是一个运行在后台并实现勿需用户交互的任务的控制台程序。Windows NT/2000/XP 操作系统提供为服务程序提供专门的支持。人们可以用服务控制面板来配置安装好的服务程序,也就是 Windows 2000/XP 控制面板|管理工具中的“服务”(或在“开始”|“运行”对话框中输入 services.msc /s——译者注)。可以将服务配置成操作系统启动时自动启动,这样你就不必每次再重启系统后还要手动启动服务。
本文将首先解释如何创建一个定期查询可用物理内存并将结果写入某个文本文件的服务。然后指导你完成生成,安装和实现服务的整个过程。
第一步:主函数和全局定义
首先,包含所需的头文件。例子要调用 Win32 函数(windows.h)和磁盘文件写入(stdio.h):
#include <windows.h>
#include <stdio.h>
接着,定义两个常量:
#define SLEEP_TIME 5000
#define LOGFILE "C:\\MyServices\\memstatus.txt"
SLEEP_TIME 指定两次连续查询可用内存之间的毫秒间隔。在第二步中编写服务工作循环的时候要使用该常量。
LOGFILE 定义日志文件的路径,你将会用 WriteToLog 函数将内存查询的结果输出到该文件,WriteToLog 函数定义如下:
int WriteToLog(char* str)
{
FILE* log;
log = fopen(LOGFILE, "a+");
if (log == NULL)
return -1;
fprintf(log, "%s\n", str);
fclose(log);
return 0;
}
声明几个全局变量,以便在程序的多个函数之间共享它们值。此外,做一个函数的前向定义:
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
现在,准备工作已经就绪,你可以开始编码了。服务程序控制台程序的一个子集。因此,开始你可以定义一个 main 函数,它是程序的入口点。对于服务程序来说,main 的代码令人惊讶地简短,因为它只创建分派表并启动控制分派机。
void main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
// 启动服务的控制分派机线程
StartServiceCtrlDispatcher(ServiceTable);
}
一个程序可能包含若干个服务。每一个服务都必须列于专门的分派表中(为此该程序定义了一个 ServiceTable 结构数组)。这个表中的每一项都要在 SERVICE_TABLE_ENTRY 结构之中。它有两个域:
- lpServiceName: 指向表示服务名称字符串的指针;当定义了多个服务时,那么这个域必须指定;
- lpServiceProc: 指向服务主函数的指针(服务入口点);
分派表的最后一项必须是服务名和服务主函数域的 NULL 指针,文本例子程序中只宿主一个服务,所以服务名的定义是可选的。
服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程。当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数。将分派表传递给 StartServiceCtrlDispatcher。这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数(本文例子中只有一个服务)分派器还监视程序中所有服务的执行情况。然后分派器将控制请求从 SCM 传给服务。
注意:如果 StartServiceCtrlDispatcher 函数30秒没有被调用,便会报错,为了避免这种情况,我们必须在 ServiceMain 函数中(参见本文例子)或在非主函数的单独线程中初始化服务分派表。本文所描述的服务不需要防范这样的情况。
分派表中所有的服务执行完之后(例如,用户通过“服务”控制面板程序停止它们),或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。
第二步:ServiceMain 函数
Listing 1 展示了 ServiceMain 的代码。该函数是服务的入口点。它运行在一个单独的线程当中,这个线程是由控制分派器创建的。ServiceMain 应该尽可能早早为服务注册控制处理器。这要通过调用 RegisterServiceCtrlHadler 函数来实现。你要将两个参数传递给此函数:服务名和指向 ControlHandlerfunction 的指针。
它指示控制分派器调用 ControlHandler 函数处理 SCM 控制请求。注册完控制处理器之后,获得状态句柄(hStatus)。通过调用 SetServiceStatus 函数,用 hStatus 向 SCM 报告服务的状态。
Listing 1 展示了如何指定服务特征和其当前状态来初始化 ServiceStatus 结构,ServiceStatus 结构的每个域都有其用途:
- dwServiceType:指示服务类型,创建 Win32 服务。赋值 SERVICE_WIN32;
- dwCurrentState:指定服务的当前状态。因为服务的初始化在这里没有完成,所以这里的状态为 SERVICE_START_PENDING;
- dwControlsAccepted:这个域通知 SCM 服务接受哪个域。本文例子是允许 STOP 和 SHUTDOWN 请求。处理控制请求将在第三步讨论;
- dwWin32ExitCode 和 dwServiceSpecificExitCode:这两个域在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此,它们的值为 0;
- dwCheckPoint 和 dwWaitHint:这两个域表示初始化某个服务进程时要30秒以上。本文例子服务的初始化过程很短,所以这两个域的值都为 0。
调用 SetServiceStatus 函数向 SCM 报告服务的状态时。要提供 hStatus 句柄和 ServiceStatus 结构。注意 ServiceStatus 一个全局变量,所以你可以跨多个函数使用它。ServiceMain 函数中,你给结构的几个域赋值,它们在服务运行的整个过程中都保持不变,比如:dwServiceType。
在报告了服务状态之后,你可以调用 InitService 函数来完成初始化。这个函数只是添加一个说明性字符串到日志文件。如下面代码所示:
// 服务初始化
int InitService()
{
int result;
result = WriteToLog("Monitoring started.");
return(result);
}
在 ServiceMain 中,检查 InitService 函数的返回值。如果初始化有错(因为有可能写日志文件失败),则将服务状态置为终止并退出 ServiceMain:
error = InitService();
if (error)
{
// 初始化失败,终止服务
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
// 退出 ServiceMain
return;
}
如果初始化成功,则向 SCM 报告状态:
// 向 SCM 报告运行状态
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
接着,启动工作循环。每五秒钟查询一个可用物理内存并将结果写入日志文件。
如 Listing 1 所示,循环一直到服务的状态为 SERVICE_RUNNING 或日志文件写入出错为止。状态可能在 ControlHandler 函数响应 SCM 控制请求时修改。
第三步:处理控制请求
在第二步中,你用 ServiceMain 函数注册了控制处理器函数。控制处理器与处理各种 Windows 消息的窗口回调函数非常类似。它检查 SCM 发送了什么请求并采取相应行动。
每次你调用 SetServiceStatus 函数的时候,必须指定服务接收 STOP 和 SHUTDOWN 请求。Listing 2 示范了如何在 ControlHandler 函数中处理它们。
STOP 请求是 SCM 终止服务的时候发送的。例如,如果用户在“服务”控制面板中手动终止服务。SHUTDOWN 请求是关闭机器时,由 SCM 发送给所有运行中服务的请求。两种情况的处理方式相同:
- 写日志文件,监视停止;
- 向 SCM 报告 SERVICE_STOPPED 状态;
由于 ServiceStatus 结构对于整个程序而言为全局量,ServiceStatus 中的工作循环在当前状态改变或服务终止后停止。其它的控制请求如:PAUSE 和 CONTINUE 在本文的例子没有处理。
控制处理器函数必须报告服务状态,即便 SCM 每次发送控制请求的时候状态保持相同。因此,不管响应什么请求,都要调用 SetServiceStatus。
图一 显示 MemoryStatus 服务的服务控制面板
第四步:安装和配置服务
程序编好了,将之编译成 exe 文件。本文例子创建的文件叫 MemoryStatus.exe,将它拷贝到 C:\MyServices 文件夹。为了在机器上安装这个服务,需要用 SC.EXE 可执行文件,它是 Win32 Platform SDK 中附带的一个工具。(译者注:Visaul Studio .NET 2003 IDE 环境中也有这个工具,具体存放位置在:C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\Bin\winnt)。使用这个实用工具可以安装和移除服务。其它控制操作将通过服务控制面板来完成。以下是用命令行安装 MemoryStatus 服务的方法:
sc create MemoryStatus binpath= c:\MyServices\MemoryStatus.exe
发出此创建命令。指定服务名和二进制文件的路径(注意 binpath= 和路径之间的那个空格)。安装成功后,便可以用服务控制面板来控制这个服务(参见图一)。用控制面板的工具栏启动和终止这个服务。
图二 MemoryStatus 服务的属性窗口
MemoryStatus 的启动类型是手动,也就是说根据需要来启动这个服务。右键单击该服务,然后选择上下文菜单中的“属性”菜单项,此时显示该服务的属性窗口。在这里可以修改启动类型以及其它设置。你还可以从“常规”标签中启动/停止服务。以下是从系统中移除服务的方法:
sc delete MemoryStatus
指定 “delete” 选项和服务名。此服务将被标记为删除,下次西通重启后,该服务将被完全移除。
第五步:测试服务
从服务控制面板启动 MemoryStatus 服务。如果初始化不出错,表示启动成功。过一会儿将服务停止。检查一下 C:\MyServices 文件夹中 memstatus.txt 文件的服务输出。在我的机器上输出是这样的:
Monitoring started.
273469440
273379328
273133568
273084416
Monitoring stopped.
为了测试 MemoryStatus 服务在出错情况下的行为,可以将 memstatus.txt 文件设置成只读。这样一来,服务应该无法启动。
去掉只读属性,启动服务,在将文件设成只读。服务将停止执行,因为此时日志文件写入失败。如果你更新服务控制面板的内容,会发现服务状态是已经停止。
开发更大更好的服务程序
理解 Win32 服务的基本概念,使你能更好地用 C++ 来设计包装类。包装类隐藏了对底层 Win32 函数的调用并提供了一种舒适的通用接口。修改 MemoryStatus 程序代码,创建满足自己需要的服务!为了实现比本文例子所示范的更复杂的任务,你可以创建多线程的服务,将作业划分成几个工作者线程并从 ServiceMain 函数中监视它们的执行。
最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了。
下面是参考网络资源总结的一些在Java编程中尽可能要做到的一些地方。
1. 尽量在合适的场合使用单例
使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:
第一,控制资源的使用,通过线程同步来控制资源的并发访问;
第二,控制实例的产生,以达到节约资源的目的;
第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信。
2. 尽量避免随意使用静态变量
要知道,当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如
- public class A{
- static B b = new B();
- }
public class A{ static B b = new B(); }
此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
3. 尽量避免过多过常的创建Java对象
尽量避免在经常调用的方法,循环中new对象,由于系统不仅要花费时间来创建对象,而且还要花时间对这些对象进行垃圾回收和处理,在我们可以控制的范围内,最大限度的重用对象,最好能用基本的数据类型或数组来替代对象。
4. 尽量使用final修饰符
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
5. 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。
6. 尽量处理好包装类型和基本类型两者的使用场所
虽然包装类型和基本类型在使用过程中是可以相互转换,但它们两者所产生的内存区域是完全不同的,基本类型数据产生和处理都在栈中处理,包装类型是对象,是在堆中产生实例。
在集合类对象,有对象方面需要的处理适用包装类型,其他的处理提倡使用基本类型。
7. 慎用synchronized,尽量减小synchronize的方法
都知道,实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。synchronize方法被调用时,直接会把当前对象锁 了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,并且应尽量使用方法同步代替代码块同步。
8. 尽量使用StringBuilder和StringBuffer进行字符串连接
这个就不多讲了。
9. 尽量不要使用finalize方法
实际上,将资源清理放在finalize方法中完成是非常不好的选择,由于GC的工作量很大,尤其是回收Young代内存时,大都会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。
10. 尽量使用基本数据类型代替对象
String str = "hello";
上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
11. 单线程应尽量使用HashMap、ArrayList
HashTable、Vector等使用了同步机制,降低了性能。
12. 尽量合理的创建HashMap
当你要创建一个比较大的hashMap时,充分利用另一个构造函数
public HashMap(int initialCapacity, float loadFactor)
避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。
13. 尽量减少对变量的重复计算
如
for(int i=0;i<list.size();i++)
应该改为
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
14. 尽量避免不必要的创建
如
A a = new A();
if(i==1){list.add(a);}
应该改为
if(i==1){
A a = new A();
15. 尽量在finally块中释放资源
程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。
16. 尽量使用移位来代替'a/b'的操作
"/"是一个代价很高的操作,使用移位的操作将会更快和更有效
如
int num = a / 4;
int num = a / 8;
应该改为
int num = a >> 2;
int num = a >> 3;
但注意的是使用移位应添加注释,因为移位操作不直观,比较难理解
17.尽量使用移位来代替'a*b'的操作
同样的,对于'*'操作,使用移位的操作将会更快和更有效
如
int num = a * 4;
int num = a * 8;
应该改为
int num = a << 2;
18. 尽量确定StringBuffer的容量
StringBuffer 的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再 丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。
如:StringBuffer buffer = new StringBuffer(1000);
19. 尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- }
Public void test(){ Object obj = new Object(); …… Obj=null; }
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
- Public void test(){
- Object obj = new Object();
- ……
- Obj=null;
- //执行耗时,耗内存操作;或调用耗时,耗内存的方法
- ……
- }
Public void test(){ Object obj = new Object(); …… Obj=null; //执行耗时,耗内存操作;或调用耗时,耗内存的方法 …… }
这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。
20. 尽量避免使用二维数组
二维数据占用的内存空间比一维数组多得多,大概10倍以上。
21. 尽量避免使用split
除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需 要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
22. ArrayList & LinkedList
一 个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指 针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好2 者得数据结构,对症下药。
23. 尽量使用System.arraycopy ()代替通过来循环复制数组
System.arraycopy() 要比通过循环来复制数组快的多
24. 尽量缓存经常使用的对象
尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。
25. 尽量避免非常大的内存分配
有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。
26. 慎用异常
当创建一个异常时,需要收集一个栈跟踪(stack track),这个栈跟踪用于描述异常是在何处创建的。构建这些栈跟踪时需要为运行时栈做一份快照,正是这一部分开销很大。当需要创建一个 Exception 时,JVM 不得不说:先别动,我想就您现在的样子存一份快照,所以暂时停止入栈和出栈操作。栈跟踪不只包含运行时栈中的一两个元素,而是包含这个栈中的每一个元素。
如 果您创建一个 Exception ,就得付出代价。好在捕获异常开销不大,因此可以使用 try-catch 将核心内容包起来。从技术上讲,您甚至可以随意地抛出异常,而不用花费很大的代价。招致性能损失的并不是 throw 操作——尽管在没有预先创建异常的情况下就抛出异常是有点不寻常。真正要花代价的是创建异常。幸运的是,好的编程习惯已教会我们,不应该不管三七二十一就 抛出异常。异常是为异常的情况而设计的,使用时也应该牢记这一原则。
相关回复:
xuanyuan 写道
7.慎用synchronized,尽量减小synchronize的方法
re:同意,不过文中有个地方说错了,使用synchronized关键字并不一定都是锁定当前对象的,要看具体的锁是什么。如果是在方法上加的synchronized,则是以对象本身为锁的,如果是静态方法则锁的粒度是类。
---------------
9.尽量不要使用finalize方法
re:同意,其实不推荐用finalize方法的根本原因在于,JVM的规范并不保证何时执行该方法,所以用这个方法来释放资源很不合适,有可能造成长时间资源得不到释放。
---------------
16.尽量使用移位来代替'a/b'的操作;17.尽量使用移位来代替'a*b'的操作
re:个人不太同意这两条。这样做确实有更好的性能,但是却牺牲了可读性。这两个操作符对很多程序员来说并不直观。我认为在如今硬件价格不那么昂贵的情况下,略微牺牲一些性能,换来更好的可读性和可维护性是好的选择。
wuzhengju 写道
19.尽量早释放无用对象的引用
大部分时,方法局部引用变量所引用的对象 会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。
例如:
Public void test(){
Object obj = new Object();
……
Obj=null;
}
上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:
Public void test(){
Object obj = new Object();
……
Obj=null;
//执行耗时,耗内存操作;或调用耗时,耗内存的方法
……
}
如果Object obj = new Object(); 如果这对象并不是大对象,这有必要吗?Obj=null;只是告诉jvm这个对象已经成为垃圾,至于什么时候回收,还不能确定! 这可读性也不好!
下面的代码片段是由经过验证的程序修改而来。观察这些代码片段你会发现,跟以前的版本相比,在Java7里,文件相关的操作变得简单的多了。通过使用新的Files类里提供的各种方法,你可以只用一行代码就能完成下列的文件操作:
这篇文件是以你对Java7里提供的新的Path类很熟悉为前提,如果你不熟悉这个类,这里就简单说一句,Path是文件系统里对位置的一个逻辑概念,例如c:\ 和../foobar.txt都是Path。
创建和删除文件
下面的代码片段向你展示的是用 Files.createFile (Path target) 方法创建文件的基本用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Path file = Files.createFile (target);
很多时候,出于安全的原因,你可能希望在创建的文件上设置一下属性,例如:是否可读/可写/写执行。这些属性依赖于文件系统的种类,你需要使用跟文件系统相应的权限辅助类来完成这种操作。例如,PosixFilePermission和PosixFilePermissions为POSIX文件系统设计的。下面的是在POSIX文件系统上的文件设置读写权限的用法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Set<PosixFilePermission> perms = PosixFilePermissions.fromString ("rw-rw-rw-");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute (perms);
Files.createFile (target, attr);
这个java.nio.file.attribute包里提供了很多关于FilePermission的类。
警告当创建一个带有权限属性的文件时,请注意包含这个文件的文件夹是否有权限的强制约束。例如,你会发现,由于这些限制,尽管你给创建的文件指定了rw-rw-rw权限,实际创建的结果却是rw-r–r–。
删除文件更简单,使用Files.delete (Path)这个方法。
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.delete (target);
拷贝和移动文件
下面的代码向你展示的是使用Files.copy (Path source, Path target)方法做文件拷贝的基本用法。
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.copy (source, target);
经常的,在拷贝文件的过程中你可能希望指定一些操作设置。在Java7里,你可以通过使用StandardCopyOption enum来设置这些属性。下面看一个例子。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
- Files.copy (source, target, REPLACE_EXISTING);
拷贝操作时可以使用的属性还包括COPY_ATTRIBUTES (保留文件属性) 和ATOMIC_MOVE (确保移动事务操作的成功,否则进行回滚)。
移动文件的操作跟拷贝很相似,使用Files.move (Path source, Path target)方法。
同样,你也可以指定移动操作的属性,使用Files.move (Path source, Path target, CopyOptions...) 方法里的参数来设置。
- import static java.nio.file.StandardCopyOption.*;
- Path source = Paths.get ("C:\\My Documents\\Stuff.txt");
- Path target = Paths.get ("D:\\Backup\\MyStuff.txt");
Files.move (source, target, REPLACE_EXISTING,COPY_ATTRIBUTES);
可以看出,新的用于文件操作的NIO.2 API 非常便于使用。
众所周知,随机数是任何一种编程语言最基本的特征之一。而生成随机数的基本方式也是相同的:产生一个0到1之间的随机数。看似简单,但有时我们也会忽略了一些有趣的功能。
我们从书本上学到什么?
最明显的,也是直观的方式,在Java中生成随机数只要简单的调用:
- java.lang.Math.random()
在所有其他语言中,生成随机数就像是使用Math工具类,如abs, pow, floor, sqrt和其他数学函数。大多数人通过书籍、教程和课程来了解这个类。一个简单的例子:从0.0到1.0之间可以生成一个双精度浮点数。那么通过上面的信息,开发人员要产生0.0和10.0之间的双精度浮点数会这样来写:
- Math.random() * 10
而产生0和10之间的整数,则会写成:
- Math.round(Math.random() * 10)
进阶
通过阅读Math.random()的源码,或者干脆利用IDE的自动完成功能,开发人员可以很容易发现,java.lang.Math.random()使用一个内部的随机生成对象 - 一个很强大的对象可以灵活的随机产生:布尔值、所有数字类型,甚至是高斯分布。例如:
- new java.util.Random().nextInt(10)
它有一个缺点,就是它是一个对象。它的方法必须是通过一个实例来调用,这意味着必须先调用它的构造函数。如果在内存充足的情况下,像上面的表达式是可以接受的;但内存不足时,就会带来问题。
一个简单的解决方案,可以避免每次需要生成一个随机数时创建一个新实例,那就是使用一个静态类。猜你可能想到了java.lang.Math,很好,我们就是改良java.lang.Math的初始化。虽然这个工程量低,但你也要做一些简单的单元测试来确保其不会出错。
假设程序需要生成一个随机数来存储,问题就又来了。比如有时需要操作或保护种子(seed),一个内部数用来存储状态和计算下一个随机数。在这些特殊情况下,共用随机生成对象是不合适的。
并发
在Java EE多线程应用程序的环境中,随机生成实例对象仍然可以被存储在类或其他实现类,作为一个静态属性。幸运的是,java.util.Random是线程安全的,所以不存在多个线程调用会破坏种子(seed)的风险。
另一个值得考虑的是多线程java.lang.ThreadLocal的实例。偷懒的做法是通过Java本身API实现单一实例,当然你也可以确保每一个线程都有自己的一个实例对象。
虽然Java没有提供一个很好的方法来管理java.util.Random的单一实例。但是,期待已久的Java 7提供了一种新的方式来产生随机数:
- java.util.concurrent.ThreadLocalRandom.current().nextInt(10)
这个新的API综合了其他两种方法的优点:单一实例/静态访问,就像Math.random()一样灵活。ThreadLocalRandom也比其他任何处理高并发的方法要更快。
经验
Chris Marasti-Georg 指出:
- Math.round(Math.random() * 10)
使分布不平衡,例如:0.0 - 0.499999将四舍五入为0,而0.5至1.499999将四舍五入为1。那么如何使用旧式语法来实现正确的均衡分布,如下:
- Math.floor(Math.random() * 11)
幸运的是,如果我们使用java.util.Random或java.util.concurrent.ThreadLocalRandom就不用担心上述问题了。
Java实战项目里面介绍了一些不正确使用java.util.Random API的危害。这个教训告诉我们不要使用:
- Math.abs(rnd.nextInt())%n
而使用:
- rnd.nextInt(n)
package com.wss;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class GPS_GNSS_XML_Color {
//删除节点时传入的参数
private static String deleteNumber;
//修改节点时传入的参数
private static String updateNumber;
//读取传入的路径,返回一个document对象
public static Document loadInit(String filePath){
Document document = null;
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(new File(filePath));
document.normalize();
return document;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
/**
* 删除制定的xml
* @param filePath
* @return
*/
public static boolean deleteXML(String filePath){
deleteNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
Document document = loadInit(filePath);
try{
NodeList nodeList = document.getElementsByTagName("color");
for(int i=0; i<nodeList.getLength(); i++){
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
//删除节点时传入的参数
if(number_.equals(deleteNumber)){
Node node = nodeList.item(i);
node.getParentNode().removeChild(node);
saveXML(document, filePath);
}
}
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 修改制定的xml
* @param filePath
* @return
*/
public static boolean updateXML(String filePath){
updateNumber = "421f481e-790c-41be-91e3-27d215b73ce2";
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
try{
//获取叶节点
NodeList nodeList = document.getElementsByTagName("color");
//遍历叶节点
for(int i=0; i<nodeList.getLength(); i++){
String number = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
//修改节点时传入的参数
if(number.equals(updateNumber)){
document.getElementsByTagName("colorValue").item(i).getFirstChild().setNodeValue("black");
document.getElementsByTagName("minValue").item(i).getFirstChild().setNodeValue("2222");
document.getElementsByTagName("maxValue").item(i).getFirstChild().setNodeValue("22222");
System.out.println();
}
}
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 添加节点
* @param filePath
* @return
*/
public static boolean addXML(String filePath){
try{
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
//创建叶节点
Element eltColor = document.createElement("color");
Element eltNumber = document.createElement("number");//创建叶节点的第一个元素
Element eltColorValue = document.createElement("colorValue");//创建叶节点的第二个元素
Element eltMinValue = document.createElement("minValue");//创建叶节点的第三个元素
Element eltMaxValue = document.createElement("maxValue");//创建叶节点的第四个元素
Text number_ = document.createTextNode(UUID.randomUUID().toString());//创建叶节点的第一个元素下的文本节点
eltNumber.appendChild(number_);//把该文本节点加入到叶节点的第一个元素里面
Text colorValue_ = document.createTextNode("colorValue");//创建叶节点的第二个元素下的文本节点
eltColorValue.appendChild(colorValue_);//把该文本节点加入到叶节点的第二个元素里面
Text minValue_ = document.createTextNode("100");//创建叶节点的第三个元素下的文本节点
eltMinValue.appendChild(minValue_);//把该文本节点加入到叶节点的第三个元素里面
Text maxValue_ = document.createTextNode("200");//创建叶节点的第四个元素下的文本节点
eltMaxValue.appendChild(maxValue_);//把该文本节点加入到叶节点的第四个元素里面
//把叶节点下的元素加入到叶节点下
eltColor.appendChild(eltNumber);
eltColor.appendChild(eltColorValue);
eltColor.appendChild(eltMinValue);
eltColor.appendChild(eltMaxValue);
//获取根节点
Element eltRoot = document.getDocumentElement();
//把叶节点加入到根节点下
eltRoot.appendChild(eltColor);
//更新修改后的源文件
saveXML(document, filePath);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 把修改后的document写进源文件(更新源文件)
* @param document
* @param filePath
* @return
*/
public static boolean saveXML(Document document, String filePath){
try{
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
return true;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return false;
}
}
/**
* 获取xml文件的所有记录
* @param filePath
* @return
*/
public static List<ColorValue> selectXML(String filePath){
List<ColorValue> colorValueList = new ArrayList<ColorValue>();
try{
//读取传入的路径,返回一个document对象
Document document = loadInit(filePath);
//获取叶节点
NodeList nodeList = document.getElementsByTagName("color");
//遍历叶节点
for(int i=0; i<nodeList.getLength(); i++){
ColorValue colorValue = new ColorValue();
String number_ = document.getElementsByTagName("number").item(i).getFirstChild().getNodeValue();
String colorValue_ = document.getElementsByTagName("colorValue").item(i).getFirstChild().getNodeValue();
Double minValue_ = Double.parseDouble(document.getElementsByTagName("minValue").item(i).getFirstChild().getNodeValue());
Double maxValue_ = Double.parseDouble(document.getElementsByTagName("maxValue").item(i).getFirstChild().getNodeValue());
colorValue.setNumber(number_);
colorValue.setColorValue(colorValue_);
colorValue.setMinValue(minValue_);
colorValue.setMaxValue(maxValue_);
colorValueList.add(colorValue);
}
return colorValueList;
}catch(Exception e){
e.printStackTrace();
System.out.println(e.getMessage());
return null;
}
}
}
package com.wss;
public class ColorValue {
private String number;
private String colorValue;
private Double minValue;
private Double maxValue;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getColorValue() {
return colorValue;
}
public void setColorValue(String colorValue) {
this.colorValue = colorValue;
}
public Double getMinValue() {
return minValue;
}
public void setMinValue(Double minValue) {
this.minValue = minValue;
}
public Double getMaxValue() {
return maxValue;
}
public void setMaxValue(Double maxValue) {
this.maxValue = maxValue;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Colors>
<color>
<number>7007b384-fab3-4779-9171-229d0664b6b5</number>
<colorValue>black</colorValue>
<minValue>2222</minValue>
<maxValue>22222</maxValue>
</color>
<color>
<number>421f481e-790c-41be-91e3-27d215b73ce2</number>
<colorValue>colorValue</colorValue>
<minValue>100</minValue>
<maxValue>200</maxValue>
</color>
</Colors>