JXL

 JXL(Java Excel API)是一個用來動態讀寫Excel文件的開源框架,利用它可以在任何支持Java的操作系統上動態讀寫Excel文件。JXL的主頁是:http://www.andykhan.com/jexcelapi/,可以在這裡下載到它的最新的版本。
你可以分別通過如下命令
java -jar jxl.jar -xml test.xls
java -jar jxl.jar -cvs test.xls
以xml和cvs格式查看test.xls,這是因為JXL作者實現了一個用來演示的jxl.demo.Demo的類。

當然我們使用JXL主要是用它來動態讀寫Excel文件。現在就來看看JXL在對Excel的讀和寫上都提供了那些支持。
先來看看Excel文件中都有寫上面對像
1 文件對像 2工作簿對像 3 單元格對象。
相應的在JXL中就有Workbook,Sheet ,Cell 。通過這三個對像我們就可以實現Excel文件的讀取工作。
我們先想想一下讀取步驟,不管是什麼樣的Excel操作框架必定都要經歷
1選取Excel文件,2選擇工作簿,3選擇Cell,4讀取信息。
那麼現在就可以看看JXL中這四步驟如何體現:
//通過Workbook的靜態方法getWorkbook選取Excel文件
Workbook workbook = Workbook.getWorkbook(new File(『myfile.xls』));

//通過Workbook的getSheet方法選擇第一個工作簿(從0開始)
Sheet sheet = workbook.getSheet(0);

//通過Sheet方法的getCell方法選擇位置為C2的單元格(兩個參數都從0開始)
Cell c2 = sheet.getCell(2,1);

//通過Cell的getContents方法把單元格中的信息以字符的形式讀取出來
String stringc2 = c2.getContents();

可以看到正是剛才所說的四個步驟。

我們都知道Excel單元格是有格式的,那麼這些信息如何取得。
Cell提供了一個getType方法能夠返回單元格的類型信息,同時JXL提供了一個CellType類用來預設Excel中的類型信息,而且JXL提供了一些Cell類的子類用來分別用來表示各種類型的單元格,如LabelCell,NumberCell,DateCell分別表示字符、數值、日期類型的單元格。所以我們可以這樣寫:
if (c2.getType() == CellType.NUMBER)
{
  NumberCell nc = (NumberCell) c2;
  numberb2 = nc.getValue();
}

最後不要忘記關閉workbook以釋放資源:
workbook.close();
現在總結一下:三個對象,四個步驟,注意格式。就可以輕鬆的從Excel文件中讀取數據。

JAVA Excel API

  
package myexceltest;

import jxl.*;
import java.io.*;
import jxl.write.*;
/**
 * <p>java讀取Excel表格,拷貝、更新Excel工作薄 </p>
 * <p>Description: Java開發人員可以讀取Excel文件的內容,更新Excel工作薄,開發人員
 *     也可以用程序生成新的Excel表格,不過我覺得在我們工作中幾乎沒有這方面需求,我
 *     就不再列出來了,如果有哪位同事需要的話,我再把程序寫出來
 * </p>
 * <p>Copyright: Copyright (c) KongZhong Corparation 2005</p>
 * <p>程序開發環境為jb9</p>
 * @author 張麗鵬
 * @version 1.0
 */

public class Test1 {
  public static void main(String[] args) {
    jxl.Workbook rwb = null;
    try{
      //構建Workbook對像, 只讀Workbook對像
      //直接從本地文件創建Workbook
      //從輸入流創建Workbook
      InputStream is = new FileInputStream(『D:/jb9Test/MyExcelTest/Book1.xls』);
      rwb = Workbook.getWorkbook(is);

      //Sheet(術語:工作表)就是Excel表格左下角的Sheet1,Sheet2,Sheet3但在程序中
      //Sheet的下標是從0開始
      //獲取第一張Sheet表
       Sheet rs = rwb.getSheet(0);
       //獲取Sheet表中所包含的總列數
       int rsColumns = rs.getColumns();
       //獲取Sheet表中所包含的總行數
       int rsRows = rs.getRows();
       //獲取指定單元格的對象引用
       for(int i=0;i<rsRows;i++){
         for(int j=0;j<rsColumns;j++){
           Cell cell = rs.getCell(j,i);
           System.out.print(cell.getContents()+』 『);
         }
         System.out.println();
       }
       //利用已經創建的Excel工作薄創建新的可寫入的Excel工作薄
       jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(『D:/jb9Test/MyExcelTest/Book2.xls』),rwb);
       //讀取第一張工作表
       jxl.write.WritableSheet ws = wwb.getSheet(0);

       //獲得第一個單元格對像
       jxl.write.WritableCell wc = ws.getWritableCell(0, 0);
       //判斷單元格的類型, 做出相應的轉化
       if (wc.getType() == CellType.LABEL) {
         Label l = (Label) wc;
         l.setString(『The value has been modified.』);
       }
       //寫入Excel對像
       wwb.write();
       wwb.close();

    }catch(Exception e){
      e.printStackTrace();
    }
    finally{
      //操作完成時,關閉對象,釋放佔用的內存空間
      rwb.close();

    }
  }
}
 

JAVA控制EXCEL的方法

JAVA控制EXCEL的方法之一
使用Windows作業系統的朋友對Excel(試算表)一定不會陌生,但是要使用Java語言來操縱Excel檔並不是一件容易的事。在Web應用日益盛行的今天,通過Web來操作Excel檔的需求越來越強烈,目前較為流行的操作是在JSP或Servlet 中創建一個CSV (comma separated values)檔,並將這個檔以MIME,text/csv類型返回給流覽器,接著流覽器調用Excel並且顯示CSV檔。這樣只是說可以訪問到Excel檔,但是還不能真正的操縱Excel檔,本文將給大家一個驚喜,向大家介紹一個開放源碼項目??Java Excel API,使用它大家就可以方便地操縱Excel檔了。
JAVA EXCEL API簡介
  Java Excel是一開放源碼專案,通過它Java開發人員可以讀取Excel檔的內容、創建新的Excel檔、更新已經存在的Excel檔。使用該API非Windows作業系統也可以通過純Java應用來處理Excel資料表。因為是使用Java編寫的,所以我們在Web應用中可以通過JSP、Servlet來調用API實現對Excel資料表的訪問。 現在發佈的穩定版本是V2.0,提供以下功能:
? 從Excel 95、97、2000等格式的檔中讀取資料;
? 讀取Excel公式(可以讀取Excel 97以後的公式);
? 生成Excel資料表(格式為Excel 97);
? 支援字體、數位、日期的格式化;
? 支援單格的陰影操作,以及顏色操作;
? 修改已經存在的資料表;
? 現在還不支援以下功能,但不久就會提供了:
? 不能夠讀取圖表資訊;
可以讀,但是不能生成公式,任何類型公式最後的計算值都可以讀出;
應用示例
從Excel檔讀取資料表
Java Excel API既可以從本地檔系統的一個檔(.xls),也可以從輸入流中讀取Excel資料表。讀取Excel資料表的第一步是創建Workbook(術語:工作薄),下面的代碼片段舉例說明了應該如何操作:(完整代碼見ExcelReading.java)
import java.io.*;
import jxl.*;
… … … …
try
{
//構建Workbook物件, 唯讀Workbook物件
//直接從本地檔創建Workbook
//從輸入流創建Workbook
InputStream is = new FileInputStream(sourcefile);
jxl.Workbook rwb = Workbook.getWorkbook(is);
}
catch (Exception e)
{
e.printStackTrace();
}
  一旦創建了Workbook,我們就可以通過它來訪問Excel Sheet(術語:工作表)。參考下面的代碼片段:
