2012年4月16日
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=" 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)