|
2007年5月14日
package cc.dynasoft.struts.action;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFFooter;
import org.apache.poi.hssf.usermodel.HSSFHeader;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.Region;
import cc.dynasoft.bean.Department;
///import org.apache.poi.hssf.record.HeaderRecorder;
public class OutputExcel {
public static boolean outputExcel(ExcelArgs args, List title, List list) {
try {
int cellNum = args.getCellNum(); // workbook
int rowNum = args.getRowNum();
/**
* 建立表格設(shè)置。
*/
HSSFWorkbook wb = new HSSFWorkbook(); // create the new Workbook
HSSFSheet sheet = wb.createSheet(args.getSheetName()); // create
/**
* 打印設(shè)置
*/
HSSFPrintSetup hps = sheet.getPrintSetup();
hps.setPaperSize((short) 9); // 設(shè)置A4紙
// hps.setLandscape(true); // 將頁(yè)面設(shè)置為橫向打印模式
sheet.setHorizontallyCenter(true); // 設(shè)置打印頁(yè)面為水平居中
// sheet.setVerticallyCenter(true); // 設(shè)置打印頁(yè)面為垂直居中
wb.setPrintArea(0, "$A$2:$e$" + rowNum + 2);// 打印區(qū)域設(shè)置.
/**
* 設(shè)置表的Footer
*/
HSSFFooter footer = sheet.getFooter();
// 設(shè)置footer的位置和顯示的內(nèi)容
footer.setCenter("Time:" + HSSFFooter.date());
footer.setRight("Page " + HSSFFooter.page() + " of "
+ HSSFFooter.numPages());
/**
* 設(shè)置表的Header
*/
// 設(shè)置header的位置,共有三種位置和相應(yīng)的顯示設(shè)置
HSSFHeader header = sheet.getHeader();
// header.setRight("Center Header");
// header.setLeft("Left Header");
header.setCenter(HSSFHeader.font("Stencil-Normal", "Italic")
+ HSSFHeader.fontSize((short) 30) + args.getHeaderTitle());
// header.endDoubleUnderline();
header.startUnderline();
/**
* 設(shè)置列的寬度
*/
sheet.setColumnWidth((short) 2,
(short) ((30 * 8) / ((double) 1 / 10)));
sheet.setColumnWidth((short) 3,
(short) ((40 * 8) / ((double) 1 / 10)));
sheet.setColumnWidth((short) 4,
(short) ((50 * 8) / ((double) 1 / 20)));
/**
* 創(chuàng)建第一行,也就是顯示的標(biāo)題, 可以高置的高度,單元格的格式,顏色,字體等設(shè)置. 同時(shí)可以合并單元格.
*/
HSSFRow row0 = sheet.createRow(0); // 創(chuàng)建0行
row0.setHeight((short) 0x300); // 設(shè)直行的高度.
HSSFFont font2 = wb.createFont(); // 創(chuàng)建字體格式
font2.setColor(HSSFFont.SS_NONE); // 設(shè)置單元格字體的顏色.
font2.setFontHeight((short) 700); // 設(shè)置字體大小
font2.setFontName("Courier New"); // 設(shè)置單元格字體
HSSFCell cell0 = row0.createCell((short) 0); // 創(chuàng)建0行0列.
HSSFCellStyle style3 = wb.createCellStyle(); // 創(chuàng)建單元格風(fēng)格.
style3.setAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
style3.setAlignment(HSSFCellStyle.ALIGN_CENTER); // /水平居中
style3.setFont(font2); // 將字體格式加入到單元格風(fēng)格當(dāng)中
// cell0.setCellType()
cell0.setCellStyle(style3); // 設(shè)置單元格的風(fēng)格.
cell0.setCellValue(args.getHeaderTitle()); // 設(shè)置單元的內(nèi)容.
sheet.addMergedRegion(new Region(0, (short) 0, 0,
(short) (cellNum - 1)));// 指定合并區(qū)域,前二個(gè)參數(shù)為開(kāi)始處X,Y坐標(biāo).后二個(gè)為結(jié)束的坐標(biāo).
/**
* 設(shè)置其它數(shù)據(jù) 設(shè)置風(fēng)格
*/
HSSFCellStyle style = wb.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 設(shè)置單無(wú)格的邊框?yàn)榇煮w
style.setBottomBorderColor(HSSFColor.BLACK.index); // 設(shè)置單元格的邊框顏色.
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setLeftBorderColor(HSSFColor.BLACK.index);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setRightBorderColor(HSSFColor.BLACK.index);
style.setBorderTop(HSSFCellStyle.BORDER_THIN);
style.setTopBorderColor(HSSFColor.BLACK.index);
// style.setWrapText(true);//文本區(qū)域隨內(nèi)容多少自動(dòng)調(diào)整
// style.setFillForegroundColor(HSSFColor.LIME.index);
// style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
/**
* 設(shè)置風(fēng)格1
*/
HSSFCellStyle style1 = wb.createCellStyle();
style1.setBorderBottom(HSSFCellStyle.BORDER_THIN); // 設(shè)置單無(wú)格的邊框?yàn)榇煮w
style1.setBottomBorderColor(HSSFColor.BLACK.index); // 設(shè)置單元格的邊框顏色.
style1.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style1.setLeftBorderColor(HSSFColor.BLACK.index);
style1.setBorderRight(HSSFCellStyle.BORDER_THIN);
style1.setRightBorderColor(HSSFColor.BLACK.index);
style1.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
style1.setTopBorderColor(HSSFColor.BLACK.index);
style1.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);// 最好的設(shè)置Pattern
// 單元格背景的顯示模式.
style1.setFillForegroundColor(new HSSFColor.RED().getIndex()); // 設(shè)置單元格背景色;
style1.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 水平對(duì)齊方式
// style1.setWrapText(true);//文本區(qū)域隨內(nèi)容多少自動(dòng)調(diào)整
// style.setFillPattern(HSSFCellStyle.//);
// 設(shè)置字體Color,首先創(chuàng)建Font對(duì)象,后對(duì)font設(shè)置,然后做為參數(shù)傳給style
HSSFFont font = wb.createFont();
font.setColor(HSSFFont.SS_NONE);
// font.setFontHeightInPoints((short)24);
font.setFontName("Courier New");
// font.setItalic(true);
// font.setStrikeout(true);//給字體加上刪除線
font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
style1.setFont(font);
/**
*
* 設(shè)置第零行表格說(shuō)明行
*
*
*
*/
HSSFRow row1 = sheet.createRow((short) 1);
for (int j = 0; j < cellNum; j++) {
HSSFCell cell = row1.createCell((short) j);
cell.setCellValue((String) title.get(j));
cell.setCellStyle(style1);
}
// style.setFillPattern(HSSFCellStyle.NO_FILL);
/**
* 設(shè)置表的內(nèi)容主體
*/
Iterator iter = list.iterator();
for (int i = 2; iter.hasNext(); i++) {
Department dep = (Department) iter.next();
HSSFRow row = sheet.createRow((short) i);
HSSFCell cell5 = row.createCell((short) 0);
HSSFCell cell1 = row.createCell((short) 1);
HSSFCell cell2 = row.createCell((short) 2);
HSSFCell cell3 = row.createCell((short) 3);
HSSFCell cell4 = row.createCell((short) 4);
cell5.setCellValue(dep.getId());
cell5.setCellStyle(style);
cell1.setCellValue(dep.getParentId());
cell1.setCellStyle(style);
cell2.setCellValue(dep.getName());
cell2.setCellStyle(style);
cell3.setCellValue(dep.getDescription());
cell3.setCellStyle(style);
cell4.setCellValue(dep.getImagePath());
cell4.setCellStyle(style);
}
// Write the output to a file}
// FileOutputStream fileOut = new
// FileOutputStream(args.getPath()+args.getFileName());
/**
* 對(duì)文件進(jìn)行輸出操作。
*/
FileOutputStream fileOut = new FileOutputStream(args
.getPathAndName());
wb.write(fileOut);
// fileOut.close();
} catch (IOException ex) {
ex.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
return true;
}
}
mkdir /home/u1 創(chuàng)建文件夾/home/u1
chown oracle /home/u1 表示改變目錄所有者為oracle賬戶;
chgrp dba /home/u1 改變/home/u1目錄為dba所有;
chmod 755 /home/u1 表示oracle賬戶對(duì)/home/u1目錄有755權(quán)限;
rmdir /home/u1 表示刪除/home/u1目錄
hostname可以查看linux的計(jì)算機(jī)名;
whoami可以查看當(dāng)前用戶;
pwd顯示當(dāng)前路徑;
df查看系統(tǒng)的硬件信息
ls -lrt l表示顯示詳細(xì)列表,-t表示按時(shí)間排序,-r反向排序
cat orcl_ora_3436.trc|grep bucket
以下查看相關(guān)文件內(nèi)容:
more /etc/oratab
cat /etc/passwd
cat /etc/group
copy命令
該命令的功能是將給出的文件或目錄拷貝到另一文件或目錄中,同MSDOS下的copy命令一樣,功能十分強(qiáng)大。
語(yǔ)法: cp [選項(xiàng)] 源文件或目錄 目標(biāo)文件或目錄
說(shuō)明:該命令把指定的源文件復(fù)制到目標(biāo)文件或把多個(gè)源文件復(fù)制到目標(biāo)目錄中。
該命令的各選項(xiàng)含義如下:
- a 該選項(xiàng)通常在拷貝目錄時(shí)使用。它保留鏈接、文件屬性,并遞歸地拷貝目錄,其作用等于dpR選項(xiàng)的組合。
- d 拷貝時(shí)保留鏈接。
- f 刪除已經(jīng)存在的目標(biāo)文件而不提示。
- i 和f選項(xiàng)相反,在覆蓋目標(biāo)文件之前將給出提示要求用戶確認(rèn)。回答y時(shí)目標(biāo)文件將被覆蓋,是交互式拷貝。
- p 此時(shí)cp除復(fù)制源文件的內(nèi)容外,還將把其修改時(shí)間和訪問(wèn)權(quán)限也復(fù)制到新文件中。
- r 若給出的源文件是一目錄文件,此時(shí)cp將遞歸復(fù)制該目錄下所有的子目錄和文件。此時(shí)目標(biāo)文件必須為一個(gè)目錄名。
- l 不作拷貝,只是鏈接文件。
需要說(shuō)明的是,為防止用戶在不經(jīng)意的情況下用cp命令破壞另一個(gè)文件,如用戶指定的目標(biāo)文件名已存在,用cp命令拷貝文件后,這個(gè)文件就會(huì)被新源文件覆蓋,因此,建議用戶在使用cp命令拷貝文件時(shí),最好使用i選項(xiàng)。
對(duì)于rownum來(lái)說(shuō)它是oracle系統(tǒng)順序分配為從查詢返回的行的編號(hào),返回的第一行分配的是1,第二行是2,依此類推,這個(gè)偽字段可以用于限制查詢返回的總行數(shù),而且rownum不能以任何表的名稱作為前綴。
舉例說(shuō)明:
例如表:student(學(xué)生)表,表結(jié)構(gòu)為:
ID char(6) --學(xué)號(hào)
name VARCHAR2(10) --姓名
create table student (ID char(6), name VARCHAR2(100));
insert into sale values('200001',‘張一’);
insert into sale values('200002',‘王二’);
insert into sale values('200003',‘李三’);
insert into sale values('200004',‘趙四’);
commit;
(1) rownum 對(duì)于等于某值的查詢條件
如 果希望找到學(xué)生表中第一條學(xué)生的信息,可以使用rownum=1作為條件。但是想找到學(xué)生表中第二條學(xué)生的信息,使用rownum=2結(jié)果查不到數(shù)據(jù)。因 為rownum都是從1開(kāi)始,但是1以上的自然數(shù)在rownum做等于判斷是時(shí)認(rèn)為都是false條件,所以無(wú)法查到rownum = n(n>1的自然數(shù))。
SQL> select rownum,id,name from student where rownum=1;(可以用在限制返回記錄條數(shù)的地方,保證不出錯(cuò),如:隱式游標(biāo))
SQL> select rownum,id,name from student where rownum=1;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200001 張一
SQL> select rownum,id,name from student where rownum =2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(2)rownum對(duì)于大于某值的查詢條件
如果想找到從第二行記錄以后的記錄,當(dāng)使用rownum>2是查不出記錄的,原因是由于rownum是一個(gè)總是從1開(kāi)始的偽列,Oracle 認(rèn)為rownum> n(n>1的自然數(shù))這種條件依舊不成立,所以查不到記錄
SQL> select rownum,id,name from student where rownum >2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
那如何才能找到第二行以后的記錄呀。可以使用以下的子查詢方法來(lái)解決。注意子查詢中的rownum必須要有別名,否則還是不會(huì)查出記錄來(lái),這是因?yàn)閞ownum不是某個(gè)表的列,如果不起別名的話,無(wú)法知道rownum是子查詢的列還是主查詢的列。
SQL>select * from(select rownum no ,id,name from student) where no>2;
NO ID NAME
---------- ------ ---------------------------------------------------
3 200003 李三
4 200004 趙四
SQL> select * from(select rownum,id,name from student)where rownum>2;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
(3)rownum對(duì)于小于某值的查詢條件
如果想找到第三條記錄以前的記錄,當(dāng)使用rownum<3是能得到兩條記錄的。顯然rownum對(duì)于rownum<n((n>1的自然數(shù))的條件認(rèn)為是成立的,所以可以找到記錄。
SQL> select rownum,id,name from student where rownum <3;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200001 張一
2 200002 王二
綜 上幾種情況,可能有時(shí)候需要查詢r(jià)ownum在某區(qū)間的數(shù)據(jù),那怎么辦呀從上可以看出rownum對(duì)小于某值的查詢條件是人為true的,rownum對(duì) 于大于某值的查詢條件直接認(rèn)為是false的,但是可以間接的讓它轉(zhuǎn)為認(rèn)為是true的。那就必須使用子查詢。例如要查詢r(jià)ownum在第二行到第三行之 間的數(shù)據(jù),包括第二行和第三行數(shù)據(jù),那么我們只能寫以下語(yǔ)句,先讓它返回小于等于三的記錄行,然后在主查詢中判斷新的rownum的別名列大于等于二的記 錄行。但是這樣的操作會(huì)在大數(shù)據(jù)集中影響速度。
SQL> select * from (select rownum no,id,name from student where rownum<=3 ) where no >=2;
NO ID NAME
---------- ------ ---------------------------------------------------
2 200002 王二
3 200003 李三
(4)rownum和排序
Oracle中的rownum的是在取數(shù)據(jù)的時(shí)候產(chǎn)生的序號(hào),所以想對(duì)指定排序的數(shù)據(jù)去指定的rowmun行數(shù)據(jù)就必須注意了。
SQL> select rownum ,id,name from student order by name;
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
3 200003 李三
2 200002 王二
1 200001 張一
4 200004 趙四
可以看出,rownum并不是按照name列來(lái)生成的序號(hào)。系統(tǒng)是按照記錄插入時(shí)的順序給記錄排的號(hào),rowid也是順序分配的。為了解決這個(gè)問(wèn)題,必須使用子查詢
SQL> select rownum ,id,name from (select * from student order by name);
ROWNUM ID NAME
---------- ------ ---------------------------------------------------
1 200003 李三
2 200002 王二
3 200001 張一
4 200004 趙四
這樣就成了按name排序,并且用rownum標(biāo)出正確序號(hào)(有小到大)
//ArrayList
{
ArrayList arraylist=new ArrayList();
arraylist.add(0,"end");//指定索引加入值
//需注意的是,如果現(xiàn)有2個(gè)值,我加入索引為5的那么就會(huì)出現(xiàn)異常
for(int i=0;i<2;i++){
arraylist.add(i,String.valueOf(i));
}
System.out.println("ArrayList:");
for(int i=0;i<arraylist.size();i++){
System.out.print(arraylist.get(i)+";");
}
arraylist.add("0");//直接加入值到ArrayList的最后
arraylist.add("0");
System.out.print("\nArrayList\'s lastIndexOf(\"0\") is "+arraylist.lastIndexOf("0"));
}
//Arrays
{
String []array=new String[]{"a","b","c"};
List list=Arrays.asList(array);
System.out.println("\nArrays:");
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+";");
}
System.out.print("\nArrays\'s length is "+array.length);//打印數(shù)組的長(zhǎng)度
}
//Collections
{
String []array=new String[]{"a","b","c"};
List list=Arrays.asList(array);
Collections.fill(list,"Fill");//用Fill填充全部元素
System.out.println("\nCollections:");
for(int i=0;i<list.size();i++){
System.out.print(list.get(i)+";");
}
array=new String[]{"1","2","3"};
List list2=Arrays.asList(array);
Collections.copy(list,list2);//拷貝list2的數(shù)據(jù)進(jìn)list
System.out.println("\n"+list);
Collections.swap(list,2,1);//調(diào)換索引為1和2的元素的位置
System.out.println(list);
}
//EventObject
{
String s="hello";
String s2=s;
EventObject eventobject=new EventObject(s);//一個(gè)準(zhǔn)容器類型,確切的歸類它不是容器
System.out.println("EventObject:");
System.out.println(eventobject.getSource());
System.out.println(eventobject.equals(s2));
}
//HashMap
{
HashMap hashmap=new HashMap();//一個(gè)速度最快的容器
hashmap.put("0","c");
hashmap.put("1","a");
hashmap.put("2","b");
hashmap.put("3","a");
System.out.println("HashMap:");
System.out.println(hashmap);//該容器有其內(nèi)部的排序方式
Set set=hashmap.keySet();//獲取全部鍵
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(hashmap.get(iterator.next())+";");
}
}
//HashSet
{
HashSet hashset=new HashSet();//一個(gè)絕對(duì)不能重復(fù)的類型
hashset.add("c");
hashset.add("b");
hashset.add("a");
hashset.add("a");
hashset.add("b");
System.out.println("\nHashSet:");
System.out.println(hashset);
Iterator iterator=hashset.iterator();//取出元素
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//Hashtable
{
Hashtable hashtable=new Hashtable();//一個(gè)完全可以由其他容器替換的老容器類型
hashtable.put("0","c");
hashtable.put("1","a");
hashtable.put("3","c");
hashtable.put("2","b");
System.out.println("\nHashtable:");
Enumeration enumeration=hashtable.elements();//獲取元素,Enumeration已經(jīng)不是主流,Iterator是它的下一代替代品
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+";");
}
}
//IdentityHashMap
{
IdentityHashMap identityhashmap=new IdentityHashMap();
identityhashmap.put("0","c");
identityhashmap.put("1","a");
identityhashmap.put("3","b");
identityhashmap.put("2","a");
System.out.println("\nIdentityHashMap:");
System.out.println(identityhashmap);
System.out.println(identityhashmap.containsKey("3"));//是否包含這個(gè)鍵
System.out.println(identityhashmap.containsValue("a"));//是否包含值
Set set=identityhashmap.entrySet();//傳為Set類型
System.out.println(set);
set=identityhashmap.keySet();//全部鍵
System.out.println(set);
}
//LinkedHashMap
{
LinkedHashMap linkedhashmap=new LinkedHashMap();
linkedhashmap.put("0","b");
linkedhashmap.put("2","a");
linkedhashmap.put("1","c");
linkedhashmap.put("3","b");
System.out.println("LinkedHashMap:");
System.out.println(linkedhashmap);
System.out.println(linkedhashmap.containsKey("2"));//是否包含這個(gè)鍵
System.out.println(linkedhashmap.containsValue("c"));//是否包含值
Set set=linkedhashmap.keySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(linkedhashmap.get(iterator.next())+";");
}
}
//LinkedHashSet
{
LinkedHashSet linkedhashset=new LinkedHashSet();//它包含了幾種Set的屬性但卻沒(méi)有自己的特色
linkedhashset.add("c");
linkedhashset.add("a");
linkedhashset.add("a");
linkedhashset.add("b");
System.out.println("\nLinkedHashSet:");
System.out.println(linkedhashset);
System.out.println(linkedhashset.contains("a"));//是否包含對(duì)象
Iterator iterator=linkedhashset.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//LinkedList
{
LinkedList linkedlist=new LinkedList();//自由使用是它的特色
linkedlist.add("a");
linkedlist.add(1,"c");
linkedlist.addLast("b");
linkedlist.addFirst("d");
System.out.println("\nLinkedList:");
System.out.println(linkedlist);
//linkedlist.clear();//該方法清空容器
//linkedlist.remove(0);//刪除索引為0的元素
//linkedlist.remove("d");//刪除值為d的元素
//linkedlist.removeFirst();//刪除第一個(gè)元素
//linkedlist.removeLast();//刪除最后一個(gè)元素
for(int i=0;i<linkedlist.size();i++){
System.out.print(linkedlist.get(i)+";");
}
}
//Stack
{
Stack stack=new Stack();//堆棧
stack.add("b");
stack.add(0,"c");
stack.push("d");
stack.add("e");
stack.push("a");
Enumeration enumeration=stack.elements();
System.out.println("\nStack:");
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+";");
}
//后進(jìn)先出
System.out.println("\n"+stack.peek());
System.out.println(stack.pop());
System.out.println(stack.contains("d")+";"+stack.contains("a"));//是否包含該元素,有趣的事情發(fā)生了
System.out.println(stack.search("c"));//非常有用的屬性,檢索,但是由后向前的排列
}
//TreeMap
{
TreeMap treemap=new TreeMap();
treemap.put("0","d");
treemap.put("2","a");
treemap.put("1","b");
treemap.put("3","c");
System.out.println("\nTreeMap:");//可以對(duì)鍵排序
System.out.println(treemap);
System.out.println(treemap.firstKey());//返回第一個(gè)鍵
Set set=treemap.keySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(treemap.get(iterator.next())+";");
}
}
//TreeSet
{
TreeSet treeset=new TreeSet();//自動(dòng)排序內(nèi)容
treeset.add("b");
treeset.add("a");
treeset.add("c");
treeset.add("d");
System.out.println("\nTreeSet:");
System.out.println(treeset);
System.out.println(treeset.first());//返回第一個(gè)元素
Iterator iterator=treeset.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
}
//Vector
{
Vector vector=new Vector();
vector.add(0,"b");
vector.add("a");
vector.addElement("d");
vector.add("c");
System.out.println("\nVector:");
System.out.println(vector);
vector.set(2,"h");//替換掉指定索引的元素
System.out.println(vector);
Object []str=vector.toArray();
for(int i=0;i<str.length;i++){
System.out.print(str[i]+";");
}
vector.setSize(2);//重新設(shè)置大小為2
System.out.println("\n"+vector);
}
//WeakHashMap
{
WeakHashMap weakhashmap=new WeakHashMap();
weakhashmap.put("1","b");
weakhashmap.put("2","c");
weakhashmap.put("0","d");
weakhashmap.put("3","a");
System.out.println("\nWeakHashMap:");
System.out.println(weakhashmap);
System.out.println(weakhashmap.containsKey("3"));//是否包含鍵
System.out.println(weakhashmap.containsValue("d"));//是否包含值
Set set=weakhashmap.entrySet();
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+";");
}
//weakhashmap.remove("2");//刪除該鍵對(duì)應(yīng)的值
//weakhashmap.get("1");//獲取指定鍵的值
}
}
在JAVA的util包中有兩個(gè)所有集合的父接口Collection和Map,它們的父子關(guān)系:
java.util
+Collection 這個(gè)接口extends自 --java.lang.Iterable接口
+List 接口
-ArrayList 類
-LinkedList 類
-Vector 類 此類是實(shí)現(xiàn)同步的
+Queue 接口
+不常用,在此不表.
+Set 接口
+SortedSet 接口
-TreeSet 類
-HashSet
+Map 接口
-HashMap 類 (除了不同步和允許使用 null 鍵/值之外,與 Hashtable 大致相同.)
-Hashtable 類 此類是實(shí)現(xiàn)同步的,不允許使用 null 鍵值
+SortedMap 接口
-TreeMap 類
以下對(duì)眾多接口和類的簡(jiǎn)單說(shuō)明:首先不能不先說(shuō)一下數(shù)組(Array)
一、Array , Arrays
Java所有“存儲(chǔ)及隨機(jī)訪問(wèn)一連串對(duì)象”的做法,array是最有效率的一種。
1、
效率高,但容量固定且無(wú)法動(dòng)態(tài)改變。
array還有一個(gè)缺點(diǎn)是,無(wú)法判斷其中實(shí)際存有多少元素,length只是告訴我們array的容量。
2、Java中有一個(gè)Arrays類,專門用來(lái)操作array。
arrays中擁有一組static函數(shù),
equals():比較兩個(gè)array是否相等。array擁有相同元素個(gè)數(shù),且所有對(duì)應(yīng)元素兩兩相等。
fill():將值填入array中。
sort():用來(lái)對(duì)array進(jìn)行排序。
binarySearch():在排好序的array中尋找元素。
System.arraycopy():array的復(fù)制。
二、Collection , Map
若撰寫程序時(shí)不知道究竟需要多少對(duì)象,需要在空間不足時(shí)自動(dòng)擴(kuò)增容量,則需要使用容器類庫(kù),array不適用。
1、Collection 和 Map 的區(qū)別
容器內(nèi)每個(gè)為之所存儲(chǔ)的元素個(gè)數(shù)不同。
Collection類型者,每個(gè)位置只有一個(gè)元素。
Map類型者,持有 key-value pair,像個(gè)小型數(shù)據(jù)庫(kù)。
2、Java2容器類類庫(kù)的用途是“保存對(duì)象”,它分為兩類,各自旗下的子類關(guān)系
Collection
--List:將以特定次序存儲(chǔ)元素。所以取出來(lái)的順序可能和放入順序不同。
--ArrayList / LinkedList / Vector
--Set : 不能含有重復(fù)的元素
--HashSet /TreeSet
Map
--HashMap
--HashTable
--TreeMap
Map----一組成對(duì)的“鍵值對(duì)”對(duì)象,即其元素是成對(duì)的對(duì)象,最典型的應(yīng)用就是數(shù)據(jù)字典,并且還有其它廣泛的應(yīng)用。另外,Map可以返回其所有鍵組成的Set和其所有值組成的Collection,或其鍵值對(duì)組成的Set,并且還可以像數(shù)組一樣擴(kuò)展多維Map,只要讓Map中鍵值對(duì)的每個(gè)“值”是一個(gè)Map即可。
Collection下 1.迭代器
迭代器是一種設(shè)計(jì)模式,它是一個(gè)對(duì)象,它可以遍歷并選擇序列中的對(duì)象,而開(kāi)發(fā)人員不需要了解該序列的底層結(jié)構(gòu)。迭代器通常被稱為“輕量級(jí)”對(duì)象,因?yàn)閯?chuàng)建它的代價(jià)小。
Java中的Iterator功能比較簡(jiǎn)單,并且只能單向移動(dòng):
(1) 使用方法iterator()要求容器返回一個(gè)Iterator。第一次調(diào)用Iterator的next()方法時(shí),它返回序列的第一個(gè)元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個(gè)元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡(jiǎn)單的實(shí)現(xiàn),為L(zhǎng)ist設(shè)計(jì)的ListIterator具有更多的功能,它可以從兩個(gè)方向遍歷List,也可以從List中插入和刪除元素。
2.List的功能方法
List(interface): 次序是List最重要的特點(diǎn);它確保維護(hù)元素特定的順序。List為Collection添加了許多方法,使得能夠向List中間插入與移除元素(只推薦LinkedList使用)。一個(gè)List可以生成ListIterator,使用它可以從兩個(gè)方向遍歷List,也可以從List中間插入和刪除元素。
ArrayList: 由數(shù)組實(shí)現(xiàn)的List。它允許對(duì)元素進(jìn)行快速隨機(jī)訪問(wèn),但是向List中間插入與移除元素的速度很慢。ListIterator只應(yīng)該用來(lái)由后向前遍歷ArrayList,而不是用來(lái)插入和刪除元素,因?yàn)檫@比LinkedList開(kāi)銷要大很多。
LinkedList: 由列表實(shí)現(xiàn)的List。對(duì)順序訪問(wèn)進(jìn)行了優(yōu)化,向List中間插入與刪除得開(kāi)銷不大,隨機(jī)訪問(wèn)則相對(duì)較慢(可用ArrayList代替)。它具有方法addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast(),這些方法(沒(méi)有在任何接口或基類中定義過(guò))使得LinkedList可以當(dāng)作堆棧、隊(duì)列和雙向隊(duì)列使用。
3.Set的功能方法
Set(interface): 存入Set的每個(gè)元素必須是唯一的,這也是與List不同的,因?yàn)镾et不保存重復(fù)元素。加入Set的Object必須定義equals()方法以確保對(duì)象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護(hù)元素的次序。
HashSet: HashSet能快速定位一個(gè)元素,存入HashSet的對(duì)象必須定義hashCode()。
TreeSet: 保持次序的Set,底層為樹(shù)結(jié)構(gòu)。使用它可以從Set中提取有序的序列。
LinkedHashSet: 具有HashSet的查詢速度,且內(nèi)部使用鏈表維護(hù)元素的順序(插入的次序)。于是在使用迭代器遍歷Set時(shí),結(jié)果會(huì)按元素插入的次序顯示。
HashSet采用散列函數(shù)對(duì)元素進(jìn)行排序,這是專門為快速查詢而設(shè)計(jì)的;TreeSet采用紅黑樹(shù)的數(shù)據(jù)結(jié)構(gòu)進(jìn)行排序元素;LinkedHashSet內(nèi)部使用散列以加快查詢速度,同時(shí)使用鏈表維護(hù)元素的次序,使得看起來(lái)元素是以插入的順序保存的。需要注意的是,生成自己的類時(shí),Set需要維護(hù)元素的存儲(chǔ)順序,因此要實(shí)現(xiàn)Comparable接口并定義compareTo()方法。
3、其他特征
* List,Set,Map將持有對(duì)象一律視為Object型別。
* Collection、List、Set、Map都是接口,不能實(shí)例化。
繼承自它們的 ArrayList, Vector, HashTable, HashMap是具象class,這些才可被實(shí)例化。
* vector容器確切知道它所持有的對(duì)象隸屬什么型別。vector不進(jìn)行邊界檢查。
三、Collections
Collections是針對(duì)集合類的一個(gè)幫助類。提供了一系列靜態(tài)方法實(shí)現(xiàn)對(duì)各種集合的搜索、排序、線程完全化等操作。
相當(dāng)于對(duì)Array進(jìn)行類似操作的類——Arrays。
如,Collections.max(Collection coll); 取coll中最大的元素。
Collections.sort(List list); 對(duì)list中元素排序
四、如何選擇?
1、容器類和Array的區(qū)別、擇取
* 容器類僅能持有對(duì)象引用(指向?qū)ο蟮闹羔槪皇菍?duì)象信息copy一份至數(shù)列某位置。
* 一旦將對(duì)象置入容器內(nèi),便損失了該對(duì)象的型別信息。
2、
* 在各種Lists中,最好的做法是以ArrayList作為缺省選擇。當(dāng)插入、刪除頻繁時(shí),使用LinkedList();
Vector總是比ArrayList慢,所以要盡量避免使用。
* 在各種Sets中,HashSet通常優(yōu)于HashTree(插入、查找)。只有當(dāng)需要產(chǎn)生一個(gè)經(jīng)過(guò)排序的序列,才用TreeSet。
HashTree存在的唯一理由:能夠維護(hù)其內(nèi)元素的排序狀態(tài)。
* 在各種Maps中
HashMap用于快速查找。
* 當(dāng)元素個(gè)數(shù)固定,用Array,因?yàn)锳rray效率是最高的。
結(jié)論:最常用的是ArrayList,HashSet,HashMap,Array。而且,我們也會(huì)發(fā)現(xiàn)一個(gè)規(guī)律,用TreeXXX都是排序的。
注意:
1、Collection沒(méi)有g(shù)et()方法來(lái)取得某個(gè)元素。只能通過(guò)iterator()遍歷元素。
2、Set和Collection擁有一模一樣的接口。
3、List,可以通過(guò)get()方法來(lái)一次取出一個(gè)元素。使用數(shù)字來(lái)選擇一堆對(duì)象中的一個(gè),get(0)...。(add/get)
4、一般使用ArrayList。用LinkedList構(gòu)造堆棧stack、隊(duì)列queue。
5、Map用 put(k,v) / get(k),還可以使用containsKey()/containsValue()來(lái)檢查其中是否含有某個(gè)key/value。
HashMap會(huì)利用對(duì)象的hashCode來(lái)快速找到key。
* hashing
哈希碼就是將對(duì)象的信息經(jīng)過(guò)一些轉(zhuǎn)變形成一個(gè)獨(dú)一無(wú)二的int值,這個(gè)值存儲(chǔ)在一個(gè)array中。
我們都知道所有存儲(chǔ)結(jié)構(gòu)中,array查找速度是最快的。所以,可以加速查找。
發(fā)生碰撞時(shí),讓array指向多個(gè)values。即,數(shù)組每個(gè)位置上又生成一個(gè)梿表。
6、Map中元素,可以將key序列、value序列單獨(dú)抽取出來(lái)。
使用keySet()抽取key序列,將map中的所有keys生成一個(gè)Set。
使用values()抽取value序列,將map中的所有values生成一個(gè)Collection。
為什么一個(gè)生成Set,一個(gè)生成Collection?那是因?yàn)椋琸ey總是獨(dú)一無(wú)二的,value允許重復(fù)。
1、項(xiàng)目經(jīng)理必須關(guān)注項(xiàng)目成功的三個(gè)標(biāo)準(zhǔn)
簡(jiǎn)單地說(shuō),一是準(zhǔn)時(shí);二是預(yù)算控制在既定的范圍內(nèi);三是質(zhì)量得到經(jīng)理和用戶們的贊許。項(xiàng)目經(jīng)理必須保證項(xiàng)目小組的每一位成員都能對(duì)照上面三個(gè)標(biāo)準(zhǔn)來(lái)進(jìn)行工作。
2、任何事都應(yīng)當(dāng)先規(guī)劃再執(zhí)行
就項(xiàng)目管理而言,很多專家和實(shí)踐人員都同意這樣一個(gè)觀點(diǎn):需要項(xiàng)目經(jīng)理投入的最重要的一件事就是規(guī)劃。只有詳細(xì)而系統(tǒng)的由項(xiàng)目小組成員參與的規(guī)劃才是項(xiàng)目成功的唯一基礎(chǔ)。當(dāng)現(xiàn)實(shí)的世界出現(xiàn)了一種不適于計(jì)劃生存的環(huán)境時(shí),項(xiàng)目經(jīng)理應(yīng)制定一個(gè)新的計(jì)劃來(lái)反映環(huán)境的變化。規(guī)劃、規(guī)劃、再規(guī)劃就是項(xiàng)目經(jīng)理的一種生活方式。
3、項(xiàng)目經(jīng)理必須以自己的實(shí)際行動(dòng)向項(xiàng)目小組成員傳遞一種緊迫感
由于項(xiàng)目在時(shí)間、資源和經(jīng)費(fèi)上都是有限的,項(xiàng)目最終必須完成。但項(xiàng)目小組成員大多有自己的愛(ài)好,項(xiàng)目經(jīng)理應(yīng)讓項(xiàng)目小組成員始終關(guān)注項(xiàng)目的目標(biāo)和截止期限。例如,可以定期檢查,可以召開(kāi)例會(huì),可以制作一些提醒的標(biāo)志置于項(xiàng)目的場(chǎng)所。
4、成功的項(xiàng)目應(yīng)使用一種可以度量且被證實(shí)的項(xiàng)目生命周期
標(biāo)準(zhǔn)的信息系統(tǒng)開(kāi)發(fā)模型可以保證專業(yè)標(biāo)準(zhǔn)和成功的經(jīng)驗(yàn)?zāi)軌蛉谌腠?xiàng)目計(jì)劃。這類模型不僅可以保證質(zhì)量,還可以使重復(fù)勞動(dòng)降到最低程度。因此,當(dāng)遇到時(shí)間和預(yù)算壓力需要削減項(xiàng)目時(shí),項(xiàng)目經(jīng)理應(yīng)確定一種最佳的項(xiàng)目生命周期。
5、所有項(xiàng)目目標(biāo)和項(xiàng)目活動(dòng)必須生動(dòng)形象地得以交流和溝通
項(xiàng)目經(jīng)理和項(xiàng)目小組在項(xiàng)目開(kāi)始時(shí)就應(yīng)當(dāng)形象化地描述項(xiàng)目的最終目標(biāo),以確保與項(xiàng)目有關(guān)的每一個(gè)人都能記住。項(xiàng)目成本的各個(gè)細(xì)節(jié)都應(yīng)當(dāng)清楚、明確、毫不含糊,并確保每個(gè)人對(duì)此都達(dá)成了一致的意見(jiàn)。
6、采用漸進(jìn)的方式逐步實(shí)現(xiàn)目標(biāo)
如果試圖同時(shí)完成所有的項(xiàng)目目標(biāo),只會(huì)造成重復(fù)勞動(dòng),既浪費(fèi)時(shí)間又浪費(fèi)錢。俗話說(shuō),一口吃不成個(gè)胖子。項(xiàng)目目標(biāo)只能一點(diǎn)一點(diǎn)地去實(shí)現(xiàn),并且每實(shí)現(xiàn)一個(gè)目標(biāo)就進(jìn)行一次評(píng)估,確保整個(gè)項(xiàng)目能得以控制。
7、項(xiàng)目應(yīng)得到明確的許可,并由投資方簽字實(shí)施
在實(shí)現(xiàn)項(xiàng)目目標(biāo)的過(guò)程中獲得明確的許可是非常重要的。應(yīng)將投資方的簽字批準(zhǔn)視為項(xiàng)目的一個(gè)出發(fā)點(diǎn)。道理很簡(jiǎn)單:任何有權(quán)拒絕或有權(quán)修改項(xiàng)目目標(biāo)的人都應(yīng)當(dāng)在項(xiàng)目啟動(dòng)時(shí)審查和批準(zhǔn)這些項(xiàng)目目標(biāo)。
8、要想獲得項(xiàng)目成功必須對(duì)項(xiàng)目目標(biāo)進(jìn)行透徹的分析
研究表明,如果按照眾所周知記錄在案的業(yè)務(wù)需求來(lái)設(shè)計(jì)項(xiàng)目的目標(biāo),則該項(xiàng)目多半會(huì)成功。所以,項(xiàng)目經(jīng)理應(yīng)當(dāng)堅(jiān)持這樣一個(gè)原則,即在組織機(jī)構(gòu)啟動(dòng)項(xiàng)目之前,就應(yīng)當(dāng)為該項(xiàng)目在業(yè)務(wù)需求中找到充分的依據(jù)。
9、項(xiàng)目經(jīng)理應(yīng)當(dāng)責(zé)權(quán)對(duì)等
項(xiàng)目經(jīng)理應(yīng)當(dāng)對(duì)項(xiàng)目的結(jié)果負(fù)責(zé),這一點(diǎn)并不過(guò)分。但與此相對(duì)應(yīng),項(xiàng)目經(jīng)理也應(yīng)被授予足夠的權(quán)利以承擔(dān)相應(yīng)的責(zé)任。在某些時(shí)候,權(quán)利顯得特別重要,如獲取或協(xié)調(diào)資源,要求得到有關(guān)的中小企業(yè)的配合,做相應(yīng)的對(duì)項(xiàng)目成功有價(jià)值的決策等等。
10、項(xiàng)目投資方和用戶應(yīng)當(dāng)主動(dòng)介入,不能被動(dòng)地坐享其成
多數(shù)項(xiàng)目投資方和用戶都能正確地要求和行使批準(zhǔn)(全部或部分)項(xiàng)目目標(biāo)的權(quán)力。但伴隨這個(gè)權(quán)力的是相應(yīng)的責(zé)任——主動(dòng)地介入項(xiàng)目的各個(gè)階段。例如,在項(xiàng)目早期要幫助確定項(xiàng)目目標(biāo);在項(xiàng)目進(jìn)行中,要對(duì)完成的階段性目標(biāo)進(jìn)行評(píng)估,以確保項(xiàng)目能順利進(jìn)行。項(xiàng)目投資方應(yīng)幫助項(xiàng)目經(jīng)理去訪問(wèn)有關(guān)的中小企業(yè)和目標(biāo)顧客的成員,并幫助項(xiàng)目經(jīng)理獲得必要的文件資料。
11、項(xiàng)目的實(shí)施應(yīng)當(dāng)采用市場(chǎng)運(yùn)作機(jī)制
在多數(shù)情況下,項(xiàng)目經(jīng)理應(yīng)將自己看成是賣主,以督促自己完成投資方和用戶交付的任務(wù)。項(xiàng)目計(jì)劃一旦批準(zhǔn)項(xiàng)目經(jīng)理應(yīng)當(dāng)定期提醒項(xiàng)目小組成員該項(xiàng)目必須滿足的業(yè)務(wù)需求是什么,以及該怎樣工作才能滿足這些業(yè)務(wù)需求。
12、項(xiàng)目經(jīng)理應(yīng)當(dāng)獲得項(xiàng)目小組成員的最佳人選
最佳人選是指受過(guò)相應(yīng)的技能培訓(xùn),有經(jīng)驗(yàn),素質(zhì)高。對(duì)于項(xiàng)目來(lái)說(shuō),獲得最佳人選往往能彌補(bǔ)時(shí)間、經(jīng)費(fèi)或其它方面的不足。項(xiàng)目經(jīng)理應(yīng)當(dāng)為這些最佳的項(xiàng)目成員創(chuàng)造良好的工作環(huán)境,如幫助他們免受外部干擾,幫助他們獲得必要的工具和條件以發(fā)揮他們的才能。
在開(kāi)始正文之前,我想先講兩個(gè)故事——關(guān)于軟件項(xiàng)目的故事。
故事一
有兩個(gè)軟件項(xiàng)目(姑且稱之為“項(xiàng)目 A”和“項(xiàng)目 B”),它們?cè)陂_(kāi)始時(shí)的預(yù)算都是 50 個(gè)人月,時(shí)間是 5 個(gè)月。
項(xiàng)目 A 在 5 個(gè)月后完工,耗費(fèi)成本 50 人月
項(xiàng)目 B 在 6 個(gè)月后完工,耗費(fèi)成本 70 人月
在軟件圈子里摸爬滾打多年的讀者們對(duì)這個(gè)故事一定有自己的判斷——而且我可以大致猜出是什么樣的判斷。不過(guò)先別著急,我們還有另一個(gè)故事。
故事二
有兩個(gè)軟件項(xiàng)目(仍然姑且稱之為“項(xiàng)目 A”和“項(xiàng)目 B”),它們?cè)陂_(kāi)始時(shí)的計(jì)劃都是交付 200 項(xiàng)功能。
項(xiàng)目 A 在項(xiàng)目結(jié)束時(shí)一次性交付了最初計(jì)劃的 200 項(xiàng)功能,但客戶發(fā)現(xiàn)其中大約 30 項(xiàng)功能沒(méi)有太大用處,而另外 30 項(xiàng)有用的功能要等到下一個(gè)項(xiàng)目才能實(shí)現(xiàn)。
項(xiàng)目 B 在第一個(gè)月結(jié)束時(shí)交付了第一個(gè)版本,此后每?jī)芍芙桓兑粋€(gè)新的版本。在項(xiàng)目進(jìn)行的過(guò)程中,客戶進(jìn)行了一次業(yè)務(wù)調(diào)整,加入了 90 項(xiàng)新的功能,并擱置了 50 項(xiàng)用處不大的功能。最終該項(xiàng)目交付了 240 項(xiàng)功能。
聰明的讀者大概注意到了,前后兩個(gè)故事講的是同一回事,同樣的兩個(gè)項(xiàng)目。現(xiàn)在我的問(wèn)題來(lái)了:請(qǐng)問(wèn)哪個(gè)項(xiàng)目是更成功的項(xiàng)目?
這個(gè)問(wèn)題并不容易回答——實(shí)際上它沒(méi)有標(biāo)準(zhǔn)答案。站在很多軟件企業(yè)的立場(chǎng)上,項(xiàng)目 A 是一個(gè)理想的成功項(xiàng)目:按時(shí)間、按成本完成預(yù)先約定的任務(wù)。請(qǐng)注意,我用了“理想的”這個(gè)詞,稍后我還會(huì)解釋這個(gè)有趣的詞,因?yàn)閷?shí)際上的軟件項(xiàng)目往往沒(méi)有那么理想。
而如果換一個(gè)角度,站在客戶的立場(chǎng)上呢?也許付錢購(gòu)買軟件的客戶會(huì)有一些不同的想法。項(xiàng)目 B 從開(kāi)始之后一個(gè)月便交付了第一個(gè)可工作的版本,從那時(shí)起客戶就開(kāi)始使用這個(gè)軟件的部分功能,并且不斷地把自己使用的感受反饋給開(kāi)發(fā)團(tuán)隊(duì)。在真實(shí)的業(yè)務(wù)運(yùn)營(yíng)過(guò)程中,客戶甚至發(fā)現(xiàn)了一種新的盈利模式,并進(jìn)行了一次大規(guī)模的業(yè)務(wù)調(diào)整,這次調(diào)整的結(jié)果也直觀地體現(xiàn)在軟件項(xiàng)目中。雖然項(xiàng)目B的整體交付速率低于項(xiàng)目 A,但它提供的所有功能都是客戶真正需要的,它們?yōu)榭蛻籼峁?shí)實(shí)在在的價(jià)值——更不用說(shuō),客戶提前好幾個(gè)月就開(kāi)始使用這個(gè)軟件。
實(shí)際上,這是一篇關(guān)于軟件價(jià)值的文章。和“成功項(xiàng)目”一樣,對(duì)于“軟件的價(jià)值”,不同的人也會(huì)有不同的定義。不過(guò)作為付錢購(gòu)買軟件的客戶,他對(duì)于軟件價(jià)值的定義是一目了然的:他能夠從使用軟件中創(chuàng)造多少價(jià)值,軟件能夠?yàn)樗臉I(yè)務(wù)提供多少價(jià)值,這就是軟件的價(jià)值。或者說(shuō)得更簡(jiǎn)明一點(diǎn):
軟件價(jià)值源自使用
這正是為什么很多客戶青睞“項(xiàng)目 B”的原因——我并不打算聲稱所有客戶都有同樣的觀點(diǎn),稍后我也會(huì)舉出反例,但至少支持這一觀點(diǎn)的客戶不在少數(shù)。因?yàn)樗麄兲幵谝粋€(gè)殘酷而快速變化的商業(yè)環(huán)境中:他們的供應(yīng)商在變化,他們的客戶在變化,他們所處的經(jīng)濟(jì)環(huán)境和政策環(huán)境也在變化。這一切的變化迫使他們的業(yè)務(wù)也要隨之變化。更要命的是,今天這個(gè)經(jīng)濟(jì)全球化的時(shí)代是一個(gè)“快魚(yú)吃慢魚(yú)”的時(shí)代,客戶迫切希望新的軟件系統(tǒng)為他們帶來(lái)競(jìng)爭(zhēng)優(yōu)勢(shì)——哪怕這個(gè)軟件系統(tǒng)尚未完成,只要能夠投入使用。最后,客戶對(duì)于新的軟件系統(tǒng)究竟應(yīng)該是什么樣子并沒(méi)有百分之百的把握,他們的想法往往要在真正使用軟件之后才會(huì)浮現(xiàn)成型。幾方面的因素加在一起,使得這些客戶更愿意盡快開(kāi)始使用軟件、提出反饋、并不斷完善軟件,而不是提出一組需求、然后坐等幾個(gè)月之后原封不動(dòng)地拿到這些功能。
一個(gè)真實(shí)的案例
在 ThoughtWorks 的一個(gè)項(xiàng)目中,開(kāi)發(fā)者們?cè)陧?xiàng)目開(kāi)始之后一個(gè)月內(nèi)就發(fā)布了第一個(gè)版本——只有一些簡(jiǎn)單的數(shù)據(jù)采集功能。在發(fā)布展示會(huì)上,發(fā)生了這樣的對(duì)話……
開(kāi)發(fā)者:這是我們的第一個(gè)功能。我們從文本文件、Excel 數(shù)據(jù)表和遺留數(shù)據(jù)庫(kù)采集數(shù)據(jù),現(xiàn)在我們的數(shù)據(jù)庫(kù)中有這些數(shù)據(jù)……(展示數(shù)據(jù)庫(kù)結(jié)構(gòu))
客戶:唔……有意思。要是你能做這樣一個(gè)查詢(寫出查詢要求),得到的結(jié)果可能會(huì)有用。
開(kāi)發(fā)者:可是我們的界面上沒(méi)有地方做這樣的查詢操作。
客戶:啊,我不需要操作界面,只要每天深夜做一次查詢,把報(bào)表發(fā)到我的信箱就可以了。
開(kāi)發(fā)者:這樣嗎……另一個(gè)問(wèn)題是,這需要花我們幾天時(shí)間。
客戶:不要緊,把別的任務(wù)往后放幾天好了,我很想看到這份報(bào)表。
開(kāi)發(fā)者:那好吧,下周我們就會(huì)開(kāi)始提供這個(gè)報(bào)表。
猜猜結(jié)果怎么樣?一周之后客戶就開(kāi)始每天接收這份報(bào)表,并根據(jù)報(bào)表內(nèi)容做一些分析和決策。僅僅幾個(gè)月之后,這份報(bào)表給客戶帶來(lái)的收益就已經(jīng)超過(guò)了整個(gè)項(xiàng)目的投資——這時(shí)項(xiàng)目其他部分的開(kāi)發(fā)甚至還沒(méi)有完成。
想想這個(gè)客戶會(huì)怎么定義一個(gè)“成功的軟件項(xiàng)目”?好吧,也許這個(gè)項(xiàng)目超過(guò)了預(yù)期的時(shí)間,也許投入了更多的人力,但這些并不意味著“項(xiàng)目失敗”——只是付出更高的成本。關(guān)鍵在于,他投入的這些成本能夠帶來(lái)多大的收益,他的投資回報(bào)率是否劃算。對(duì)于這個(gè)客戶而言,如果項(xiàng)目能夠隨時(shí)給他提供可用的、能夠創(chuàng)造最大價(jià)值的軟件,能夠隨時(shí)讓——就像故事中提到的——這種有價(jià)值的想法得以實(shí)現(xiàn),這就是一個(gè)成功的項(xiàng)目。
所以,親愛(ài)的讀者,請(qǐng)你忘記本文標(biāo)題上出現(xiàn)的“敏捷”二字,我們?cè)谶@里所說(shuō)的不是別的,就是一種為客戶創(chuàng)造最大化價(jià)值的軟件開(kāi)發(fā)方法。這樣的方法有很多種,但它們有一個(gè)共同的特點(diǎn):盡快、盡可能頻繁地交付可以工作的軟件,讓客戶盡快開(kāi)始使用軟件,從使用中創(chuàng)造價(jià)值、厘清思路、提出反饋。仍然以 ThoughtWorks 的項(xiàng)目為例,這些項(xiàng)目通常在啟動(dòng)開(kāi)發(fā)階段之后一個(gè)月內(nèi)就會(huì)發(fā)布第一個(gè)版本,隨后每一周或每?jī)芍馨l(fā)布一個(gè)新版本——每個(gè)版本都是一個(gè)可以工作的軟件,每個(gè)版本都比前一個(gè)版本具有更豐富的功能,并且每個(gè)版本都包含客戶認(rèn)為迄今為止最有價(jià)值的那些功能。用軟件開(kāi)發(fā)的“黑話”,“開(kāi)發(fā)下一個(gè)版本”的過(guò)程叫做“迭代”,這些開(kāi)發(fā)方法最大的共同點(diǎn)就是“迭代式開(kāi)發(fā)”——不是一股腦地交付全部功能,而是每次增加一點(diǎn)、漸進(jìn)地交付最有價(jià)值的功能。
軟件開(kāi)發(fā)的夢(mèng)想與真實(shí)
回到文章開(kāi)始處的兩個(gè)故事。我曾經(jīng)說(shuō)過(guò),對(duì)于很多軟件企業(yè)而言,項(xiàng)目 A 是一個(gè)“理想的”成功項(xiàng)目。那么,是什么讓情況變得不那么理想?
答案是一個(gè)所有軟件開(kāi)發(fā)者耳熟能詳?shù)脑~:需求變更。在真實(shí)的項(xiàng)目中,客戶通常不會(huì)等到最后一天再照單全收整個(gè)項(xiàng)目,因?yàn)樗雷约旱臉I(yè)務(wù)正在發(fā)生變化。這時(shí)需求變更就出現(xiàn)了,伴隨著來(lái)回的扯皮和討價(jià)還價(jià)。更糟的是,大量的需求變更發(fā)生在項(xiàng)目晚期——因?yàn)橹钡竭@時(shí)客戶才真正看到、使用到這個(gè)軟件,他的很多想法才真正浮現(xiàn)成型。隨著這種“最后一分鐘的需求變更”,項(xiàng)目超期、超出預(yù)算也就成了家常便飯。能夠像項(xiàng)目A這樣完工交付的,實(shí)在是鳳毛麟角的幸運(yùn)兒。
為了對(duì)付需求變更這個(gè)噩夢(mèng),軟件開(kāi)發(fā)者們還發(fā)明了另一個(gè)詞:變更控制。這個(gè)有趣的詞暗示著:需求變更是一種“不好”的東西,是需要“控制”的東西。然而站在客戶的角度上想想,他在親身使用了軟件之后提出的要求,難道不是最有價(jià)值的東西嗎?把這種真正創(chuàng)造業(yè)務(wù)價(jià)值的要求“控制”起來(lái),難道是合理的嗎?
在前面我也暗示過(guò),并非所有的客戶都一定青睞迭代式開(kāi)發(fā)。那么,哪些軟件項(xiàng)目不一定需要迭代式開(kāi)發(fā)呢?從整篇文章的內(nèi)容不難看出,如果客戶的業(yè)務(wù)絕對(duì)不會(huì)變化,如果客戶的需求巨細(xì)靡遺非常明確,如果客戶不需要盡快開(kāi)始使用軟件以便收回成本,那么迭代式開(kāi)發(fā)對(duì)他的幫助就會(huì)小得多。不過(guò),如果讀者認(rèn)真思考的話,這樣的例子也許并不多——也許比你最初認(rèn)為的要少得多。一個(gè)很好的例子是“神州六號(hào)”火箭使用的計(jì)算機(jī)控制系統(tǒng)。還有多少這樣的例子?讀者不妨試著自己想想。
如果我足夠幸運(yùn)的話,也許一些讀者已經(jīng)被這篇文章吊起了胃口:既然有這么好的軟件開(kāi)發(fā)方法,既然它能夠?yàn)槲覀儎?chuàng)造更大的價(jià)值,那還等什么呢,我們馬上就動(dòng)手吧。事情不會(huì)那么簡(jiǎn)單。為了讓迭代式開(kāi)發(fā)能夠成為現(xiàn)實(shí),為了確保盡快、盡可能頻繁地交付,為了確保每次交付的都是最有價(jià)值的功能,我們——包括軟件開(kāi)發(fā)者、軟件企業(yè)和客戶——需要很多的改變。這里既有職責(zé)與權(quán)利的劃分,也有開(kāi)發(fā)過(guò)程和團(tuán)隊(duì)的重組,還有技術(shù)層面的實(shí)踐指導(dǎo)。這些正是敏捷方法學(xué)所涵蓋的內(nèi)容。缺少了這些東西,“為客戶創(chuàng)造最大價(jià)值”就只能成為一句空話。在后續(xù)的文章里,我們將結(jié)合 ThoughtWorks 的實(shí)踐經(jīng)驗(yàn),逐步介紹敏捷方法的方方面面。
最開(kāi)始時(shí)微軟公司將Java當(dāng)做一種能解決C和C++中存在的問(wèn)題的語(yǔ)言,并不在意,并繼續(xù)維持和培訓(xùn)著其C和C++技術(shù)和編程人員。接下來(lái)不幸的是,正當(dāng)微軟盡力在Visual J++基礎(chǔ)上拓展Java功能,并使之與Windows操作系統(tǒng)緊密結(jié)合在一起的時(shí)候,Sun公司對(duì)微軟提出法律訴訟說(shuō)其違反了許可證協(xié)議中的條款,最終的結(jié)果是微軟公司不得不停止其Visual J++產(chǎn)品的開(kāi)發(fā)。(微軟公司仍然銷售Visual J++,但是從1998年10月以來(lái)就沒(méi)有新的版本發(fā)布,并且在.Net平臺(tái)上也沒(méi)有Visual J++的位置了)接下來(lái)的事情就很清楚了,微軟公司開(kāi)發(fā)了C#語(yǔ)言。接下來(lái)的一部分將討論C#與Java的相似性。
C#與Java的區(qū)別
C#最引人的地方是它與Java的區(qū)別而不是其相似性。下面主要來(lái)介紹C#區(qū)別于Java的不同的運(yùn)行特點(diǎn)及Java完全沒(méi)有的特點(diǎn)。
中間語(yǔ)言
當(dāng)MSIL被編譯成最終的機(jī)器碼時(shí),微軟公司在如何選擇上是非常靈活的。微軟公司很謹(jǐn)慎的對(duì)外宣稱說(shuō)MSIL不是解釋型的,而是被編譯成機(jī)器碼。因?yàn)殚_(kāi)發(fā)人員都有這樣一個(gè)觀念:Java程序天生就比C程序運(yùn)行慢,所以這暗示著基于MSIL的程序優(yōu)于解釋型的Java字節(jié)碼。當(dāng)然,既然C#和其它MSIL產(chǎn)品編譯器還未發(fā)布,那么這一點(diǎn)就還未證明,但是Java無(wú)處不在的即時(shí)編譯器使得C#和Java在效能上是一樣的。象“C#是編譯型的,Java是解釋型的”這樣話只是銷售中的技巧。Java的字節(jié)碼和MSIL碼都是的類似匯編的中間語(yǔ)言,在運(yùn)行時(shí)執(zhí)行這些中間碼。
與COM的整合
對(duì)于基于Windows的C#開(kāi)發(fā)人員來(lái)說(shuō),最大的收獲是對(duì)COM的無(wú)損整合,COM是微軟Win32的組件技術(shù)。實(shí)際上,任何一種.Net體系結(jié)構(gòu)上的語(yǔ)言最終都可能去寫COM的客戶端和服務(wù)器端程序。用C#編寫的類也會(huì)作為COM組件的子類;結(jié)果類(resulting class)也能作為COM組件使用,并作為COM組件的子類。
微軟公司的目標(biāo)是使越來(lái)越多的語(yǔ)言都能訪問(wèn)組件,并使這些組件能整合到.Net體系結(jié)構(gòu)中。已有幾個(gè)廠商開(kāi)始著手開(kāi)發(fā)支持.Net功能的編程語(yǔ)言,如COBOL和Haskell。開(kāi)發(fā)人員能選擇不同的語(yǔ)言解決不同問(wèn)題,更重要的是,開(kāi)發(fā)人員不必為采用.Net體系結(jié)構(gòu)而必須學(xué)習(xí)新語(yǔ)言,可以選擇一種他們熟悉的語(yǔ)言。
總結(jié)
本文的第一、二部分對(duì)C#做了一膚淺的總體介紹,主要是其產(chǎn)生動(dòng)機(jī)及與Java的相似性。第三部分則涵概了C#的語(yǔ)言特點(diǎn)。用范例說(shuō)明了C#與Java兩者在相似性外,它們又是非常不同的,有許多細(xì)微的語(yǔ)義和設(shè)計(jì)區(qū)別,適合不同的技術(shù)和市場(chǎng)環(huán)境,又談到了微軟公司對(duì)C#進(jìn)行標(biāo)準(zhǔn)化方面的嘗試,及其對(duì)Java的影響。
c#與java的區(qū)別
1.屬性:
java中定義和訪問(wèn)均要用get和set方法,可以不成對(duì)出現(xiàn)。
c#中是真正的屬性,定義時(shí)get和set必須同時(shí)出現(xiàn),房問(wèn)時(shí)用.號(hào)即可。不用get,set
2.對(duì)象索引
就是對(duì)象數(shù)組
public Story this [int index] {
3.C#中,不用任何范圍修飾符時(shí),默認(rèn)的是protect,因而不能在類外被訪問(wèn).
4.因?yàn)镴AVA規(guī)定,在一個(gè)文件中只能有一個(gè)public類,而且這個(gè)類的名稱必須與文件名一模一樣,這是一個(gè)區(qū)別
5.在C#中,它是以Main方法來(lái)定位入口的.如果一個(gè)程序中沒(méi)有一個(gè)名為Main的方法,就會(huì)出"找不到入口的錯(cuò)誤".不要把Main寫成main喲
6.C#預(yù)定義的簡(jiǎn)單數(shù)據(jù)類型比Java多。例如,C#有unit,即無(wú)符號(hào)整數(shù)
7.忘掉Java中的static final修飾符。在C#中,常量可以用const關(guān)鍵詞聲明
C#的設(shè)計(jì)者還增加了readonly關(guān)鍵詞,readonly域只能通過(guò)初始化器或類的構(gòu)造函數(shù)設(shè)置
8.公用類的入口點(diǎn):c#是可以對(duì)Main進(jìn)行重載(java中是main),允許有int返回值和空參數(shù)的Main
9.在Java中,switch語(yǔ)句只能處理整數(shù)。但C#中的switch語(yǔ)句不同,它還能夠處理字符變量。請(qǐng)考慮下面用switch語(yǔ)句處理字符串變量的C#代碼
10.C#沒(méi)有>>>移位操作符
11.goto關(guān)鍵詞:
Java不用goto關(guān)鍵詞。在C#中,goto允許你轉(zhuǎn)到指定的標(biāo)簽。不過(guò),C#以特別謹(jǐn)慎的態(tài)度對(duì)待goto,比如它不允許goto轉(zhuǎn)入到語(yǔ)句塊的內(nèi)部。在Java中,你可以用帶標(biāo)簽的語(yǔ)句加上break或continue取代C#中的goto。
12.int[] x = { 0, 1, 2, 3 };
int x[] = { 0, 1, 2, 3 };
但在C#中,只有第一行代碼合法,[]不能放到變量名字之后。
13.與Java不同的是,C#允許為名稱空間或者名稱空間中的類指定別名:
using TheConsole = System.Console;
14.在Java中,包的名字同時(shí)也是實(shí)際存在的實(shí)體,它決定了放置.java文件的目錄結(jié)構(gòu)。在C#中,物理的包和邏輯的名稱之間是完全分離的
.NET中包的實(shí)體稱為程序集(Assembly)。每一個(gè)程序集包含一個(gè)manifest結(jié)構(gòu)。manifest列舉程序集所包含的文件,控制哪些類型和資源被顯露到程序集之外,并把對(duì)這些類型和資源的引用映射到包含這些類型與資源的文件。程序集是自包含的,一個(gè)程序集可以放置到單一的文件之內(nèi),也可以分割成多個(gè)文件。.NET的這種封裝機(jī)制解決了DLL文件所面臨的問(wèn)題,即臭名昭著的DLL Hell問(wèn)題。
15.在Java中,java.lang包是默認(rèn)的包,C#中不存在默認(rèn)的包
16.C#中的訪問(wèn)修飾符與Java中的基本對(duì)應(yīng),但多出了一個(gè)internal。簡(jiǎn)而言之,C#有5種類型的可訪問(wèn)性,如下所示:
public:成員可以從任何代碼訪問(wèn)。
protected:成員只能從派生類訪問(wèn)。
internal:成員只能從同一程序集的內(nèi)部訪問(wèn)。
protected internal:成員只能從同一程序集內(nèi)的派生類訪問(wèn)。
private:成員只能在當(dāng)前類的內(nèi)部訪問(wèn)。
17.由于C#中不存在final關(guān)鍵詞,如果想要某個(gè)類不再被派生,你可以使用sealed關(guān)鍵詞
18.與Java不同,C#中的接口不能包含域(Field)。
另外還要注意,在C#中,接口內(nèi)的所有方法默認(rèn)都是公用方法。在Java中,方法聲明可以帶有public修飾符(即使這并非必要),但在C#中,顯式為接口的方法指定public修飾符是非法的。例如,下面的C#接口將產(chǎn)生一個(gè)編譯錯(cuò)誤。
19.C#中的is操作符與Java中的instanceof操作符一樣,兩者都可以用來(lái)測(cè)試某個(gè)對(duì)象的實(shí)例是否屬于特定的類型。在Java中沒(méi)有與C#中的as操作符等價(jià)的操作符。as操作符與is操作符非常相似,但它更富有“進(jìn)取心”:如果類型正確的話,as操作符會(huì)嘗試把被測(cè)試的對(duì)象引用轉(zhuǎn)換成目標(biāo)類型;否則,它把變量引用設(shè)置成null。
20.C#仍舊保留了C++的內(nèi)存手工管理方法,它適合在速度極端重要的場(chǎng)合使用,而在Java中這是不允許的
21.在C#中,所有的異常都從一個(gè)名為Exception的類派生
22.枚舉器即enum類型(java無(wú)),把它作為一個(gè)變量值的類型使用,從而把變量可能的取值范圍限制為枚舉器中出現(xiàn)的值。
23.結(jié)構(gòu)(Struct)與類很相似,而結(jié)構(gòu)是一種值類型,它存儲(chǔ)在棧中或者是嵌入式的,結(jié)構(gòu)可以實(shí)現(xiàn)接口,可以象類一樣擁有成員,但結(jié)構(gòu)不支持繼承
24.屬性聲明語(yǔ)法的第一部分與域聲明很相似,第二部分包括一個(gè)set過(guò)程和/或一個(gè)get過(guò)程
25.傳值方式:
在java中簡(jiǎn)單數(shù)據(jù)類型的值傳參時(shí),都以傳值方式;
在c#中如果加ref則會(huì)以引用的方式傳值(方法內(nèi)部改變?cè)搮?shù),則外部變量一起跟著變);
加out與ref基本相同,但out不要求參數(shù)一定要初始化.
26.c#保留了指針。unsafe
27.代理:代理(delegate)可以看作C++或者其他語(yǔ)言中的函數(shù)指針
代理用來(lái)封裝可調(diào)用方法。你可以在類里面編寫方法并在該方法上創(chuàng)建代理,此后這個(gè)代理就可以被傳遞到第二個(gè)方法。這樣,第二個(gè)方法就可以調(diào)用第一個(gè)方法。
代理是從公共基類System.Delegate派生的引用類型。定義和使用代理包括三個(gè)步驟:聲明,創(chuàng)建實(shí)例,調(diào)用。代理用delegate聲明語(yǔ)法聲明。
初學(xué) Java 有段時(shí)間了,感覺(jué)似乎開(kāi)始入了門,有了點(diǎn)兒感覺(jué)
但是發(fā)現(xiàn)很多困惑和疑問(wèn)而且均來(lái)自于最基礎(chǔ)的知識(shí)
折騰了一陣子又查了查書(shū),終于對(duì) String 這個(gè)特殊的對(duì)象有了點(diǎn)感悟
大家先來(lái)看看一段奇怪的程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
}
}
這個(gè)程序真是簡(jiǎn)單啊!可是有什么問(wèn)題呢?
1. 來(lái)自 String 的憂慮
上面這段程序中,到底有幾個(gè)對(duì)象呢?
可能很多人脫口而出:兩個(gè),s1 和 s2
為什么?
String 是 final 類,它的值不可變。
看起來(lái)似乎很有道理,那么來(lái)檢測(cè)一下吧,稍微改動(dòng)一下程序
就可以看到結(jié)果了:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = "Monday";
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
}
}
呵呵,很多人都會(huì)說(shuō)已經(jīng)不止兩個(gè)對(duì)象了
編譯并運(yùn)行程序,輸出:s1 == s2
啊!
為什么 s1 == s2 ?
== 分明是在說(shuō):s1 與 s2 引用同一個(gè) String 對(duì)象 -- "Monday"!
2. 千變?nèi)f化的 String
再稍微改動(dòng)一下程序,會(huì)有更奇怪的發(fā)現(xiàn):
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
我們將 s2 用 new 操作符創(chuàng)建
程序輸出:
s1 != s2
s1 equals s2
嗯,很明顯嘛
s1 s2分別引用了兩個(gè)"Monday"String對(duì)象
可是為什么兩段程序不一樣呢?
3. 在 String 的游泳池中游泳
哈哈,翻了翻書(shū)終于找到了答案:
原來(lái),程序在運(yùn)行的時(shí)候會(huì)創(chuàng)建一個(gè)字符串緩沖池
當(dāng)使用 s2 = "Monday" 這樣的表達(dá)是創(chuàng)建字符串的時(shí)候,程序首先會(huì)
在這個(gè)String緩沖池中尋找相同值的對(duì)象,在第一個(gè)程序中,s1先被
放到了池中,所以在s2被創(chuàng)建的時(shí)候,程序找到了具有相同值的 s1
將 s2 引用 s1 所引用的對(duì)象"Monday"
第二段程序中,使用了 new 操作符,他明白的告訴程序:
“我要一個(gè)新的!不要舊的!”與是一個(gè)新的"Monday"Sting對(duì)象被創(chuàng)
建在內(nèi)存中。他們的值相同,但是位置不同,一個(gè)在池中游泳
一個(gè)在岸邊休息。哎呀,真是資源浪費(fèi),明明是一樣的非要分開(kāi)做什么呢?
4. 繼續(xù)潛水
再次更改程序:
public class TestString {
public static void main(String[] args) {
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern();
if (s1 == s2)
System.out.println("s1 == s2");
else
System.out.println("s1 != s2");
if (s1.equals(s2))
System.out.println("s1 equals s2");
else
System.out.println("s1 not equals s2");
}
}
這次加入:s2 = s2.intern();
哇!程序輸出:
s1 == s2
s1 equals s2
原來(lái),程序新建了 s2 之后,又用intern()把他打翻在了池里
哈哈,這次 s2 和 s1 有引用了同樣的對(duì)象了
我們成功的減少了內(nèi)存的占用
5. == 與 equals() 的爭(zhēng)斗
String 是個(gè)對(duì)象,要對(duì)比兩個(gè)不同的String對(duì)象的值是否相同
明顯的要用到 equals() 這個(gè)方法
可是如果程序里面有那么多的String對(duì)象,有那么多次的要用到 equals ,
哦,天哪,真慢啊
更好的辦法:
把所有的String都intern()到緩沖池去吧
最好在用到new的時(shí)候就進(jìn)行這個(gè)操作
String s2 = new String("Monday").intern();
嗯,大家都在水池里泡著了嗎?哈哈
現(xiàn)在我可以無(wú)所顧忌的用 == 來(lái)比較 String 對(duì)象的值了
真是爽啊,又快又方便!
關(guān)于String :)
String 啊 String ,讓我說(shuō)你什么好呢?
你為我們 Java 程序員帶來(lái)所有的困擾還不夠嗎?
看看 String 這一次又怎么鬧事兒吧
1. 回顧一下壞脾氣的 String 老弟
例程1:
class Str {
public static void main(String[] args) {
String s = "Hi!";
String t = "Hi!";
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
程序輸出什么呢?
如果看客們看過(guò)我的《來(lái)自 String 的困惑》之一
相信你很快會(huì)做出正確的判斷:
程序輸出:equals
2. 哦,天哪,它又在攪混水了
例程2:
class Str {
public static void main(String[] args) {
String s = "HELLO";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
那么這個(gè)程序有輸出什么呢?
慎重!再慎重!不要被 String 這個(gè)迷亂的家伙所迷惑!
它輸出:equals
WHY!!!
把程序簡(jiǎn)單的更改一下:
class Str2 {
public static void main(String[] args) {
String s = "Hello";
String t = s.toUpperCase();
if (s == t)
System.out.println("equals");
else
System.out.println("not equals");
}
}
你可能會(huì)說(shuō):不是一樣嗎?
不!千真萬(wàn)確的,不一樣!這一次輸出:not equals
Oh MyGOD!!!
誰(shuí)來(lái)教訓(xùn)一下這個(gè) String 啊!
3. 你了解你的馬嗎?
“要馴服脫韁的野馬,就要了解它的秉性”牛仔們說(shuō)道。
你了解 String 嗎?
解讀 String 的 API ,可以看到:
toUpperCase() 和 toLowerCase() 方法返回一個(gè)新的String對(duì)象,
它將原字符串表示字符串的大寫或小寫形勢(shì);
但是要注意:如果原字符串本身就是大寫形式或小寫形式,那么返回原始對(duì)象。
這就是為什么第二個(gè)程序中 s 和 t 糾纏不清的緣故
對(duì)待這個(gè)淘氣的、屢教不改的 String ,似乎沒(méi)有更好的辦法了
讓我們解剖它,看看它到底有什么結(jié)構(gòu)吧:
(1) charAt(int n) 返回字符串內(nèi)n位置的字符,第一個(gè)字符位置為0,
最后一個(gè)字符的位置為length()-1,訪問(wèn)錯(cuò)誤的位置會(huì)扔出一塊大磚頭:
StringIndexOutOfBoundsException 真夠大的
(2) concat(String str) 在原對(duì)象之后連接一個(gè) str ,但是返回一個(gè)新的 String 對(duì)象
(3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法
這個(gè)方法的實(shí)質(zhì)是首先調(diào)用靜態(tài)字符方法toUpperCase() 或者 toLowerCase()
將對(duì)比的兩個(gè)字符轉(zhuǎn)換,然后進(jìn)行 == 運(yùn)算
(4) trim() 返回一個(gè)新的對(duì)象,它將原對(duì)象的開(kāi)頭和結(jié)尾的空白字符切掉
同樣的,如果結(jié)果與原對(duì)象沒(méi)有差別,則返回原對(duì)象
(5) toString() String 類也有 toString() 方法嗎?
真是一個(gè)有趣的問(wèn)題,可是如果沒(méi)有它,你的 String 對(duì)象說(shuō)不定真的不能用在
System.out.println() 里面啊
小心,它返回對(duì)象自己
String 類還有很多其他方法,掌握他們會(huì)帶來(lái)很多方便
也會(huì)有很多困惑,所以堅(jiān)持原則,是最關(guān)鍵的
4. 我想買一匹更好的馬
來(lái)購(gòu)買更馴服溫和的 String 的小弟 StringBuffer 吧
這時(shí)候會(huì)有人反對(duì):它很好用,它效率很高,它怎么能夠是小弟呢?
很簡(jiǎn)單,它的交互功能要比 String 少,如果你要編輯字符串
它并不方便,你會(huì)對(duì)它失望
但這不意味著它不強(qiáng)大
public final class String implements Serializable, Comparable, CharSequence
public final class StringBuffer implements Serializable, CharSequence
很明顯的,小弟少了一些東東,不過(guò)這不會(huì)干擾它的前途
StringBuffer 不是由 String 繼承來(lái)的
不過(guò)要注意兄弟它也是 final 啊,本是同根生
看看他的方法吧,這么多穩(wěn)定可靠的方法,用起來(lái)比頑皮的 String 要有效率的多
?br /> Java 為需要改變的字符串對(duì)象提供了獨(dú)立的 StringBuffer 類
它的實(shí)例不可變(final),之所以要把他們分開(kāi)
是因?yàn)椋址男薷囊笙到y(tǒng)的開(kāi)銷量增大,
占用更多的空間也更復(fù)雜,相信當(dāng)有10000人擠在一個(gè)狹小的游泳池里游泳
而岸邊又有10000人等待進(jìn)入游泳池而焦急上火
又有10000人在旁邊看熱鬧的時(shí)候,你這個(gè) String 游泳池的管理員也會(huì)焦頭爛額
在你無(wú)需改變字符串的情況下,簡(jiǎn)單的 String 類就足夠你使喚的了,
而當(dāng)要頻繁的更改字符串的內(nèi)容的時(shí)候,就要借助于宰相肚里能撐船的
StringBuffer 了
5. 宰相肚里能撐船
(1) length() 與 capacity()
String 中的 length() 返回字符串的長(zhǎng)度
兄弟 StringBuffer 也是如此,他們都由對(duì)象包含的字符長(zhǎng)度決定
capacity()呢?
public class TestCapacity {
public static void main(String[] args){
StringBuffer buf = new StringBuffer("it was the age of wisdom,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
String str = buf.toString();
System.out.println("str = " + str);
System.out.println("str.length() = " + str.length());
buf.append(" " + str.substring(0,18)).append("foolishness,");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " + buf.length());
System.out.println("buf.capacity() = " + buf.capacity());
System.out.println("str = " + str);
}
}
程序輸出:
buf = it was the age of wisdom.
buf.length() = 25
buf.capacity() = 41
str = it was the age of wisdom
str.length() = 25
buf = it was the age of wisdom, it was the age of foolishness,
buf.length() = 56
buf.capacity() = 84
str = it was the age of wisdom,
可以看到,在內(nèi)容更改之后,capacity也隨之改變了
長(zhǎng)度隨著向字符串添加字符而增加
而容量只是在新的長(zhǎng)度超過(guò)了現(xiàn)在的容量之后才增加
StringBuffer 的容量在操作系統(tǒng)需要的時(shí)候是自動(dòng)改變的
程序員們對(duì)capacity所能夠做的僅僅是可以在初始化 StringBuffer對(duì)象的時(shí)候
以上片斷引用自http://bbs.blueidea.com/viewthread.php?tid=945875&page=###
解釋得比較形象和經(jīng)典。具體的比較,要親自動(dòng)手運(yùn)行一下程序才行,如下為網(wǎng)上找到的專門研究equals和==的關(guān)系的程序,相信可從中體會(huì)出他們的深刻不同:
String s1 = null;
String s2 = null;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***1***");
s1 = null;
s2 = "";
System.out.println(s1==s2);//false
//System.out.println(s1.equals(s2));//NullPointerException
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***2***");
s1 = "";
s2 = null;
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//false
s1 = s2;
System.out.println(s1==s2);//true
//System.out.println(s1.equals(s2));//NullPointerException
System.out.println("***3***");
s1 = "";
s2 = "";
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***4***");
s1 = new String("");
s2 = new String("");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***5***");
s1 = "null";
s2 = "null";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***6***");
s1 = new String("null");
s2 = new String("null");
System.out.println(s1==s2);//flase
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***7***");
s1 = "abc";
s2 = "abc";
System.out.println(s1==s2);//ture
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***8***");
s1 = new String("abc");
s2 = new String("abc");
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
s1 = s2;
System.out.println(s1==s2);//true
System.out.println(s1.equals(s2));//true
System.out.println("***9***");
總結(jié): 多數(shù)情況下這兩者的區(qū)別就是究竟是對(duì)對(duì)象的引用進(jìn)行比較還是對(duì)對(duì)象的值進(jìn)行比較(其他特殊情況此處不予考慮)。==操作符是比較的對(duì)象的引用而不是對(duì)象的值。
但在最初的Object對(duì)象中的equals方法與==操作符完成功能是相同的。
源碼:
java.lang.Object.equals()方法:
-------------------------------------------------------------
public boolean equalss(Object obj) {
return (this = = obj);
}
-------------------------------------------------------------
jdk文檔中給出如下解釋:
-------------------------------------------------------------
The equalss method implements an equivalence relation:
· It is reflexive: for any reference value x, x.equalss(x) should return true.
· It is symmetric: for any reference values x and y, x.equalss(y) should return true if and only if y.equalss(x) returns true.
· It is transitive: for any reference values x, y, and z, if x.equalss(y) returns true and y.equalss(z) returns true, then x.equalss(z) should return true.
· It is consistent: for any reference values x and y, multiple invocations of x.equalss(y) consistently return true or consistently return false, provided no information used in equalss comparisons on the object is modified.
· For any non-null reference value x, x.equalss(null) should return false.
The equalss method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any reference values x and y, this method returns true if and only if x and y refer to the same object (x==y has the value true).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equals objects must have equals hash codes.
-------------------------------------------------------------
對(duì)于String類的equals方法是對(duì)什么內(nèi)容進(jìn)行比較的呢?下面我們來(lái)看它的代碼和注釋:
源代碼:
-------------------------------------------------------------
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
-------------------------------------------------------------
此方法的注釋為:
-------------------------------------------------------------
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
-------------------------------------------------------------
由上面的代碼和注釋可以得到String類的equal方法是對(duì)對(duì)象的值進(jìn)行比較。
根據(jù)以上的討論可以得出結(jié)論:equal方法和==操作符是否存在區(qū)別要個(gè)別對(duì)待,要根據(jù)equal的每個(gè)實(shí)現(xiàn)情況來(lái)具體判斷。
tomcat5.5.9 jdbc 連接池配置時(shí)常會(huì)出現(xiàn)兩個(gè)錯(cuò)誤:
1.***not bound
2.Cannot create JDBC driver of class '' for connect URL 'null'
可以通過(guò)以下的方法達(dá)到正確的配置:
1.現(xiàn)在%tomcat home%/conf/catalina/localhost 下面添加一段獨(dú)立的context xml段,命名為jasper.xml,例如
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/jasper" docBase="jasper" debug="1" reloadable="true" crossContext="true">
</Context>
2.通過(guò)admin的界面(或手動(dòng)在server.xml界面里進(jìn)行配置)數(shù)據(jù)源,以sql2k為例,配置后的server.xml應(yīng)該為
<?xml version="1.0" encoding="UTF-8"?>
<Server>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/>
<GlobalNamingResources>
<Environment
name="simpleValue"
type="java.lang.Integer"
value="30"/>
<Resource
auth="Container"
description="User database that can be updated and saved"
name="UserDatabase"
type="org.apache.catalina.UserDatabase"
pathname="conf/tomcat-users.xml"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"/>
<Resource
name="jdbc/Northwind"
type="javax.sql.DataSource"
password="*****"
driverClassName="com.microsoft.jdbc.sqlserver.SQLServerDriver"
maxIdle="2"
maxWait="5000"
username="sa"
url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Northwind"
maxActive="20"/>
</GlobalNamingResources>
<Service
name="Catalina">
<Connector
port="80"
redirectPort="8443"
minSpareThreads="25"
connectionTimeout="20000"
maxSpareThreads="75"
maxThreads="150"
maxHttpHeaderSize="8192">
</Connector>
<Connector
port="8009"
redirectPort="8443"
protocol="AJP/1.3">
</Connector>
<Engine
defaultHost="localhost"
name="Catalina">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"/>
<Host
appBase="webapps"
name="localhost">
</Host>
</Engine>
</Service>
</Server>
3.在conf下面的context.xml文件中,</Context>之前加入
<ResourceLink name="jdbc/Northwind" global="jdbc/Northwind" type="javax.sql.DataSourcer"/>
4.在你的web文件夾下面的WEB-INF中找到web.xml,在最后</web-app>之前加入
<resource-ref>
<description>Northwind Connection</description>
<res-ref-name>jdbc/Northwind</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
5.保存,重啟tomcat,這樣,通過(guò)測(cè)試頁(yè)面,就可以發(fā)現(xiàn)已經(jīng)可以通過(guò)數(shù)據(jù)庫(kù)連接池連上sql2k
test1.jsp
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<%@page import="javax.naming.*"%>
<%@page import="javax.sql.*"%>
<%
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:/comp/env");
DataSource ds = (DataSource)envContext.lookup("jdbc/Northwind");
Connection conn = ds.getConnection();
int counts=0;
String sql="select count(*) from orders";
PreparedStatement pst=conn.prepareStatement(sql);
ResultSet rst=pst.executeQuery();
while(rst.next()){
counts=rst.getInt(1);
}
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>JNDI 測(cè)試</title>
</head>
<body>
<%=sql%><br>
pnrreg talbe's count is:<%=counts%>
</body>
</html>
摘要: JS的正則表達(dá)式
//校驗(yàn)是否全由數(shù)字組成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗(yàn)登錄名:只能輸入5-20個(gè)以字母開(kāi)頭、可帶數(shù)字、“_”... 閱讀全文
原著:Steve Mansour
sman@scruznet.com
Revised: June 5, 1999
(copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! )
翻譯:Neo Lee
neo.lee@gmail.com
2004年10月16日
英文版原文
譯者按:原文因?yàn)槟甏眠h(yuǎn),文中很多鏈接早已過(guò)期(主要是關(guān)于vi、sed等工具的介紹和手冊(cè)),本譯文中已將此類鏈接刪除,如需檢查這些鏈接可以查看上面鏈接的原文。除此之外基本照原文直譯,括號(hào)中有“譯者按”的部分是譯者補(bǔ)充的說(shuō)明。如有內(nèi)容方面的問(wèn)題請(qǐng)直接和Steve Mansor聯(lián)系,當(dāng)然,如果你只寫中文,也可以和我聯(lián)系。
目 錄
什么是正則表達(dá)式
范例
簡(jiǎn)單
中級(jí)(神奇的咒語(yǔ))
困難(不可思議的象形文字)
不同工具中的正則表達(dá)式
什么是正則表達(dá)式
一個(gè)正則表達(dá)式,就是用某種模式去匹配一類字符串的一個(gè)公式。很多人因?yàn)樗鼈兛瓷先ケ容^古怪而且復(fù)雜所以不敢去使用——很不幸,這篇文章也不能夠改變這一點(diǎn),不過(guò),經(jīng)過(guò)一點(diǎn)點(diǎn)練習(xí)之后我就開(kāi)始覺(jué)得這些復(fù)雜的表達(dá)式其實(shí)寫起來(lái)還是相當(dāng)簡(jiǎn)單的,而且,一旦你弄懂它們,你就能把數(shù)小時(shí)辛苦而且易錯(cuò)的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)內(nèi)完成。正則表達(dá)式被各種文本編輯軟件、類庫(kù)(例如Rogue Wave的tools.h++)、腳本工具(像awk/grep/sed)廣泛的支持,而且像Microsoft的Visual C++這種交互式IDE也開(kāi)始支持它了。
我們將在如下的章節(jié)中利用一些例子來(lái)解釋正則表達(dá)式的用法,絕大部分的例子是基于vi中的文本替換命令和grep文件搜索命令來(lái)書(shū)寫的,不過(guò)它們都是比較典型的例子,其中的概念可以在sed、awk、perl和其他支持正則表達(dá)式的編程語(yǔ)言中使用。你可以看看不同工具中的正則表達(dá)式這一節(jié),其中有一些在別的工具中使用正則表達(dá)式的例子。還有一個(gè)關(guān)于vi中文本替換命令(s)的簡(jiǎn)單說(shuō)明附在文后供參考。
正則表達(dá)式基礎(chǔ)
正則表達(dá)式由一些普通字符和一些 元字符(metacharacters)組成。普通字符包括大小寫的字母和數(shù)字,而元字符則具有特殊的含義,我們下面會(huì)給予解釋。
在最簡(jiǎn)單的情況下,一個(gè)正則表達(dá)式看上去就是一個(gè)普通的查找串。例如,正則表達(dá)式"testing"中沒(méi)有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。
要想真正的用好正則表達(dá)式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對(duì)它們的一個(gè)簡(jiǎn)短的描述。
元字符 |
|
描述 |
|
|
|
. |
|
匹配任何單個(gè)字符。例如正則表達(dá)式r.t匹配這些字符串:rat、rut、r t,但是不匹配root。 |
$ |
|
匹配行結(jié)束符。例如正則表達(dá)式weasel$ 能夠匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。 |
^ |
|
匹配一行的開(kāi)始。例如正則表達(dá)式^When in能夠匹配字符串"When in the course of human events"的開(kāi)始,但是不能匹配"What and When in the"。 |
* |
|
匹配0或多個(gè)正好在它之前的那個(gè)字符。例如正則表達(dá)式.*意味著能夠匹配任意數(shù)量的任何字符。 |
\ |
|
這是引用府,用來(lái)將這里列出的這些元字符當(dāng)作普通的字符來(lái)進(jìn)行匹配。例如正則表達(dá)式\$被用來(lái)匹配美元符號(hào),而不是行尾,類似的,正則表達(dá)式\.用來(lái)匹配點(diǎn)字符,而不是任何字符的通配符。 |
[ ]
[c1-c2]
[^c1-c2] |
|
匹配括號(hào)中的任何一個(gè)字符。例如正則表達(dá)式r[aou]t匹配rat、rot和rut,但是不匹配ret。可以在括號(hào)中使用連字符-來(lái)指定字符的區(qū)間,例如正則表達(dá)式[0-9]可以匹配任何數(shù)字字符;還可以制定多個(gè)區(qū)間,例如正則表達(dá)式[A-Za-z]可以匹配任何大小寫字母。另一個(gè)重要的用法是“排除”,要想匹配除了指定區(qū)間之外的字符——也就是所謂的補(bǔ)集——在左邊的括號(hào)和第一個(gè)字符之間使用^字符,例如正則表達(dá)式[^269A-Z] 將匹配除了2、6、9和所有大寫字母之外的任何字符。 |
\< \> |
|
匹配詞(word)的開(kāi)始(\<)和結(jié)束(\>)。例如正則表達(dá)式\<the能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個(gè)元字符不是所有的軟件都支持的。 |
\( \) |
|
將 \( 和 \) 之間的表達(dá)式定義為“組”(group),并且將匹配這個(gè)表達(dá)式的字符保存到一個(gè)臨時(shí)區(qū)域(一個(gè)正則表達(dá)式中最多可以保存9個(gè)),它們可以用 \1 到\9 的符號(hào)來(lái)引用。 |
| |
|
將兩個(gè)匹配條件進(jìn)行邏輯“或”(Or)運(yùn)算。例如正則表達(dá)式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:這個(gè)元字符不是所有的軟件都支持的。 |
+ |
|
匹配1或多個(gè)正好在它之前的那個(gè)字符。例如正則表達(dá)式9+匹配9、99、999等。注意:這個(gè)元字符不是所有的軟件都支持的。 |
? |
|
匹配0或1個(gè)正好在它之前的那個(gè)字符。注意:這個(gè)元字符不是所有的軟件都支持的。 |
\{i\}
\{i,j\} |
|
匹配指定數(shù)目的字符,這些字符是在它之前的表達(dá)式定義的。例如正則表達(dá)式A[0-9]\{3\} 能夠匹配字符"A"后面跟著正好3個(gè)數(shù)字字符的串,例如A123、A348等,但是不匹配A1234。而正則表達(dá)式[0-9]\{4,6\} 匹配連續(xù)的任意4個(gè)、5個(gè)或者6個(gè)數(shù)字字符。注意:這個(gè)元字符不是所有的軟件都支持的。 |
最簡(jiǎn)單的元字符是點(diǎn),它能夠匹配任何單個(gè)字符(注意不包括新行符)。假定有個(gè)文件test.txt包含以下幾行內(nèi)容:
he is a rat
he is in a rut
the food is Rotten
I like root beer
我們可以使用grep命令來(lái)測(cè)試我們的正則表達(dá)式,grep命令使用正則表達(dá)式去嘗試匹配指定文件的每一行,并將至少有一處匹配表達(dá)式的所有行顯示出來(lái)。命令
在test.txt文件中的每一行中搜索正則表達(dá)式 r.t,并打印輸出匹配的行。正則表達(dá)式 r.t匹配一個(gè) r接著任何一個(gè)字符再接著一個(gè) t。所以它將匹配文件中的 rat和 rut,而不能匹配 Rotten中的 Rot,因?yàn)檎齽t表達(dá)式是大小寫敏感的。要想同時(shí)匹配大寫和小寫字母,應(yīng)該使用字符區(qū)間元字符(方括號(hào))。正則表達(dá)式 [Rr]能夠同時(shí)匹配 R和 r。所以,要想匹配一個(gè)大寫或者小寫的 r接著任何一個(gè)字符再接著一個(gè) t就要使用這個(gè)表達(dá)式: [Rr].t。
要想匹配行首的字符要使用抑揚(yáng)字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打頭的行,你可能會(huì)先用簡(jiǎn)單表達(dá)式he,但是這會(huì)匹配第三行的the,所以要使用正則表達(dá)式^he,它只匹配在行首出現(xiàn)的h。
有時(shí)候指定“除了×××都匹配”會(huì)比較容易達(dá)到目的,當(dāng)抑揚(yáng)字符(^)出現(xiàn)在方括號(hào)中是,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情性(也就是the和she),可以使用:[^st]he。
可以使用方括號(hào)來(lái)指定多個(gè)字符區(qū)間。例如正則表達(dá)式[A-Za-z]匹配任何字母,包括大寫和小寫的;正則表達(dá)式[A-Za-z][A-Za-z]* 匹配一個(gè)字母后面接著0或者多個(gè)字母(大寫或者小寫)。當(dāng)然我們也可以用元字符+做到同樣的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等價(jià)。但是要注意元字符+ 并不是所有支持正則表達(dá)式的程序都支持的。關(guān)于這一點(diǎn)可以參考后面的正則表達(dá)式語(yǔ)法支持情況。
要指定特定數(shù)量的匹配,要使用大括號(hào)(注意必須使用反斜杠來(lái)轉(zhuǎn)義)。想匹配所有100和1000的實(shí)例而排除10和10000,可以使用:10\{2,3\},這個(gè)正則表達(dá)式匹配數(shù)字1后面跟著2或者3個(gè)0的模式。在這個(gè)元字符的使用中一個(gè)有用的變化是忽略第二個(gè)數(shù)字,例如正則表達(dá)式0\{3,\} 將匹配至少3個(gè)連續(xù)的0。
簡(jiǎn)單的例子
這里有一些有代表性的、比較簡(jiǎn)單的例子。
vi 命令 |
作用 |
|
|
:%s/ */ /g |
把一個(gè)或者多個(gè)空格替換為一個(gè)空格。 |
:%s/ *$// |
去掉行尾的所有空格。 |
:%s/^/ / |
在每一行頭上加入一個(gè)空格。 |
:%s/^[0-9][0-9]* // |
去掉行首的所有數(shù)字字符。 |
:%s/b[aeio]g/bug/g |
將所有的bag、beg、big和bog改為bug。 |
:%s/t\([aou]\)g/h\1t/g |
將所有tag、tog和tug分別改為hat、hot和hug(注意用group的用法和使用\1引用前面被匹配的字符)。 |
|
|
中級(jí)的例子(神奇的咒語(yǔ))
例1
將所有方法foo(a,b,c)的實(shí)例改為foo(b,a,c)。這里a、b和c可以是任何提供給方法foo()的參數(shù)。也就是說(shuō)我們要實(shí)現(xiàn)這樣的轉(zhuǎn)換:
之前 |
|
之后 |
foo(10,7,2) |
|
foo(7,10,2) |
foo(x+13,y-2,10) |
|
foo(y-2,x+13,10) |
foo( bar(8), x+y+z, 5) |
|
foo( x+y+z, bar(8), 5) |
下面這條替換命令能夠?qū)崿F(xiàn)這一魔法:
:%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo(\2,\1,\3)/g
現(xiàn)在讓我們把它打散來(lái)加以分析。寫出這個(gè)表達(dá)式的基本思路是找出foo()和它的括號(hào)中的三個(gè)參數(shù)的位置。第一個(gè)參數(shù)是用這個(gè)表達(dá)式來(lái)識(shí)別的::\([^,]*\),我們可以從里向外來(lái)分析它:
[^,] |
|
除了逗號(hào)之外的任何字符 |
[^,]* |
|
0或者多個(gè)非逗號(hào)字符 |
\([^,]*\) |
|
將這些非逗號(hào)字符標(biāo)記為\1,這樣可以在之后的替換模式表達(dá)式中引用它 |
\([^,]*\), |
|
我們必須找到0或者多個(gè)非逗號(hào)字符后面跟著一個(gè)逗號(hào),并且非逗號(hào)字符那部分要標(biāo)記出來(lái)以備后用。 |
現(xiàn)在正是指出一個(gè)使用正則表達(dá)式常見(jiàn)錯(cuò)誤的最佳時(shí)機(jī)。為什么我們要使用[^,]*這樣的一個(gè)表達(dá)式,而不是更加簡(jiǎn)單直接的寫法,例如:.*,來(lái)匹配第一個(gè)參數(shù)呢?設(shè)想我們使用模式.*來(lái)匹配字符串"10,7,2",它應(yīng)該匹配"10,"還是"10,7,"?為了解決這個(gè)兩義性(ambiguity),正則表達(dá)式規(guī)定一律按照最長(zhǎng)的串來(lái),在上面的例子中就是"10,7,",顯然這樣就找出了兩個(gè)參數(shù)而不是我們期望的一個(gè)。所以,我們要使用[^,]*來(lái)強(qiáng)制取出第一個(gè)逗號(hào)之前的部分。
這個(gè)表達(dá)式我們已經(jīng)分析到了:foo(\([^,]*\),這一段可以簡(jiǎn)單的翻譯為“當(dāng)你找到foo(就把其后直到第一個(gè)逗號(hào)之前的部分標(biāo)記為\1”。然后我們使用同樣的辦法標(biāo)記第二個(gè)參數(shù)為\2。對(duì)第三個(gè)參數(shù)的標(biāo)記方法也是一樣,只是我們要搜索所有的字符直到右括號(hào)。我們并沒(méi)有必要去搜索第三個(gè)參數(shù),因?yàn)槲覀儾恍枰{(diào)整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個(gè)參數(shù)的foo()方法調(diào)用,在foo()是一個(gè)重載(overoading)方法時(shí)這種明確的模式往往是比較保險(xiǎn)的。然后,在替換部分,我們找到foo()的對(duì)應(yīng)實(shí)例,然后利用標(biāo)記好的部分進(jìn)行替換,是的第一和第二個(gè)參數(shù)交換位置。
例2
假設(shè)有一個(gè)CSV(comma separated value)文件,里面有一些我們需要的信息,但是格式卻有問(wèn)題,目前數(shù)據(jù)的列順序是:姓名,公司名,州名縮寫,郵政編碼,現(xiàn)在我們希望講這些數(shù)據(jù)重新組織,以便在我們的某個(gè)軟件中使用,需要的格式為:姓名,州名縮寫-郵政編碼,公司名。也就是說(shuō),我們要調(diào)整列順序,還要合并兩個(gè)列來(lái)構(gòu)成一個(gè)新列。另外,我們的軟件不能接受逗號(hào)前后面有任何空格(包括空格和制表符)所以我們還必須要去掉逗號(hào)前后的所有空格。
這里有幾行我們現(xiàn)在的數(shù)據(jù):
Bill Jones, HI-TEK Corporation , CA, 95011
Sharon Lee Smith, Design Works Incorporated, CA, 95012
B. Amos , Hill Street Cafe, CA, 95013
Alexander Weatherworth, The Crafts Store, CA, 95014
...
我們希望把它變成這個(gè)樣子:
Bill Jones,CA 95011,HI-TEK Corporation
Sharon Lee Smith,CA 95012,Design Works Incorporated
B. Amos,CA 95013,Hill Street Cafe
Alexander Weatherworth,CA 95014,The Crafts Store
...
我們將用兩個(gè)正則表達(dá)式來(lái)解決這個(gè)問(wèn)題。第一個(gè)移動(dòng)列和合并列,第二個(gè)用來(lái)去掉空格。
下面就是第一個(gè)替換命令:
:%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/\1,\3 \4,\2/
這里的方法跟例1基本一樣,第一個(gè)列(姓名)用這個(gè)表達(dá)式來(lái)匹配: \([^,]*\),即第一個(gè)逗號(hào)之前的所有字符,而姓名內(nèi)容被用 \1標(biāo)記下來(lái)。公司名和州名縮寫字段用同樣的方法標(biāo)記為 \2和 \3,而最后一個(gè)字段用 \(.*\)來(lái)匹配("匹配所有字符直到行末")。替換部分則引用上面標(biāo)記的那些內(nèi)容來(lái)進(jìn)行構(gòu)造。
下面這個(gè)替換命令則用來(lái)去除空格:
我們還是分解來(lái)看: [ \t]匹配空格/制表符, [ \t]* 匹配0或多個(gè)空格/制表符, [ \t]*,匹配0或多個(gè)空格/制表符后面再加一個(gè)逗號(hào),最后, [ \t]*,[ \t]*匹配0或多個(gè)空格/制表符接著一個(gè)逗號(hào)再接著0或多個(gè)空格/制表符。在替換部分,我們簡(jiǎn)單的我們找到的所有東西替換成一個(gè)逗號(hào)。這里我們使用了結(jié)尾的可選的 g參數(shù),這表示在每行中對(duì)所有匹配的串執(zhí)行替換(而不是缺省的只替換第一個(gè)匹配串)。
例3
假設(shè)有一個(gè)多字符的片斷重復(fù)出現(xiàn),例如:
Billy tried really hard
Sally tried really really hard
Timmy tried really really really hard
Johnny tried really really really really hard 而你想把"really"、"really really",以及任意數(shù)量連續(xù)出現(xiàn)的"really"字符串換成一個(gè)簡(jiǎn)單的"very"(simple is good!),那么以下命令:
:%s/\(really \)\(really \)*/very / 就會(huì)把上述的文本變成:
Billy tried very hard
Sally tried very hard
Timmy tried very hard
Johnny tried very hard 表達(dá)式 \(really \)*匹配0或多個(gè)連續(xù)的"really "(注意結(jié)尾有個(gè)空格),而 \(really \)\(really \)* 匹配1個(gè)或多個(gè)連續(xù)的"really "實(shí)例。
困難的例子(不可思議的象形文字)
Coming soon.
不同工具中的正則表達(dá)式
OK,你已經(jīng)準(zhǔn)備使用RE(regular expressions,正則表達(dá)式),但是你并準(zhǔn)備使用vi。所以,在這里我們給出一些在其他工具中使用RE的例子。另外,我還會(huì)總結(jié)一下你在不同程序之間使用RE可能發(fā)現(xiàn)的區(qū)別。
當(dāng)然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,F(xiàn)ind What輸入框?qū)?yīng)上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框?qū)?yīng)pat2部分。但是,為了得到vi的執(zhí)行范圍和g選項(xiàng),你要使用Replace All或者適當(dāng)?shù)氖止ind Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個(gè)范圍的文本,然后在其中執(zhí)行替換,但是總之不夠vi那么靈活和典雅)。
sed
Sed是Stream EDitor的縮寫,是Unix下常用的基于文件和管道的編輯工具,可以在手冊(cè)中得到關(guān)于sed的詳細(xì)信息。
這里是一些有趣的sed腳本,假定我們正在處理一個(gè)叫做price.txt的文件。注意這些編輯并不會(huì)改變?cè)次募瑂ed只是處理源文件的每一行并把結(jié)果顯示在標(biāo)準(zhǔn)輸出中(當(dāng)然很容易使用重定向來(lái)定制):
sed腳本 |
|
描述 |
|
|
|
sed 's/^$/d' price.txt |
|
刪除所有空行 |
sed 's/^[ \t]*$/d' price.txt |
|
刪除所有只包含空格或者制表符的行 |
sed 's/"http://g' price.txt |
|
刪除所有引號(hào) |
awk
awk是一種編程語(yǔ)言,可以用來(lái)對(duì)文本數(shù)據(jù)進(jìn)行復(fù)雜的分析和處理。可以在手冊(cè)中得到關(guān)于awk的詳細(xì)信息。這個(gè)古怪的名字是它作者們的姓的縮寫(Aho,Weinberger和Kernighan)。
在Aho,Weinberger和Kernighan的書(shū)The AWK Programming Language中有很多很好的awk的例子,請(qǐng)不要讓下面這些微不足道的腳本例子限制你對(duì)awk強(qiáng)大能力的理解。我們同樣假定我們針對(duì)price.txt文件進(jìn)行處理,跟sed一樣,awk也只是把結(jié)果顯示在終端上。
awk腳本 |
|
描述 |
|
|
|
awk '$0 !~ /^$/' price.txt |
|
刪除所有空行 |
awk 'NF > 0' price.txt |
|
awk中一個(gè)更好的刪除所有行的辦法 |
awk '$2 ~ /^[JT]/ {print $3}' price.txt |
|
打印所有第二個(gè)字段是'J'或者'T'打頭的行中的第三個(gè)字段 |
awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt |
|
針對(duì)所有第二個(gè)字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定為數(shù)字) |
awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt |
|
打印所有第三個(gè)字段不是數(shù)字的行,這里數(shù)字是指d.d或者d這樣的形式,其中d是0到9的任何數(shù)字 |
awk '$2 ~ /John|Fred/ {print $0}' price.txt |
|
如果第二個(gè)字段包含'John'或者'Fred'則打印整行 |
grep
grep是一個(gè)用來(lái)在一個(gè)或者多個(gè)文件或者輸入流中使用RE進(jìn)行查找的程序。它的name編程語(yǔ)言可以用來(lái)針對(duì)文件和管道進(jìn)行處理。可以在手冊(cè)中得到關(guān)于grep的完整信息。這個(gè)同樣古怪的名字來(lái)源于vi的一個(gè)命令, g/re/p,意思是 global regular expression print。
下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個(gè)逗號(hào),然后是名,然后是一個(gè)制表符,然后是電話號(hào)碼:
Francis, John 5-3871
Wong, Fred 4-4123
Jones, Thomas 1-4122
Salazar, Richard 5-2522
grep命令 |
|
描述 |
|
|
|
grep '\t5-...1' phone.txt |
|
把所有電話號(hào)碼以5開(kāi)頭以1結(jié)束的行打印出來(lái),注意制表符是用\t表示的 |
grep '^S[^ ]* R' phone.txt |
|
打印所有姓以S打頭和名以R打頭的行 |
grep '^[JW]' phone.txt |
|
打印所有姓開(kāi)頭是J或者W的行 |
grep ', ....\t' phone.txt |
|
打印所有姓是4個(gè)字符的行,注意制表符是用\t表示的 |
grep -v '^[JW]' phone.txt |
|
打印所有不以J或者W開(kāi)頭的行 |
grep '^[M-Z]' phone.txt |
|
打印所有姓的開(kāi)頭是M到Z之間任一字符的行 |
grep '^[M-Z].*[12]' phone.txt |
|
打印所有姓的開(kāi)頭是M到Z之間任一字符,并且點(diǎn)號(hào)號(hào)碼結(jié)尾是1或者2的行 |
egrep
egrep是grep的一個(gè)擴(kuò)展版本,它在它的正則表達(dá)式中支持更多的元字符。下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個(gè)逗號(hào),然后是名,然后是一個(gè)制表符,然后是電話號(hào)碼:
Francis, John 5-3871
Wong, Fred 4-4123
Jones, Thomas 1-4122
Salazar, Richard 5-2522
egrep command |
|
Description |
|
|
|
egrep '(John|Fred)' phone.txt |
|
打印所有包含名字John或者Fred的行 |
egrep 'John|22$|^W' phone.txt |
|
打印所有包含John 或者以22結(jié)束或者以W的行 |
egrep 'net(work)?s' report.txt |
|
從report.txt中找到所有包含networks或者nets的行 |
正則表達(dá)式語(yǔ)法支持情況
命令或環(huán)境 |
. |
[ ] |
^ |
$ |
\( \) |
\{ \} |
? |
+ |
| |
( ) |
vi |
X |
X |
X |
X |
X |
|
|
|
|
|
Visual C++ |
X |
X |
X |
X |
X |
|
|
|
|
|
awk |
X |
X |
X |
X |
|
|
X |
X |
X |
X |
sed |
X |
X |
X |
X |
X |
X |
|
|
|
|
Tcl |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
ex |
X |
X |
X |
X |
X |
X |
|
|
|
|
grep |
X |
X |
X |
X |
X |
X |
|
|
|
|
egrep |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
fgrep |
X |
X |
X |
X |
X |
|
|
|
|
|
perl |
X |
X |
X |
X |
X |
|
X |
X |
X |
X |
vi替換命令簡(jiǎn)介
Vi的替換命令:
其中
網(wǎng)上有很多vi的在線手冊(cè),你可以訪問(wèn)他們以獲得更加完整的信息。
已知: 字段A='F:\photo\Winter Leaves.jpg'
要求:分段截取每段字符[字段A不能為TEXT類型,否則報(bào)錯(cuò)]
解決方法:
+++++++++++++++++++++++++++++++++++++++++++++++++++
---截取字符串A的第一個(gè)\左邊的字符串
select left(A,charindex('/',A)-1)
輸出結(jié)果:F:
++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取\中間的字符串
select left(stuff(A,1,charindex('/',A),''),charindex('/',stuff(A,1,charindex('/',A),''))-1)
輸出結(jié)果:photo
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取最后一個(gè)\后面的字符串
select reverse(left(reverse(A),charindex('/',reverse(A))-1))
輸出結(jié)果:Winter Leaves.jpg
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
---截取字符串A的首字幕
select STUFF(A,1, 1, '')
輸出結(jié)果::\photo\Winter Leaves.jpg
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
把你的光標(biāo)放到相應(yīng)文字上查看效果
|
要注意光標(biāo)的實(shí)際效果依賴于用戶的系統(tǒng)設(shè)置,與你在這里看到的效果并不一定一致。
|
cursor: crosshair;
|
|
十字準(zhǔn)心
|
The cursor render as a crosshair
游標(biāo)表現(xiàn)為十字準(zhǔn)線
|
cursor: pointer;
cursor: hand;
寫兩個(gè)是為了照顧IE5,它只認(rèn)hand。
|
|
手
|
The cursor render as a pointer (a hand) that indicates a link
游標(biāo)以暗示(手指)的形式來(lái)表明有一個(gè)連接
|
cursor: wait;
|
|
等待/沙漏
|
The cursor indicates that the program is busy (often a watch or an hourglass)
游標(biāo)暗示當(dāng)前程序正忙(一般為一塊表或是一個(gè)沙漏)
|
cursor: help;
|
|
幫助
|
The cursor indicates that help is available (often a question mark or a balloon)
游標(biāo)暗示當(dāng)前位置可得到幫助(一般為問(wèn)號(hào)或是氣球)
|
cursor: no-drop;
|
|
無(wú)法釋放
|
cursor: no-drop;
|
cursor: text;
|
|
文字/編輯
|
The cursor indicates text
游標(biāo)暗示當(dāng)前所處位置為文字內(nèi)容
|
cursor: move;
|
|
可移動(dòng)對(duì)象
|
The cursor indicates something that should be moved
游標(biāo)暗示一些東西應(yīng)該被移動(dòng)
|
cursor: n-resize;
|
|
向上改變大小(North)
|
The cursor indicates that an edge of a box is to be moved up (north)
邊緣可向上移動(dòng)(北)
|
cursor: s-resize;
|
|
向下改變大小(South)
|
The cursor indicates that an edge of a box is to be moved down (south)
邊緣可向下方移動(dòng)(南)
|
cursor: e-resize;
|
|
向右改變大小(East)
|
The cursor indicates that an edge of a box is to be moved right (east)
box邊緣可向右(東)邊移動(dòng)
|
cursor: w-resize;
|
|
向左改變大小(West)
|
The cursor indicates that an edge of a box is to be moved left (west)
邊緣可向左移動(dòng)(西)
|
cursor: ne-resize;
|
|
向上右改變大小(North East)
|
The cursor indicates that an edge of a box is to be moved up and right (north/east)
游標(biāo)暗示box的邊緣可向右上方移動(dòng)(東北方向)
|
cursor: nw-resize;
|
|
向上左改變大小(North West)
|
The cursor indicates that an edge of a box is to be moved up and left (north/west)
邊緣可向左上方移動(dòng)(西北)
|
cursor: se-resize;
|
|
向下右改變大小(South East)
|
The cursor indicates that an edge of a box is to be moved down and right (south/east)
邊緣可向右下方移動(dòng)(東南)
|
cursor: sw-resize;
|
|
向下左改變大小(South West)
|
The cursor indicates that an edge of a box is to be moved down and left (south/west)
邊緣可向左下方移動(dòng)(西南)
|
cursor: auto;
|
|
自動(dòng)
|
The browser sets a cursor
瀏覽器設(shè)置一個(gè)游標(biāo)
|
cursor:not-allowed;
|
|
禁止
|
cursor:not-allowed;
|
cursor: progress;
|
|
處理中
|
cursor: progress;
|
cursor: default;
|
|
系統(tǒng)默認(rèn)
|
The default cursor (often an arrow)
默認(rèn)的游標(biāo)狀態(tài)(通常為一個(gè)箭頭)
|
cursor: url(' # ');
# = 光標(biāo)文件地址 (注意文件格式必須為:.cur 或 .ani)。
|
|
用戶自定義(可用動(dòng)畫(huà))
|
The url of a custom cursor to be used.
自定義游標(biāo)的url位置
Note: Always define a generic cursor at the end of the list in case none of the url-defined cursors can be used
注意:在定義完自定義的游標(biāo)之后在末尾加上一般性的游標(biāo),以防那些url所定義的游標(biāo)不能使用
|
Logo生成網(wǎng)站:
天空秘書(shū)網(wǎng),J/m!h._HK&Rq 強(qiáng)烈推薦:http://www.logomaker.cn
http://phorum.com.tw/Generator.aspx 天空秘書(shū)網(wǎng),VK2V#J&t#W`*A http://www.logoyes.com/lc_leftframe.htm 天空秘書(shū)網(wǎng)&jD-L|;X+O8c http://cooltext.com/Default.aspx
Banner圖片制作網(wǎng)站:
http://www.bannerbreak.com/index.php
在線圖片生成網(wǎng)站:
http://www.streetsigngenerator.com/ %u` U l5e&Bt;Fd0http://www.letterjames.de/
圖片分割器: http://www.html-kit.com/e/is.cgi
立體圖片生成器: http://www.chami.com/html-kit/services/imge/
圖片生成郵票: http://photo.stamps.com/PhotoStamps/?source=si00001331
個(gè)性拼圖: http://www.jigcool.com/jigonline/jigonline1_sc.php
印章制作: http://caishu.sina.com.cn/
GIF圖片的文字LOGO在線生成:http://www.3dtextmaker.com/cgi-bin/3dtext.pl
在線制作logo,bannar的網(wǎng)站:http://www.crazystudy.com
SAINT.Assess the Security of Computer Networks :http://www.saintcorporation.com/saint/
Abacus.Intrusion Prevention System :http://www.psionic.com/abacus/
Firewall Generator(在線生成簡(jiǎn)單的防火墻腳本)
http://www.citadec.com/FirewallGenerator.html
在線字體圖片生成:http://www.youmade.com/font/
在線生成條碼打印
http://www.027hc.com/y1.asp [tG+|$M{~/@"dV0http://www.nlscan.com/soucecentre/demo.asp #U|TA I%F Ts0http://www.gzbonny.com/asp/barcode.asp
在線圖形特效生成:http://www.chami.com/
聊天工具在線狀態(tài)生成器:http://www.onlinestatus.org/forum/usage.php
粉絲身份證:http://id.igogo8.com/
制作印章:http://www.makepic.com/print.php
郵址圖片生成:http://www.makepic.com/email.php
條形碼生成:http://www.makepic.com/barcode.php
Kiss學(xué)堂 頒發(fā)結(jié)業(yè)證:http://www.makepic.com/kiss/cert.php
生成頭像:http://www.eoool.com/ImageDIY/DIYChooseImg.aspx?ImgSize=96x96x1
郵件:http://www.eoool.com/Sevice.aspx?TypeID=1
聊天圖標(biāo):http://www.eoool.com/Sevice.aspx?TypeID=2
博客圖標(biāo):http://www.eoool.com/Sevice.aspx?TypeID=3
網(wǎng)絡(luò)書(shū)簽:http://www.eoool.com/Sevice.aspx?TypeID=5
朋友圈:http://www.eoool.com/Sevice.aspx?TypeID=4
按扭:http://www.eoool.com/Sevice.aspx?TypeID=11
生成拼湊圖:http://blog.outer-court.com/letters/
一個(gè)日本武士刀劈出你需要的字:
http://tools.fodey.com/generators/animated/ninjatext.asp
生成幾種卡通人物對(duì)話動(dòng)態(tài)圖片:
http://tools.fodey.com/generators/animated/talking_squirrel.asp天空秘書(shū)網(wǎng)P R_9]H,|,x
^0g3pI#}5l;z.v`F0香煙盒生成,可以做警告圖片:http://tools.fodey.com/generators/cigarette_packet/generator.cig
支持多種域名的Email圖標(biāo)的生成: http://www.nhacks.com/email/
兩個(gè)地址支持兩種風(fēng)格任意文本的Email圖標(biāo)的生成:
http://sagittarius.dip.jp/~toshi/cgi-bin/designmail/designmail.html天空秘書(shū)網(wǎng)Q T2z6^9~ \8kZ g'IW http://sagittarius.dip.jp/~toshi/cgi-bin/catmark/catmark.html
在線favicon生成器: http://www.html-kit.com/e/favicon.cgi
支持各種類型圖片的生成,可以選擇設(shè)置的條件非常靈活:
http://www.abi-station.com/tchinese/
支持大量中文字體簽名圖標(biāo)生成: http://www.youmade.com/font/
Flickr雜志封面生成器: http://flagrantdisregard.com/flickr/magazine.php
動(dòng)態(tài)生成有趣圖片:
愛(ài)因斯坦:http://www.hetemeel.com/einsteinform.php
山姆大叔:http://www.hetemeel.com/unclesamform.php
辭典:http://www.hetemeel.com/dictionaryform.php
魔法師:http://www.imagegenerator.net/create/dumbledore/
Flickr Logo風(fēng)格圖片生成器::http://flickr.nosv.org/
按鈕生成網(wǎng)站:
http://kalsey.com/tools/buttonmaker/ %u"l*FdqLp X8K9A6Z]0http://www.lucazappa.com/brilliantMaker/buttonImage.php天空秘書(shū)網(wǎng)A,W!s)[c{ http://www.feedforall.com/public/rss-graphic-tool.htm天空秘書(shū)網(wǎng)L|e"j*BP8kS0A http://www.kalsey.com/tools/buttonmaker/ y$A Si1Y&N/Z0http://www.yugatech.com/make.php天空秘書(shū)網(wǎng)R SS2_ E^9[.O http://www.hkwebs.net/catalog/tools/buttonmaker/index.php
Email圖標(biāo)生成網(wǎng)站::
http://email.playtime.uni.cc/ :y]~5d'[d3L Y+k$j0http://services.nexodyne.com/email/ 6nPlesL0http://gizmo967.mgs3.org/Gmail/ R-GD kl3[z0http://www.hkwebs.net/catalog/tools/gmail/ 天空秘書(shū)網(wǎng);N5ha5a*V`P3` http://sagittarius.dip.jp/~toshi/cgi-bin/designmail/designmail.html ~z'Z'GK%h4cq0http://www.eoool.com/
匹配中文字符的正則表達(dá)式: [\u4e00-\u9fa5]
匹配雙字節(jié)字符(包括漢字在內(nèi)):[^\x00-\xff]
應(yīng)用:計(jì)算字符串的長(zhǎng)度(一個(gè)雙字節(jié)字符長(zhǎng)度計(jì)2,ASCII字符計(jì)1)
String.prototype.len=function(){return this.replace([^\x00-\xff]/g,"aa").length;}
匹配空行的正則表達(dá)式:\n[\s| ]*\r
匹配HTML標(biāo)記的正則表達(dá)式:/<(.*)>.*<\/\1>|<(.*) \/>/
匹配首尾空格的正則表達(dá)式:(^\s*)|(\s*$)
應(yīng)用:javascript中沒(méi)有像vbscript那樣的trim函數(shù),我們就可以利用這個(gè)表達(dá)式來(lái)實(shí)現(xiàn),如下:
String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g, ""); }
利用正則表達(dá)式分解和轉(zhuǎn)換IP地址:
下面是利用正則表達(dá)式匹配IP地址,并將IP地址轉(zhuǎn)換成對(duì)應(yīng)數(shù)值的Javascript程序:
function IP2V(ip) { re=/(\d+)\.(\d+)\.(\d+)\.(\d+)/g //匹配IP地址的正則表達(dá)式 if(re.test(ip)) { return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1 } else { throw new Error("Not a valid IP address!") } }
不過(guò)上面的程序如果不用正則表達(dá)式,而直接用split函數(shù)來(lái)分解可能更簡(jiǎn)單,程序如下:
var ip="10.100.20.168" ip=ip.split(".") alert("IP值是:"+(ip[0]*255*255*255+ip[1]*255*255+ip[2]*255+ip[3]*1))
匹配Email地址的正則表達(dá)式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配網(wǎng)址URL的正則表達(dá)式:http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?
利用正則表達(dá)式去除字串中重復(fù)的字符的算法程序:
var s="abacabefgeeii" var s1=s.replace(/(.).*\1/g,"$1") var re=new RegExp("["+s1+"]","g") var s2=s.replace(re,"") alert(s1+s2) //結(jié)果為:abcefgi
我原來(lái)在CSDN上發(fā)貼尋求一個(gè)表達(dá)式來(lái)實(shí)現(xiàn)去除重復(fù)字符的方法,最終沒(méi)有找到,這是我能想到的最簡(jiǎn)單的實(shí)現(xiàn)方法。思路是使用后向引用取出包括重復(fù)的字符,再以重復(fù)的字符建立第二個(gè)表達(dá)式,取到不重復(fù)的字符,兩者串連。這個(gè)方法對(duì)于字符順序有要求的字符串可能不適用。
得用正則表達(dá)式從URL地址中提取文件名的javascript程序,如下結(jié)果為page1
s="http://www.gzcynet/page1.htm" s=s.replace(/(.*\/){0,}([^\.]+).*/ig,"$2") alert(s)
利用正則表達(dá)式限制網(wǎng)頁(yè)表單里的文本框輸入內(nèi)容:
用正則表達(dá)式限制只能輸入中文:onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"
用正則表達(dá)式限制只能輸入全角字符: onkeyup="value=value.replace(/[^\uFF00-\uFFFF]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\uFF00-\uFFFF]/g,''))"
用正則表達(dá)式限制只能輸入數(shù)字:onkeyup="value=value.replace(/[^\d]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
用正則表達(dá)式限制只能輸入數(shù)字和英文:onkeyup="value=value.replace(/[\W]/g,'') "onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))"
下面四個(gè)都是檢查email的...
^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$
^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$
^.+@[^\.].*\.[a-z]{2,}$
^[\w\.=-]+@[\w\.-]+\.[\w]{2,3}$
模型驅(qū)動(dòng)架構(gòu)(MDA)是一種獨(dú)立于特定平臺(tái)和軟件供應(yīng)商的軟件體系結(jié)構(gòu)設(shè)計(jì)和開(kāi)發(fā)方法,它適用于設(shè)計(jì)、部署、集成等軟件開(kāi)發(fā)的整個(gè)生命周期。MDA 遵循的是諸如統(tǒng)一建模語(yǔ)言(UML)、可擴(kuò)展標(biāo)記語(yǔ)言(XML)和公共對(duì)象請(qǐng)求代理體系結(jié)構(gòu)(CORBA)等一系列業(yè)界開(kāi)放標(biāo)準(zhǔn)。
MDA 建模是基于功能,而非基于特定語(yǔ)言、平臺(tái)或?qū)崿F(xiàn)技術(shù),它可以簡(jiǎn)化系統(tǒng)集成、縮短開(kāi)發(fā)周期和節(jié)省企業(yè)資源。
模型通常以圖和文字的形式來(lái)描述一個(gè)系統(tǒng)及其環(huán)境。模型驅(qū)動(dòng)的方法就是利用模型來(lái)引導(dǎo)系統(tǒng)的設(shè)計(jì)、開(kāi)發(fā)和維護(hù)。而模型驅(qū)動(dòng)架構(gòu)即是用系統(tǒng)的模型來(lái)生成系統(tǒng)的體系結(jié)構(gòu)。
MDA 有三個(gè)視圖。第一個(gè)視圖叫“計(jì)算無(wú)關(guān)視圖(CIV)”,其作用就是將系統(tǒng)基本處理邏輯同平臺(tái)相關(guān)的技術(shù)規(guī)范分離開(kāi)來(lái)。CIV視圖關(guān)注于系統(tǒng)的環(huán)境和需求,而系統(tǒng)的具體結(jié)構(gòu)和實(shí)現(xiàn)是隱藏的。
第二個(gè)視圖是“平臺(tái)無(wú)關(guān)視圖(PIV)”。該視圖關(guān)注于系統(tǒng)的操作而隱藏了平臺(tái)相關(guān)的細(xì)節(jié),該視圖可能用一種通用的、平臺(tái)無(wú)關(guān)的建模語(yǔ)言如UML來(lái)描述。
第三個(gè)視圖叫“平臺(tái)相關(guān)視圖(PSV)”。該視圖關(guān)注特定平臺(tái)的實(shí)現(xiàn)細(xì)節(jié)。
以上三個(gè)視圖都有其各自相應(yīng)的模型:
- 計(jì)算無(wú)關(guān)模型(CIM)通常由業(yè)務(wù)分析人員創(chuàng)建,展示了系統(tǒng)的業(yè)務(wù)模型。
- 平臺(tái)無(wú)關(guān)模型(PIM)是系統(tǒng)功能的模型,通常由系統(tǒng)架構(gòu)師創(chuàng)建。
- 平臺(tái)相關(guān)模型(PSM)對(duì)一個(gè)或多個(gè)平臺(tái)的PIM模型的具體實(shí)現(xiàn)建模。
MDA 的真正價(jià)值在于 CIM 模型可以通過(guò)簡(jiǎn)單的映射轉(zhuǎn)換成 PIM 模型。同樣的,PIM 模型也可以映射成 PSM 模型,而 PSM 模型則可以最終轉(zhuǎn)換成具體的實(shí)現(xiàn)代碼。
如下圖所示,右上角的 CIM 模型是整個(gè)模型轉(zhuǎn)換過(guò)程的起點(diǎn)。CIM 模型轉(zhuǎn)換成 PIM 模型后,系統(tǒng)架構(gòu)師和設(shè)計(jì)師即可以創(chuàng)建系統(tǒng)其余部分的模型。設(shè)計(jì)完成之后,PIM 模型就轉(zhuǎn)換成了一個(gè)或多個(gè) PSM 模型。
|