//獲取第一張Sheet表
Sheet rs = rwb.getSheet(0);
  我們既可能通過Sheet的名稱來訪問它,也可以通過下標來訪問它。如果通過下標來訪問的話,要注意的一點是下標從0開始,就像陣列一樣。
  一旦得到了Sheet,我們就可以通過它來訪問Excel Cell(術語:單格)。參考下面的代碼片段:
//獲取第一行,第一列的值
Cell c00 = rs.getCell(0, 0);
String strc00 = c00.getContents();
//獲取第一行,第二列的值
Cell c10 = rs.getCell(1, 0);
String strc10 = c10.getContents();
//獲取第二行,第二列的值
Cell c11 = rs.getCell(1, 1);
String strc11 = c11.getContents();
System.out.println(『Cell(0, 0)』 + 』 value : 』 + strc00 + 『; type : 』 +
c00.getType());
System.out.println(『Cell(1, 0)』 + 』 value : 』 + strc10 + 『; type : 』 +
c10.getType());
System.out.println(『Cell(1, 1)』 + 』 value : 』 + strc11 + 『; type : 』 +
c11.getType());
  如果僅僅是取得Cell的值,我們可以方便地通過getContents()方法,它可以將任何類型的Cell值都作為一個字串返回。示例代碼中Cell(0, 0)是文本型,Cell(1, 0)是數字型,Cell(1,1)是日期型,通過getContents(),三種類型的返回值都是字元型。
  如果有需要知道Cell內容的確切類型,API也提供了一系列的方法。參考下面的代碼片段:
String strc00 = null;
double strc10 = 0.00;
Date strc11 = null;
Cell c00 = rs.getCell(0, 0);
Cell c10 = rs.getCell(1, 0);
Cell c11 = rs.getCell(1, 1);
if(c00.getType() == CellType.LABEL)
{
LabelCell labelc00 = (LabelCell)c00;
strc00 = labelc00.getString();
}
if(c10.getType() == CellType.NUMBER)
{
NmberCell numc10 = (NumberCell)c10;
strc10 = numc10.getvalue();
}
if(c11.getType() == CellType.DATE)
{
DateCell datec11 = (DateCell)c11;
strc11 = datec11.getDate();
}
System.out.println(『Cell(0, 0)』 + 』 value : 』 + strc00 + 『; type : 』 +
c00.getType());
System.out.println(『Cell(1, 0)』 + 』 value : 』 + strc10 + 『; type : 』 +
c10.getType());
System.out.println(『Cell(1, 1)』 + 』 value : 』 + strc11 + 『; type : 』 +
c11.getType());
  在得到Cell物件後,通過getType()方法可以獲得該單格的類型,然後與API提供的基本類型相匹配,強制轉換成相應的類型,最後調用相應的取值方法getXXX(),就可以得到確定類型的值。API提供了以下基本類型,與Excel的資料格式相對應。
每種類型的具體意義,請參見Java Excel API Document。
當你完成對Excel試算表資料的處理後,一定要使用close()方法來關閉先前創建的物件,以釋放讀取資料表的過程中所佔用的記憶體空間,在讀取大量資料時顯得尤為重要。參考如下代碼片段:
//操作完成時,關閉物件,釋放佔用的記憶體空間
rwb.close();
Java Excel API提供了許多訪問Excel資料表的方法,在這裏我只簡要地介紹幾個常用的方法,其他的方法請參考附錄中的Java Excel API Document。
? Workbook類提供的方法
1. int getNumberOfSheets()
獲得工作薄(Workbook)中工作表(Sheet)的個數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
int sheets = rwb.getNumberOfSheets();
2. Sheet[] getSheets()
返回工作薄(Workbook)中工作表(Sheet)物件陣列,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
Sheet[] sheets = rwb.getSheets();
3. String getVersion()
返回正在使用的API的版本號,好像是沒什麼太大的作用。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
String apiVersion = rwb.getVersion();
? Sheet介面提供的方法
1. String getName()
獲取Sheet的名稱,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
String sheetName = rs.getName();
2. int getColumns()
獲取Sheet表中所包含的總列數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsColumns = rs.getColumns();
3. Cell[] getColumn(int column)
獲取某一列的所有單格,返回的是單格物件陣列,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getColumn(0);
4. int getRows()
獲取Sheet表中所包含的總行數,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsRows = rs.getRows();
5. Cell[] getRow(int row)
獲取某一行的所有單格,返回的是單格物件陣列,示例子:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getRow(0);
6. Cell getCell(int column, int row)
獲取指定單格的物件引用,需要注意的是它的兩個參數,第一個是列數,第二個是行數,這與通常的行、列組合有些不同。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell cell = rs.getCell(0, 0);
生成新的Excel工作薄
  下面的代碼主要是向大家介紹如何生成簡單的Excel工作表,在這裏單格的內容是不帶任何修飾的(如:字體,顏色等等),所有的內容都作為字串寫入。(完整代碼見ExcelWriting.java)
  與讀取Excel工作表相似,首先要使用Workbook類的工廠方法創建一個可寫入的工作薄(Workbook)物件,這裏要注意的是,只能通過API提供的工廠方法來創建Workbook,而不能使用WritableWorkbook的構造函數,因為類WritableWorkbook的構造函數為protected類型。示例代碼片段如下:
import java.io.*;
import jxl.*;
import jxl.write.*;
… … … …
try
{
//構建Workbook物件, 唯讀Workbook物件
//Method 1:創建可寫入的Excel工作薄
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile));
//Method 2:將WritableWorkbook直接寫入到輸出流
/*
OutputStream os = new FileOutputStream(targetfile);
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
  API提供了兩種方式來處理可寫入的輸出流,一種是直接生成本地檔,如果檔案名不帶全路徑的話,缺省的檔會定位在當前目錄,如果檔案名帶有全路徑的話,則生成的Excel檔則會定位在相應的目錄;另外一種是將Excel物件直接寫入到輸出流,例如:用戶通過流覽器來訪問Web伺服器,如果HTTP頭設置正確的話,流覽器自動調用用戶端的Excel應用程式,來顯示動態生成的Excel試算表。
  接下來就是要創建工作表,創建工作表的方法與創建工作薄的方法幾乎一樣,同樣是通過工廠模式方法獲得相應的物件,該方法需要兩個參數,一個是工作表的名稱,另一個是工作表在工作薄中的位置,參考下面的代碼片段:
file://創建Excel工作表
jxl.write.WritableSheet ws = wwb.createSheet(『Test Sheet 1″, 0);
  』這鍋也支好了,材料也準備齊全了,可以開始下鍋了!』,現在要做的只是實例化API所提供的Excel基本資料類型,並將它們添加到工作表中就可以了,參考下面的代碼片段:
file://1/.添加Label對象
jxl.write.Label labelC = new jxl.write.Label(0, 0, 『This is a Label cell』);
ws.addCell(labelC);
//添加帶有字型formatting的物件
jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18,
WritableFont.BOLD, true);
jxl.write.WritableCellformat wcfF = new jxl.write.WritableCellformat(wf);
jxl.write.Label labelCF = new jxl.write.Label(1, 0, 『This is a Label Cell』, wcfF);
ws.addCell(labelCF);
//添加帶有字體顏色formatting的物件
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10,
WritableFont.NO_BOLD, false,
Underlinestyle.NO_UNDERLINE, jxl.format.Colour.RED);
jxl.write.WritableCellformat wcfFC = new jxl.write.WritableCellformat(wfc);
jxl.write.Label labelCFC = new jxl.write.Label(1, 0, 『This is a Label Cell』, wcfFC);
ws.addCell(labelCF);
//2.添加Number對象
jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926);
ws.addCell(labelN);
//添加帶有formatting的Number對象
jxl.write.Numberformat nf = new jxl.write.Numberformat(『#.##』);
jxl.write.WritableCellformat wcfN = new jxl.write.WritableCellformat(nf);
jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN);
ws.addCell(labelNF);
//3.添加Boolean對象
jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(label;
//4.添加DateTime對象
jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
//添加帶有formatting的Dateformat對象
jxl.write.Dateformat df = new jxl.write.Dateformat(『dd MM yyyy hh:mm:ss』);
jxl.write.WritableCellformat wcfDF = new jxl.write.WritableCellformat(df);
jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF);
ws.addCell(labelDTF);
  這裏有兩點大家要引起大家的注意。第一點,在構造單格時,單格在工作表中的位置就已經確定了。一旦創建後,單格的位置是不能夠變更的,儘管單格的內容是可以改變的。第二點,單格的定位是按照下面這樣的規律(column, row),而且下標都是從0開始,例如,A1被存儲在(0, 0),B1被存儲在(1, 0)。
  最後,不要忘記關閉打開的Excel工作薄物件,以釋放佔用的記憶體,參見下面的代碼片段:
file://寫入Exel工作表
wwb.write();
//關閉Excel工作薄物件
wwb.close();
  這可能與讀取Excel檔的操作有少少不同,在關閉Excel物件之前,你必須要先調用write()方法,因為先前的操作都是存儲在緩存中的,所以要通過該方法將操作的內容保存在檔中。如果你先關閉了Excel物件,那麼只能得到一張空的工作薄了。
拷貝、更新Excel工作薄
  接下來簡要介紹一下如何更新一個已經存在的工作薄,主要是下面二步操作,第一步是構造唯讀的Excel工作薄,第二步是利用已經創建的Excel工作薄創建新的可寫入的Excel工作薄,參考下面的代碼片段:(完整代碼見ExcelModifying.java)
file://創建唯讀的Excel工作薄的物件
jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile));
//創建可寫入的Excel工作薄物件
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw);
//讀取第一張工作表
jxl.write.WritableSheet ws = wwb.getSheet(0);
//獲得第一個單格對象
jxl.write.WritableCell wc = ws.getWritableCell(0, 0);
//判斷單格的類型, 做出相應的轉化
if(wc.getType() == CellType.LABEL)
{
Label l = (Label)wc;
l.setString(『The value has been modified.』);
}
//寫入Excel對象
wwb.write();
//關閉可寫入的Excel對象
wwb.close();
//關閉唯讀的Excel對象
rw.close();
  之所以使用這種方式構建Excel物件,完全是因為效率的原因,因為上面的示例才是API的主要應用。為了提高性能,在讀取工作表時,與資料相關的一些輸出資訊,所有的格式資訊,如:字體、顏色等等,是不被處理的,因為我們的目的是獲得行資料的值,既使沒有了修飾,也不會對行資料的值產生什麼影響。唯一的不利之處就是,在記憶體中會同時保存兩個同樣的工作表,這樣當工作表體積比較大時,會佔用相當大的記憶體,但現在好像記憶體的大小並不是什麼關鍵因素了。
  一旦獲得了可寫入的工作表物件,我們就可以對單格物件進行更新的操作了,在這裏我們不必調用API提供的add()方法,因為單格已經於工作表當中,所以我們只需要調用相應的setXXX()方法,就可以完成更新的操作了。
  盡單格原有的格式化修飾是不能去掉的,我們還是可以將新的單格修飾加上去,以使單格的內容以不同的形式表現。
  新生成的工作表物件是可寫入的,我們除了更新原有的單格外,還可以添加新的單格到工作表中,這與示例2的操作是完全一樣的。
  最後,不要忘記調用write()方法,將更新的內容寫入到檔中,然後關閉工作薄物件,這裏有兩個工作薄物件要關閉,一個是唯讀的,另外一個是可寫入的。
  下面是在一個Excel表格中創建一個矩陣的簡單例子:
import org.apache.poi.hssf.usermodel.*;
import java.io.FileOutputStream;
// code run against the jakarta-poi-1.5.0-FINAL-20020506.jar.
public class PoiTest {
static public void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream(『foo.xls』);
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet();
wb.setSheetName(0, 『Matrix』);
for(short i=0; i<50; i++) {
HSSFRow row = s.createRow;
for(short j=0; j<50; j++) {
HSSFCell cell = row.createCell(j);
cell.setCellvalue(『』+i+』,』+j);
}
}
wb.write(fos);
fos.close();
}
}
這段代碼首先創建一個Workbook,從該Workbook中得到一個表格、命名,然後繼續寫入一個50×50的矩陣。最後輸出到一個名為foo.xls的Excel檔,甚至在Apple Mac機上也可以打開。
POI專案是Java應用的令人興奮的一步,為用戶提供了Windows文檔集成的新功能,允許Java開發人員方便地擴展其產品的功能。

2007 防火牆排名

http://www.matousec.com/projects/windows-personal-firewall-analysis/leak-tests-results.php

網路空間不用錢

台灣的無名小站不時的在哀嚎網站頻寬不夠、中華電信不降價,但是在國外卻有一狗票的網站紛紛跳進來提供免費空間讓網友們分享自己的檔案,相較之下實在很難想像台灣網路業者究竟從使用者的錢包賺進了多大把的鈔票…………

好,這都不是重點,先來看看DivShare有哪些特色

  • 無限檔案數量 
  • 無限下載次數 
  • 永不砍檔 
  • 沒有彈出式廣告(Pop-up AD)或垃圾郵件 
  • 高速、可靠的伺服器

線上編輯流程圖

http://www.gliffy.com/

可以線上編輯流程圖 非常好用

ResultSet概論

這篇文章並沒有給出如何使用ResultSet的具體例子,只是從ResultSet的功能性上進行了詳細的講述。希望這篇文章對大家理解ResultSet能夠有所幫助。下面就是這篇文章的具體內容。
         結果集(ResultSet)是數據中查詢結果返回的一種對象,可以說結果集是一個存儲查詢結果的對象,但是結果集並不僅僅具有存儲的功能,他同時還具有操縱數據的功能,可能完成對數據的更新等。
        結果集讀取數據的方法主要是getXXX(),他的參數可以使整型表示第幾列(是從1開始的),還可以是列名。返回的是對應的XXX類型的值。如果對應那列時空值,XXX是對象的話返回XXX型的空值,如果XXX是數字類型,如Float等則返回0,boolean返回false。使用getString()可以返回所有的列的值,不過返回的都是字符串類型的。XXX可以代表的類型有:基本的數據類型如整型(int),布爾型(Boolean),浮點型(Float,Double)等,比特型(byte),還包括一些特殊的類型,如:日期類型(java.sql.Date),時間類型(java.sql.Time),時間戳類型(java.sql.Timestamp),大數型(BigDecimal和BigInteger等)等。還可以使用getArray(int colindex/String columnname),通過這個方法獲得當前行中,colindex所在列的元素組成的對象的數組。使用getAsciiStream(
int colindex/String colname)可以獲得該列對應的當前行的ascii流。也就是說所有的getXXX方法都是對當前行進行操作。

    結果集從其使用的特點上可以分為四類,這四類的結果集的所具備的特點都是和Statement語句的創建有關,因為結果集是通過Statement語句執行後產生的,所以可以說,結果集具備何種特點,完全決定於Statement,當然我是說下面要將的四個特點,在Statement創建時包括三種類型。首先是無參數類型的,他對應的就是下面要介紹的基本的ResultSet對應的Statement。下面的代碼中用到的Connection並沒有對其初始化,變量conn代表的就是Connection對應的對象。SqlStr代表的是響應的SQL語句。

1、    最基本的ResultSet。
之所以說是最基本的ResultSet是因為,這個ResultSet他起到的作用就是完成了查詢結果的存儲功能,而且只能讀去一次,不能夠來回的滾動讀取。這種結果集的創建方式如下:

Statement st = conn.CreateStatement
ResultSet rs = Statement.excuteQuery(sqlStr);

由於這種結果集不支持,滾動的讀去功能所以,如果獲得這樣一個結果集,只能使用它裡面的next()方法,逐個的讀去數據。

2、    可滾動的ResultSet類型。
這個類型支持前後滾動取得紀錄next()、previous(),回到第一行first(),同時還支持要去的ResultSet中的第幾行absolute(int n),以及移動到相對當前行的第幾行relative(int n),要實現這樣的ResultSet在創建Statement時用如下的方法。

Statement st = conn.createStatement(int resultSetType, int resultSetConcurrency)
ResultSet rs = st.executeQuery(sqlStr)

其中兩個參數的意義是:
resultSetType是設置ResultSet對象的類型可滾動,或者是不可滾動。取值如下:
       ResultSet.TYPE_FORWARD_ONLY只能向前滾動
       ResultSet.TYPE_SCROLL_INSENSITIVE和Result.TYPE_SCROLL_SENSITIVE這兩個方法都能夠實現任意的前後滾動,使用各種移動的ResultSet指針的方法。二者的區別在於前者對於修改不敏感,而後者對於修改敏感。
resultSetConcurency是設置ResultSet對像能夠修改的,取值如下:
       ResultSet.CONCUR_READ_ONLY 設置為只讀類型的參數。
       ResultSet.CONCUR_UPDATABLE 設置為可修改類型的參數。
所以如果只是想要可以滾動的類型的Result只要把Statement如下賦值就行了。

Statement st = conn.createStatement(Result.TYPE_SCROLL_INSENITIVE,
                          ResultSet.CONCUR_READ_ONLY);
ResultSet rs = st.excuteQuery(sqlStr);

用這個Statement執行的查詢語句得到的就是可滾動的ResultSet。

3、    可更新的ResultSet
這樣的ResultSet對象可以完成對數據庫中表的修改,但是我知道ResultSet只是相當於數據庫中表的視圖,所以並不時所有的ResultSet只要設置了可更新就能夠完成更新的,能夠完成更新的ResultSet的SQL語句必須要具備如下的屬性:
    a、只引用了單個表。
    b、不含有join或者group by子句。
    c、那些列中要包含主關鍵字。
    具有上述條件的,可更新的ResultSet可以完成對數據的修改,可更新的結果集的創建方法是:

Statement st = createstatement(Result.TYPE_SCROLL_INSENSITIVE,Result.CONCUR_UPDATABLE)

這樣的Statement的執行結果得到的就是可更新的結果集。更新的方法是,把ResultSet的游標移動到你要更新的行,然後調用updateXXX(),這個方法XXX的含義和getXXX()是相同的。updateXXX()方法,有兩個參數,第一個是要更新的列,可以是列名或者序號。第二個是要更新的數據,這個數據類型要和XXX相同。每完成對一行的update要調用updateRow()完成對數據庫的寫入,而且是在ResultSet的游標沒有離開該修改行之前,否則修改將不會被提交。
    使用updateXXX方法還可以完成插入操作。但是首先要介紹兩個方法:
    moveToInsertRow()是把ResultSet移動到插入行,這個插入行是表中特殊的一行,不需要指定具體那一行,只要調用這個方法系統會自動移動到那一行的。
    moveToCurrentRow()這是把ResultSet移動到記憶中的某個行,通常當前行。如果沒有使用insert操作,這個方法沒有什麼效果,如果使用了insert操作,這個方法用於返回到insert操作之前的那一行,離開插入行,當然也可以通過next(),previous()等方法離開插入行。
    要完成對數據庫的插入,首先調用moveToInsertRow()移動到插入行,然後調用updateXXX的方法完成對,各列數據的更新,完成更新後和更新操作一樣,要寫到數據庫,不過這裡使用的是insertRow(),也要保證在該方法執行之前ResultSet沒有離開插入列,否則插入不被執行,並且對插入行的更新將丟失。

4、    可保持的ResultSet
正常情況下如果使用Statement執行完一個查詢,又去執行另一個查詢時這時候第一個查詢的結果集就會被關閉,也就是說,所有的Statement的查詢對應的結果集是一個,如果調用Connection的commit()方法也會關閉結果集。可保持性就是指當ResultSet的結果被提交時,是被關閉還是不被關閉。JDBC2.0和1.0提供的都是提交後ResultSet就會被關閉。不過在JDBC3.0中,我們可以設置ResultSet是否關閉。要完成這樣的ResultSet的對象的創建,要使用的Statement的創建要具有三個參數,這個Statement的創建方式也就是,我所說的Statement的第三種創建方式。如下:

Statement st=createStatement(int resultsetscrollable,int resultsetupdateable,int resultsetSetHoldability)
ResultSet rs = st.excuteQuery(sqlStr);

前兩個參數和兩個參數的createStatement方法中的參數是完全相同的,這裡只介紹第三個參數:
       resultSetHoldability表示在結果集提交後結果集是否打開,取值有兩個:
       ResultSet.HOLD_CURSORS_OVER_COMMIT:表示修改提交時,不關閉數據庫。
     ResultSet.CLOSE_CURSORS_AT_COMMIT:表示修改提交時ResultSet關閉。

不過這種功能只是在JDBC3.0的驅動下才能成立。 這樣的Statement的執行結果得到的就是可更新的結果集。更新的方法是,把ResultSet的游標移動到你要更新的行,然後調用updateXXX(),這個方法XXX的含義和getXXX()是相同的。updateXXX()方法,有兩個參數,第一個是要更新的列,可以是列名或者序號。第二個是要更新的數據,這個數據類型要和XXX相同。每完成對一行的update要調用updateRow()完成對數據庫的寫入,而且是在ResultSet的游標沒有離開該修改行之前,否則修改將不會被提交。
    使用updateXXX方法還可以完成插入操作。但是首先要介紹兩個方法:
    moveToInsertRow()是把ResultSet移動到插入行,這個插入行是表中特殊的一行,不需要指定具體那一行,只要調用這個方法系統會自動移動到那一行的。
    moveToCurrentRow()這是把ResultSet移動到記憶中的某個行,通常當前行。如果沒有使用insert操作,這個方法沒有什麼效果,如果使用了insert操作,這個方法用於返回到insert操作之前的那一行,離開插入行,當然也可以通過next(),previous()等方法離開插入行。
    要完成對數據庫的插入,首先調用moveToInsertRow()移動到插入行,然後調用updateXXX的方法完成對,各列數據的更新,完成更新後和更新操作一樣,要寫到數據庫,不過這裡使用的是insertRow(),也要保證在該方法執行之前ResultSet沒有離開插入列,否則插入不被執行,並且對插入行的更新將丟失。

批次檔教學

例一、先給出一個最easy的批處理腳本讓大家和它混個臉熟,將下面的幾行命令保存為name.bat然後執行(以後文中只給出代碼,保存和執行方式類似):

ping sz.tencent.com > a.txt
ping sz1.tencent.com >> a.txt
ping sz2.tencent.com >> a.txt
ping sz3.tencent.com >> a.txt
ping sz4.tencent.com >> a.txt
ping sz5.tencent.com >> a.txt
ping sz6.tencent.com >> a.txt
ping sz7.tencent.com >> a.txt
exit

是不是都能看的懂?是不是很easy?但它的作用卻是很實用的,執行這個批處理後,可以在你的當前盤建立一個名為a.txt的文件,它裡面記錄的信息可以幫助你迅速找到速度最快的QQ服務器,從而遠離「從服務器中轉」那一痛苦的過程。這裡>的意思,是把前面命令得到的東西放到後面所給的地方,>>的作用,和>的相同,區別是把結果追加到前一行得出的結果的後面,具體的說是下一行,而前面一行命令得出的結果將保留,這樣可以使這個a.txt文件越來越大(想到如何搞破壞了??)。By the way,這個批處理還可以和其他命令結合,搞成完全自動化判斷服務器速度的東東,執行後直接顯示速度最快的服務器IP,是不是很爽?後面還將詳細介紹。

例二、再給出一個已經過時的例子(a.bat):

@echo off
if exist C:\Progra~1\Tencent\AD\*.gif del C:\Progra~1\Tencent\AD\*.gif
a.bat

為什麼說這是個過時的例子呢?很簡單,因為現在已經幾乎沒有人用帶廣告的QQ了(KAO,我的QQ還顯示好友三圍呢!!),所以它幾乎用不上了。但曾經它的作用是不可小窺的:刪除QQ的廣告,讓對話框乾乾淨淨。這裡用的地址是QQ的默認安裝地址,默認批處理文件名為a.bat,你當然可以根據情況自行修改。在這個腳本中使用了if命令,使得它可以達到適時判斷和刪除廣告圖片的效果,你只需要不關閉命令執行後的DOS窗口,不按CTRL+C強行終止命令,它就一直監視是否有廣告圖片(QQ也再不斷查看自己的廣告是否被刪除)。當然這個腳本佔用你一點點內存,呵呵。
例三,使用批處理腳本查是否中冰河。腳本內容如下:

@echo off
netstat -a -n > a.txt
type a.txt | find 『7626″ && echo 『Congratulations! You have infected GLACIER!』
del a.txt
pause & exit

這裡利用了netstat命令,檢查所有的網絡端口狀態,只需要你清楚常見木馬所使用的端口,就能很easy的判斷出來是否被人種了冰河。然這不是確定的,因為冰河默認的端口7626,完全可以被人修改。這裡介紹的只是方法和思路。這裡介紹的是方法和思路稍做改動,就變成可以檢查其他木馬的腳本了,再改動一下,加進去參數和端口及信息列表文件後,就變成自動檢測所有木馬的腳本了。呵呵,是不是很過癮?腳本中還利用了組合命令&&和管道命令|,後面將詳細介紹。

例四,借批處理自動清除系統垃圾,腳本如下:

@echo off
if exist c:\windows\temp\*.* del c:\windows\temp\*.*
if exist c:\windows\Tempor~1\*.* del c:\windows\Tempor~1\*.*
if exist c:\windows\History\*.* del c:\windows\History\*.*
if exist c:\windows\recent\*.* del c:\windows\recent\*.*

將以上腳本內容保存到autoexec.bat裡,每次開機時就把系統垃圾給自動刪除了。這裡需要注意兩點:一、DOS不支持長文件名,所以就出現了Tempor~1這個東東;二、可根據自己的實際情況進行改動,使其符合自己的要求。

怎麼樣,看到這裡,你對批處理腳本是不是已經有點興趣了?是不是發現自己已經慢慢愛上了這個東東?別高興的太早,愛不是一件簡單的事,它也許能帶給你快樂和幸福,當然也能讓你痛苦的想去跳樓。如果你知道很難還敢繼續的話,I 服了 YOU!繼續努力吧,也許到最後你不一定得到真愛(真的有這可能,愛過的人都知道),但你可以體會到整個愛的過程,就是如此。 酸、苦和辣,有沒有甜天知道。

為什麼會把批處理和愛情扯上關係?不是我無聊,也不是因為這樣寫有趣多少,原因有二:其一,批處理和愛情有很多相同的地方,有些地方我用「專業」的行話解釋不清(我不懷疑自己的表達能力,而是事情本身就不好說清楚),說了=沒說,但用地球人都知道的愛情一比喻(愛情是什麼?我**怎麼知道!!),沒準你心裡一下就亮堂了,事半功倍,何樂而不為?其二,我這段時間狀態不是很好,感冒發燒頭疼鼻塞,但主要還是感情上精神摧殘,搞的人煩透了,借寫教程之際感慨幾句,大家就全當買狗皮膏藥了,完全可以省略不看(也許還真有點效果—-不至於讓你看著看著就睡著了,把頭磕了來找我報銷醫藥費)。說不定下次的教程中大家還會看到楊過、張無忌等金老前輩筆下的英雄們。
看過第一章的朋友,一定對批處理有了初步的印象,知道它到底是用來幹什麼的了。但你知道運用批處理的精髓在哪裡嗎?其實很簡單:思路要靈活!沒有做不到的,只有想不到的。這和愛情就有點不同了,因為愛情的世界是兩個人的世界,一廂情願不叫愛情(補充:那叫單戀。廢話!)而批處理卻是一個人的天堂,你可以為所欲為,沒有達不到的境界!

批處理看起來雜亂無章,但它的邏輯性之強,絕對不比其他程序語言(如彙編)低,如果你寫的腳本是一堆亂麻,雖然每一行命令都正確,但從頭執行到尾後,不一定得到你想要的結果,也許是一屏幕的Bad command or fail name。這又和愛情有了共同點:按步驟來經營,缺少或增多的步驟都可能導致不想看見的結果。陷入愛河的朋友,相信沒有不肯定這句話的。我的愛情批處理,輸出的結果不是Bad command or fail name,屏幕是這麼顯示的:『你的愛情』不是內部或外部命令,也不是可運行的程序或批處理文件。然後就是光標不停閃動,等待這下一次錯誤的輸入。

從這一章開始,將由淺入深的介紹批處理中常用的命令,很多常見DOS命令在批處理腳本中有這廣泛的應用,它們是批處理腳本的BODY部分,但批處理比DOS更靈活多樣,更具備自動化。要學好批處理,DOS一定要有比較紮實的基礎。這裡只講述一些比較少用(相對來說)的DOS命令,常用命令如COPY、DIR等就不做介紹了(這些看似簡單的命令實際複雜的很,我怕自己都說不清楚!)。

例五,先看一個實例。這是一個很有意思的腳本,一個小巧實用的好東東,把批處理「自動化」的特點體現的淋漓盡致。先介紹一下這個腳本的來歷:大家都知道彙編程序(MASM)的上機過程,先要對源代碼進行彙編、連接,然後再執行,而這中間有很多環節需要輸入很多東西,麻煩的很(只有經歷過的朋友才懂得)。如何使這個過程變的簡單呢?在我們搞彙編課程設計時,我「被逼」寫了這個腳本,用起來很爽,呵呵。看看腳本內容:

@echo off
::close echo
cls
::clean screen
echo This programme is to make the MASM programme automate
::display info
echo Edit by CODERED
::display info
echo Mailto me : qqkiller***@sina.com
::display info
if 『%1″==』" goto usage
::if input without paramater goto usage
if 『%1″==』/?』 goto usage
::if paramater is 『/?』 goto usage
if 『%1″==』help』 goto usage
::if paramater is 『help』 goto usage
pause
::pause to see usage
masm %1.asm
::assemble the .asm code
if errorlevel 1 pause & edit %1.asm
::if error pause to see error msg and edit the code
link %1.obj & %1
::else link the .obj file and execute the .exe file
:usage
::set usage
echo Usage: This BAT file name [asm file name]
echo Default BAT file name is START.BAT
::display usage

先不要被這一堆的東西給嚇怕了,靜下心來仔細的看(回想一下第一章中第一段是怎麼寫的!!)。已經給出了每一行命令的解釋,兩個冒號後面的內容為前一行內容解釋的E文(害怕E文的朋友也不用擔心,都很easy,一看就懂了,實在不懂了不會查詞典啊,這麼懶?),在腳本執行時不顯示,也不起任何作用。倒數第5行行首有一個冒號,可不是筆誤哦!具體作用後面會詳細講到。此腳本中masm和link是彙編程序和連接程序,必須和edit程序以及你要編輯的源代碼(當然還有這個腳本,廢話!)一起在當前目錄中。使用這個批處理腳本,可以最大可能的減少手工輸入,整個過程中只需要按幾下回車鍵,即可實現從彙編源代碼到可執行exe文件的自動化轉換,並具備智能判斷功能:如果彙編時源代碼出現錯誤(彙編不成功),則自動暫停顯示錯誤信息,並在按任意鍵後自動進入編輯源代碼界面;如果源代碼彙編成功,則進行連接,並在連接後自動執行生成的exe文件。另外,由於批處理命令的簡單性和靈活性,這個腳本還具備良好的可改進性,簡單進行修改就可以符合不同朋友的上機習慣。正在學彙編的朋友,一定別忘了實習一下!

在這個腳本中出現了如下幾個命令:@、echo、::、pause、:和goto、%以及if。而這一章就將講述這幾個命令。

1、@

這個符號大家都不陌生,email的必備符號,它怎麼會跑到批處理中呢?呵呵,不是它的錯,批處理本來就離不開它,要不就不完美了。它的作用是讓執行窗口中不顯示它後面這一行的命令本身(多麼繞口的一句話!)。呵呵,通俗一點說,行首有了它的話,這一行的命令就不顯示了。在例五中,首行的@echo off中,@的作用就是讓腳本在執行時不顯示後面的echo off部分。這下懂了吧?還是不太懂?沒關係,看完echo命令簡介,自然就懂了。

2、echo

中文為「反饋」、「回顯」的意思。它其實是一個開關命令,就是說它只有兩種狀態:打開和關閉。於是就有了echo on和echo off兩個命令了。直接執行echo命令將顯示當前echo命令狀態(off或on)執行echo off將關閉回顯,它後面的所有命令都不顯示命令本身,只顯示執行後的結果,除非執行echo on命令。在例五中,首行的@命令和echo off命令聯合起來,達到了兩個目的:不顯示echo off命令本身,不顯示以後各行中的命令本身。的確是有點亂,但你要是練習一下的話,3分鐘包會,不會的退錢!

echo命令的另一種用法一:可以用它來顯示信息!如例五中倒數第二行,Default BAT file name is START.BAT將在腳本執行後的窗口中顯示,而echo命令本身不顯示(為什麼??)。
echo命令的另一種用法二:可以直接編輯文本文件。例六:
echo nbtstat -A 192.168.0.1 > a.bat
echo nbtstat -A 192.168.0.2 >> a.bat
echo nbtstat -A 192.168.0.3 >> a.bat

以上腳本內容的編輯方法是,直接是命令行輸入,每行一回車。最後就會在當前目錄下生成一個a.bat的文件,直接執行就會得到結果。

3、::

這個命令的作用很簡單,它是註釋命令,在批處理腳本中和rem命令等效。它後面的內容在執行時不顯示,也不起任何作用,因為它只是註釋,只是增加了腳本的可讀性,和C語言中的/*…………*/類似。地球人都能看懂,就不多說了。