模型驅(qū)動(dòng)架構(gòu) (MDA)
|
MDA 提供了一種優(yōu)雅而可靠的開(kāi)發(fā)框架,這種框架使得系統(tǒng)架構(gòu)師在沒(méi)有考慮到有關(guān)系統(tǒng)實(shí)現(xiàn)的任何細(xì)節(jié)之前就可以事先定義好系統(tǒng)的模型。
MDA 的優(yōu)勢(shì)主要包括如下幾點(diǎn):
- 可移植性 -當(dāng)你創(chuàng)建好一個(gè) PIM 模型之后,創(chuàng)建一個(gè)新的基于該 PIM 模型的 PSM 模型是相當(dāng)容易的。當(dāng)然,你需要到目標(biāo)平臺(tái)的映射規(guī)則和一些連接代碼。
- 跨平臺(tái)的互操作性 - 除了可以將一個(gè)系統(tǒng)模型轉(zhuǎn)化為不同的實(shí)現(xiàn),你也可以使用一種特殊的映射規(guī)則將一個(gè) PIM 模型轉(zhuǎn)化為一個(gè)異構(gòu)的 PSM 模型,在該異構(gòu)模型中,最終的系統(tǒng)是由來(lái)自多個(gè)平臺(tái)的組件構(gòu)建而成的。
- 開(kāi)發(fā)效率 - MDA 是一種極其高效的設(shè)計(jì)和開(kāi)發(fā)方法。使用 MDA 方法可以以更少的人力來(lái)完成原先相同的工作量,或者以原先相同的人力來(lái)完成更多的工作,所有這些都無(wú)需對(duì)開(kāi)發(fā)團(tuán)隊(duì)施加額外的壓力。
- 軟件質(zhì)量 - 使用一種單一的模型來(lái)生成和導(dǎo)出系統(tǒng)的大部分代碼可以極大地降低人為錯(cuò)誤的發(fā)生。
MDA 還有其它更多的優(yōu)勢(shì),如對(duì)新技術(shù)的快速包容、平臺(tái)無(wú)關(guān)性、領(lǐng)域相關(guān)性、降低開(kāi)發(fā)成本和縮短開(kāi)發(fā)周期等等。
|
文件的建立/檢查與刪除 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>文件的建立、檢查與刪除</title> </head> <body> <% String path=request.getRealPath(""); //out.println(path); File f=new File(path,"File.txt"); //out.println(f); //out.println(f.exists());
if(f.exists()){//檢查File.txt是否存在 f.delete();//刪除File.txt文件 out.println(path + "\\File.txt 存在,已刪除。"); }else{ f.createNewFile();//在當(dāng)前目錄下建立一個(gè)名為File.txt的文件 out.println(path + "\\File.txt 不存在,已建立。");//輸出目前所在的目錄路徑 } %>
目錄的建立/檢查與刪除 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>目錄的建立/檢查與刪除</title> </head> <body> <% String path=request.getRealPath(""); path=path + "\\Sub";//將要建立的目錄路徑 File d=new File(path);//建立代表Sub目錄的File對(duì)象,并得到它的一個(gè)引用 if(d.exists()){//檢查Sub目錄是否存在 d.delete(); out.println("Sub目錄存在,已刪除"); }else{ d.mkdir();//建立Sub目錄 out.println("Sub目錄不存在,已建立"); } %> </body> </html>
如何在JSP中處理虛擬目錄 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>JSP中如何處理虛擬目錄</title> </head> <body> 取得虛擬目錄對(duì)應(yīng)的磁盤路徑<br> Web站點(diǎn)主目錄的位置為<font color=#ff0000><%=request.getRealPath("/")%></font><br> JSP網(wǎng)頁(yè)所在的目錄位置<font color=#ff0000><%=request.getRealPath("./")%></font><br> JSP網(wǎng)頁(yè)所在目錄上一層目錄的位置<font color=#ff0000><%=request.getRealPath("../")%></font><br> </body> </html>
文件屬性的取得 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.util.Date,java.io.*"%> <html> <head> <title>文件屬性的取得</title> </head> <body> <% String path=request.getRealPath("/"); File f=new File(path,"ReadData.txt"); if(f.exists()){ %> <%=f.getName()%>的屬性如下:<br><br> 文件長(zhǎng)度為:<%=f.length()%> <%=f.isFile()?"是文件":"不是文件"%><br> <%=f.isDirectory()?"是目錄":"不是目錄"%><br> <%=f.canRead()?"可讀取":"不可讀取"%><br> <%=f.canWrite()?"可寫入":"不可寫入"%><br> <%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br> 文件的最后修改日期為:<%=new Date(f.lastModified())%><br> <% }else{ f.createNewFile();//在當(dāng)前目錄下建立一個(gè)名為ReaData.txt的文件 %> <%=f.getName()%>的屬性如下:<br><br> 文件長(zhǎng)度為:<%=f.length()%> <%=f.isFile()?"是文件":"不是文件"%><br> <%=f.isDirectory()?"是目錄":"不是目錄"%><br> <%=f.canRead()?"可讀取":"不可讀取"%><br> <%=f.canWrite()?"可寫入":"不可寫入"%><br> <%=f.isHidden()?"是隱藏文件":"不是隱藏文件"%><br> 文件的最后修改日期為:<%=new Date(f.lastModified())%><br> <% } %> </body> </html>
取出目錄中文件的方法 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>取出目錄中文件的方法--列出目錄中的文件</title> </head> <body> <% String path=request.getRealPath("/"); File d=new File(path);//建立當(dāng)前目錄中文件的File對(duì)象 File list[]=d.listFiles();//取得代表目錄中所有文件的File對(duì)象數(shù)組 out.println("<font color=#ff0000>" + path + "目錄下的文件:</font><br>"); for(int i=0;i<list.length;i++){ if(list<I>.isFile()){ out.println(list<I>.getName() + "<br>"); } } out.println("<br><font color=#ff0000>" + path + "目錄下的目錄:</font><br>"); for(int i=0;i<list.length;i++){ if(list<I>.isDirectory()){ out.println(list<I>.getName() + "<br>"); } } %> </body> </html>
判斷是否為空白文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>判斷是否為空白文件</title> </head> <body> <% String path=request.getRealPath("/"); out.println(path); FileReader fr=new FileReader(path + "\\AtEnd.txt");//建立FileReader對(duì)象,并實(shí)例化為fr //對(duì)FileReader類生成的對(duì)象使用read()方法,可以從字符流中讀取下一個(gè)字符。 if(fr.read()==-1)//判斷是否已讀到文件的結(jié)尾 { out.print("AtEnd.txt文件中沒(méi)有數(shù)據(jù)<br>"); }else{ out.println("AtEnd.txt文件中有數(shù)據(jù)"); } fr.close(); %> </body> </html>
讀取所有的文件數(shù)據(jù) <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*,java.lang.*"%> <html> <head> <title>讀取所有的文件數(shù)據(jù)</title> </head> <body> <% String path=request.getRealPath("."); FileReader fr=new FileReader(path + "\\ReadData.txt"); //關(guān)鍵在于讀取過(guò)程中,要判斷所讀取的字符是否已經(jīng)到了文件的末尾,并且這個(gè)字符是不是文件中的斷行符,即判斷該字符值是否為13。 int c=fr.read();//從文件中讀取一個(gè)字符 //判斷是否已讀到文件結(jié)尾 while(c!=-1){ out.print((char)c);//輸出讀到的數(shù)據(jù) c=fr.read();//從文件中繼續(xù)讀取數(shù)據(jù) if(c==13){//判斷是否為斷行字符 out.print("<br>");//輸出分行標(biāo)簽 fr.skip(1);//略過(guò)一個(gè)字符 //c=fr.read();//讀取一個(gè)字符 } } fr.close(); %> </body> </html>
一行一行讀取數(shù)據(jù) <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>文件讀取</title> </head> <body> <% String path=request.getRealPath("");//取得當(dāng)前目錄的路徑 FileReader fr=new FileReader(path + "\\file\\inc\\t.txt");//建立FileReader對(duì)象,并實(shí)例化為fr BufferedReader br=new BufferedReader(fr);//建立BufferedReader對(duì)象,并實(shí)例化為br String Line=br.readLine();//從文件讀取一行字符串 //判斷讀取到的字符串是否不為空 while(Line!=null){ out.println(Line + "<br>");//輸出從文件中讀取的數(shù)據(jù) Line=br.readLine();//從文件中繼續(xù)讀取一行數(shù)據(jù) } br.close();//關(guān)閉BufferedReader對(duì)象 fr.close();//關(guān)閉文件 %> </body> </html>
略過(guò)文件中的字符不讀取 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>略過(guò)字節(jié)不讀取</title> </head> <body> <% String path=request.getRealPath("."); FileReader fr=new FileReader(path + "\\ReadData.txt"); fr.skip(2);//跳過(guò)2個(gè)字節(jié) int c=fr.read();//讀取一個(gè)字節(jié) while(c!=-1){ out.print((char)c); c=fr.read(); } fr.close(); %> </body> </html>
將數(shù)據(jù)寫入文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將數(shù)據(jù)寫入文件</title> </head> <body> <% String path=request.getRealPath("."); FileWriter fw=new FileWriter(path + "\\WriteData.txt");//建立FileWriter對(duì)象,并實(shí)例化fw //將字符串寫入文件 fw.write("大家好!"); fw.write("本書(shū)是《JSP編程技巧》"); fw.write("請(qǐng)多多指教!"); fw.write("email:stride@sina.com"); fw.close();
FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr);//建立BufferedReader對(duì)象,并實(shí)例化為br String Line=br.readLine(); //讀取一行數(shù)據(jù) out.println(Line + "<br>"); br.close();//關(guān)閉BufferedReader對(duì)象 fr.close(); %> </body> </html>
將寫入文件的數(shù)據(jù)分行 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將寫入文件的數(shù)據(jù)分行</title> </head> <body> <% String path=request.getRealPath("."); FileWriter fw=new FileWriter(path + "\\WriteData.txt"); BufferedWriter bw=new BufferedWriter(fw); bw.write("大家好!"); bw.write("本書(shū)是《JSP編程技巧》。"); bw.newLine();//斷行 bw.write("請(qǐng)多多指教!"); bw.newLine();//斷行 bw.write("email: stride@sina.com"); bw.flush();//將數(shù)據(jù)更新至文件 fw.close();//關(guān)閉文件流 out.println("寫入文件內(nèi)容為:<br>"); FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr); String Line=br.readLine();//讀取一行數(shù)據(jù) while(Line!=null){ out.println(Line + "<br>"); Line=br.readLine(); } fr.close(); %> </body> </html> 如何將數(shù)據(jù)追加寫入到文件 <%@ page contentType="text/html;charset=gb2312"%> <%@ page import="java.io.*"%> <html> <head> <title>將寫入文件的數(shù)據(jù)分行</title> </head> <body> <% String path=request.getRealPath("."); RandomAccessFile rf=new RandomAccessFile(path + "\\WriteData.txt","rw");//定義一個(gè)類RandomAccessFile的對(duì)象,并實(shí)例化 rf.seek(rf.length());//將指針移動(dòng)到文件末尾 rf.writeBytes("\nAppend a line to the file!"); rf.close();//關(guān)閉文件流 out.println("寫入文件內(nèi)容為:<br>"); FileReader fr=new FileReader(path + "\\WriteData.txt"); BufferedReader br=new BufferedReader(fr);//讀取文件的BufferedRead對(duì)象 String Line=br.readLine(); while(Line!=null){ out.println(Line + "<br>"); Line=br.readLine(); } fr.close();//關(guān)閉文件 %> </body> </html></I></I></I></I>
|