4、pause

中文為「暫停」的意思(看看你的workman上),我一直認為它是批處理中最簡單的一個命令,單純、實用。它的作用,是讓當前程序進程暫停一下,並顯示一行信息:請按任意鍵繼續. . .。在例五中這個命令運用了兩次,第一次的作用是讓使用者看清楚程序信息,第二個是顯示錯誤的彙編代碼信息(其實不是它想顯示,而是masm程序在顯示錯誤信息時被暫它停了,以便讓你看清楚你的源代碼錯在哪裡)。

5、:和goto

為什麼要把這兩個命令聯合起來介紹?因為它們是分不開的,無論少了哪個或多了哪個都會出錯。goto是個跳轉命令,:是一個標籤。當程序運行到goto時,將自動跳轉到:定義的部分去執行了(是不是分不開?)。例五中倒數第5行行首出現一個:,則程序在運行到goto時就自動跳轉到:標籤定義的部分執行,結果是顯示腳本usage(usage就是標籤名稱)。不難看出,goto命令就是根據這個冒號和標籤名稱來尋找它該跳轉的地方,它們是一一對應的關係。goto命令也經常和if命令結合使用。至於這兩個命令具體用法,參照例五。

goto命令的另一種用法一:提前結束程序。在程序中間使用goto命令跳轉到某一標籤,而這一標籤的內容卻定義為退出。如:

……
goto end
……
:end

在Java應用程序中創建圖像的方法和技巧

合成圖像
  您不必從文件中讀取所有的圖像 — 您可以創建自己的圖像。要創建自己的圖像,最靈活的方法是用一個 BufferedImage 對象,它是 Image 類的一個子類,它把圖像數據存儲在一個可以被訪問的緩衝區中。它還支持各種存儲像素數據的方法:使用或不使用 alpha 通道、不同種類的顏色模型以及顏色組件的各種精確度。ColorModel 類提供一種靈活的方法 定義各種顏色模型,以和 BufferedImage 對像一起使用。為了理解顏色模型工作的基本知識,我們將只使用一個缺省的顏色模型,其顏色組件由 RGB 值和一個緩衝類型(存儲 8 位的 RGB 顏色值加上一個 alpha 通道)組成。這一緩衝類型由 BufferedImage 類中的常量 TYPE_INT_ARGB 指定,它意味著每個像素要用一個 int 值。每個像素的值是以 8 位字節形式存儲一個 alpha 組件加上 RGB 顏色組件。我們可以用給定的寬度和高度創建一個這種類型的 BufferedImage 對象,代碼語句如下:

int width = 200;
int height = 300;
BufferedImage image = new BufferedImage(width,
height,BufferedImage.TYPE_INT_ARGB);

  這段代碼創建了一個 BufferedImage 對象,它代表一個 200 像素寬、300 像素高的圖像。為了應用這個圖像,我們需要有圖形上下文,而 BufferedImage 對象的 createGraphics() 方法就返回一個與該圖像相關的 Graphics2D 對像:

int width = 200;
Graphics2D g2D = image.createGraphics(); 

  使用 g2D 對象的操作會修改 BufferedImage 對像 image 的像素。利用這個對象,您現在完全有能力應用 BufferedImage 對象。您可以繪製形狀、圖像、GeneralPath 對像或任何別的東西,還可以為圖形上下文設置 alpha 組合對象。您同時還擁有 Graphics2D 對像提供的全部仿射變形能力。

  如果要從 BufferedImage 對像獲取單個像素,可以通過調用它的 getRGB() 方法,並提供該像素的 x,y 坐標作為 int 類型的參數。這個像素會按 TYPE_INT_ARGB 格式以 int 類型返回,它由四個 8 位的值(代表 alpha 值和 RGB 顏色組件)組成一個 32 位字。同時 getRGB() 還有一個重載的版本,它從一部分圖像數據中返回一個像素數組。您也可以通過調用 setRGB() 方法來設置單個像素。前兩個參數是該像素的坐標值,第三個參數是待設定的值,類型為 int。這個方法也有一個版本可以設置像素數組的值。

  至此我們已經完成了像素操作的學習。下面我們要建立一個 applet,它在 Wrox 徽標背景上使 BufferedImage 對像具有動畫效果。我們的示例還將演示怎樣能讓圖像局部透明。applet 的基本內容如下所示:

import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;

public class ImageDrawDemo extends JApplet
{
 // The init() method to initialize everything…
 // The start() method to start the animation…
 // The stop() method to stop the animation…
 // The ImagePanel class defining the panel displaying the animation…
 // Data members for the applet…
}

  創建一個圖像

  一個子圖形是一個小的圖形圖像,可以將其繪製在靜態圖像以創建動畫。要創建動畫效果,您只要隨著時間推移,在不同的位置和方向上繪製子圖形。當然,利用坐標系的變形可以使之簡化許多。遊戲經常使用子圖形 — 由於您只需要在一個靜態背景上繪製子圖形,所以可以使動畫所佔用的處理器的時間大大減少。我們對使用 BufferedImage 對象的興趣意味著我們將不再花費精力去研究減少處理器時間的最佳技術,而是把注意力放在理解怎樣才能在一個程序內部創建和使用圖像上。

  我們的 BufferedImage 對像看上去如圖 1 中的圖像:
圖 1. BufferedImage 子圖形

  這個圖像是一個以 spriteSize 為邊長的正方形。圖像其它部分的尺寸值都與這個邊長相關。實際上這裡只有兩個幾何實體,一條線和一個圓,都在不同位置和方向重複出現。如果我們創建一個 Line2D.Double 對像代表線,創建一個 Ellipse2D.Double 對像代表圓,那麼我們就可以通過移<!– –>動用戶坐標系和畫這兩個對像中的一個或其它的對象而畫出整個圖像。

  如果是按真正面向對象的方法,應該定義一個類代表一個子圖形,可能是作為 BufferedImage 的一個子類,但由於我們是在探索使用 BufferedImage 對象的技巧,因此用一個 createSprite() 方法來畫出 BufferedImage 對像上的子圖形會更適合我們的目的。因為該方法只是我們的 applet 類的一個成員,所以我們將為 applet 添加數據成員以存儲任何需要的數據。您可以把我們將使用的數據成員插入到 applet 類中,如下所示:

double totalAngle; // Current angular position of sprite
double spriteAngle; // Rotation angle of sprite about its center
ImagePanel imagePanel; // Panel to display animation

BufferedImage sprite; // Stores reference to the sprite
int spriteSize = 100; // Diameter of the sprite
Ellipse2D.Double circle; // A circle – part of the sprite
Line2D.Double line; // A line – part of the sprite

// Colors used in sprite
Color[] colors = {Color.red , Color.yellow, Color.green , Color.blue,
Color.cyan, Color.pink , Color.magenta, Color.orange};

java.util.Timer timer; // Timer for the animation
long interval = 50; // Time interval msec between repaints

  這些成員的一般用途可以從註釋中清楚地看到。下面我們要看一看開發代碼時它們是怎樣被使用的。

  createSprite() 方法需要做的第一件事就是創建 BufferedImage 對像 sprite,然後我們還需要一個 Graphics2D 對像用於在 sprite 圖像上繪畫。下面就是完成這些操作的代碼:

BufferedImage createSprite(int spriteSize)
{
 // Create image with RGB and alpha channel
 BufferedImage sprite = new BufferedImage(spriteSize, spriteSize,
 BufferedImage.TYPE_INT_ARGB);

 Graphics2D g2D = sprite.createGraphics(); // Context for buffered image
 // plus the rest of the method…
}
  sprite 對象的寬和高的值都是 spriteSize,圖像的類型為 TYPE_INT_ARGB,就是說每個像素的 alpha 值和顏色組件是以一個單獨的 int 值存儲的,而顏色是以 8 位的紅、綠、藍組件的形式存儲的。這意味著我們的 sprite 圖像將佔用 40,000 字節,這只是瀏覽一個網頁會佔用的內存的很小一部分。而這並不影響網頁的下載時間,因為在執行 applet 的時候,這部分內存是在本地機器上被分配的。除了作為網頁本身的 HTML 文件的內容外,下載時間還取決於 applet 的 .class 文件的大小,以及在它執行時下載的圖像或其它文件。

創建一個透明的背景

  在 sprite 圖像中,alpha 通道是很重要的,因為我們希望背景能完全透明。在繪畫過程中,只有 sprite 對像本身應該是可見的,而不是整個 100×100 的矩形圖像。我們可  
 
 
  
 
 
以很容易地實現這一目的,只要開始先使整個 sprite 圖像區域透明(即,alpha 值為 0.0f),然後把我們想要畫的圖形繪製在上面,使之不透明(alpha 值為 1.0f)。以下是使整個圖像透明的代碼:

// Clear image with transparent alpha by drawing a rectangle
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
Rectangle2D.Double rect = new Rectangle2D.Double(0,0,spriteSize,spriteSize);
g2D.fill(rect);

  我們首先使用 AlphaComposite 對像按照 CLEAR 規則設置 alpha 合成值,把顏色組件設置為零,又通過設置 alpha 值為 0.0f,使之透明。然後我們填充一個覆蓋整個圖像區域的矩形。我們不必設置顏色值,因為根據 CLEAR 規則,每個像素的前景和背景色所佔成分都是零,所以這兩者都不參與像素的生成。但我們仍要填充該矩形,因為這將確定被操作的圖像像素。

  這裡,我們可以稍微瞭解一下怎樣控制圖像的質量。

  著色微調

  對著色操作的許多方面而言,都有一個在質量和速度間選擇的問題。著色操作就像大多數事情一樣 — 質量是需要代價的,而這裡的代價就是處理時間。所有的著色操作都有缺省設置,其中存在一個選擇,缺省設置是特定於平台的,但您可以通過調用用於著色的 Graphics2D 對象的 setRenderingHint() 方法自己選擇。雖然只有一些微調,如果您的計算機不支持與您指定的微調相對應的著色操作選項,這些微調就無法生效。

  通過添加以下對 createSprite() 方法的調用,可以確保得到由我們的 alpha 合成操作可能生成的最好效果。

BufferedImage createSprite(int spriteSize)
{
 // Create image with RGB and alpha channel
 BufferedImage sprite = new BufferedImage(spriteSize, spriteSize, BufferedImage.TYPE_INT_ARGB);

 Graphics2D g2D = sprite.createGraphics(); // Context for buffered image

 // Set best alpha interpolation quality
 g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,
RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

 // Clear image with transparent alpha by drawing a rectangle
 g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
 Rectangle2D.Double rect = new Rectangle2D.Double(0,0,spriteSize,spriteSize);
 g2D.fill(rect);

 // plus the rest of the method…
}

  RenderingHints 類定義了多種著色微調,它們存儲在一個映射集的 Graphics2D 對像裡。 setRenderingHint() 方法的參數是一個鍵以及對應的鍵值。在我們的代碼中,第一個參數是代表 alpha 合成微調的鍵,第二個參數是該微調的值。該微調的其它可能的值有 VALUE_ALPHA_INTERPOLATION_DEFAULT,代表平台缺省值;以及 VALUE_ALPHA_INTERPOLATION_SPEED,代表追求速度而不是質量。

  您還可以為下面的鍵提供微調:

鍵  描述 
KEY_ANTIALIASING 決定是否使用抗鋸齒。當著色有傾斜角度的線時,通常會得到一組階梯式的像素排列,使這條線看上去不平滑,經常被稱為 鋸齒狀圖形。抗鋸齒是一種技術,它設置有傾斜角度的線的像素亮度,以使線看起來更平滑。因此,這個微調是用來決定在著色有傾斜角度的線時是否在減少鋸齒狀圖形上花費時間。可能的值有 VALUE_ANTIALIAS_ON, _OFF 或 _DEFAULT。 
KEY_COLOR_RENDERING 控制顏色著色的方式。可能的值有 VALUE_COLOR_RENDER_SPEED, _QUALITY 或 _DEFAULT。
KEY_DITHERING 控制如何處理抖動。抖動是用一組有限的顏色合成出一個更大範圍的顏色的過程,方法是給相鄰像素著色以產生不在該組顏色中的新的顏色幻覺。可能的值有 VALUE_DITHER_ENABLE, _DISABLE 或 _DEFAULT。 
KEY_FRACTIONALMETRICS 文本的質量。可能的值有 VALUE_FRACTIONALMETRICS_ON, _OFF 或 _DEFAULT。
KEY_INTERPOLATION 確定怎樣做內插。

  在對一個源圖像做變形時,變形後的像素很少能夠恰好對應目標像素位置。在這種情況下,每個變形後的像素的顏色值不得不由周圍的像素決定。

  內插就是實現上述過程。有許多可用的技術。可能的值,按處理時間從最多到最少,是 VALUE_INTERPOLATION_BICUBIC, _BILINEAR 或 _NEAREST_NEIGHBOR。

  KEY_RENDERING 確定著色技術,在速度和質量之間進行權衡。可能的值有 VALUE_RENDERING_SPEED, _QUALITY 或 _DEFAULT。

  KEY_TEXT_ANTIALIASING 確定對文本著色時是否抗鋸齒。可能的值有 VALUE_TEXT_ANTIALIASING_ON, _OFF 或 _DEFAULT。

JSP給圖片添加文字

<%@ page autoFlush=』false』 contentType=』text/html;charset=GBK』 import=』java.io.FileInputStream,
java.io.FileOutputStream,
java.awt.*,
java.awt.image.*,
com.sun.image.codec.jpeg.*,
java.util.*』%>

<% 
  out.clear(); 
  response.addHeader(『pragma』,』NO-cache』); 
  response.addHeader(『Cache-Control』,』no-cache』); 
  response.addDateHeader(『Expries』,0); 
  String FileName = 『E:\\2.jpg』;
  String OutFileName = 『C:\\ww.jpg』;

  //創建一個FileInputStream對像從源圖片獲取數據流 
  FileInputStream sFile = new FileInputStream(FileName);

  //創建一個Image對象並以源圖片數據流填充
 Image src = javax.imageio.ImageIO.read(sFile);  
 int width = src.getWidth(null); //得到源圖寬 
 int height = src.getHeight(null); //得到源圖長 
 if (width>70 && height>30){
     //創建一個BufferedImage來作為圖像操作容器
     BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

      //創建一個繪圖環境來進行繪製圖像
   Graphics g = image.getGraphics();

     //將原圖像數據流載入這個BufferedImage 
   g.drawImage(src,0,0,width,height,null);

     //設定文本字體
     g.setFont(new Font(『宋體』,Font.PLAIN,48)); 
 
   //設定文本
   String rand = 『850″;

     //設定文本顏色 
     g.setColor(Color.black);

   //向BufferedImage寫入文本字符
   g.drawString(rand,20,50); 

   //使更改生效
   g.dispose();   

   //創建輸出文件流
   FileOutputStream outi = new FileOutputStream(OutFileName);  

   //創建JPEG編碼對像
   JPEGImageEncoder encodera = JPEGCodec.createJPEGEncoder(outi);   

   //對這個BufferedImage (image)進行JPEG編碼
   encodera.encode(image);  
   outi.close(); //關閉輸出文件流 
 }
%>