摘:JAVA JXL API的詳細使用
轉自:http://www.cr173.com/html/10377_1.html
1 開發調研
1.1 需求描述
MS的電子表格(Excel)是Office的重要成員,是保存統計數據的一種常用格式。作為辦公文檔,勢必要涉及到的電子文檔的交換,Excel是一種在企業中非常通用的文件格式,打印和管理也比較方便。在一個Java應用中,將一部分數據生成Excel格式,是與其他系統無縫連接的重要手段。
1.2 Excel開發常用開源工具
在開源世界中,有兩套比較有影響的API可供使用,一個是POI,一個是jExcelAPI。
1.3 比較開源工具的優缺點
1.3.1 Jxl優缺點
Jxl特征有如下描述:
● 支持Excel 95-2000的所有版本
● 生成Excel 2000標準格式
● 支持字體、數字、日期操作
● 能夠修飾單元格屬性
● 支持圖像和圖表
應該說以上功能已經能夠大致滿足我們的需要。最關鍵的是這套API是純Java的,並不依賴Windows系統,即使運行在Linux下,它同樣能夠正確的處理Excel文件。另外需要說明的是,這套API對圖形和圖表的支持很有限,而且僅僅識別PNG格式。
1.3.2 Poi優缺點
Jakarta 的 POI Project 與 Java Excel API 在開源世界中可以說是並駕齊驅,但是也各有優劣,poi在某些細節有些小Bug並且不支持寫入圖片(poi其實可以寫入圖片,不過沒有jxl來的方便,比較麻煩),其他方面都挺不錯的;而JXL提供了對圖片的支持(但是僅僅支持png格式的圖片),問題就是對公式支持不是很好,但還是提供了簡單的公式讀取支持。因此你的項目中要選用什麽樣的第三方插件為完全由你的應用來決定。如果你的軟件是跟財務有相當的關系的話,建議采用 POI Project,就我所在目前的項目來說由於用不到計算公式,而且很可能需要導出圖片,因此,我的選擇是 JXL 。
1.4 性能比較以及最終選擇
1.4.1 內存消耗:(來自網絡)
談下JVM虛擬機內存消耗的情況.
數據量3000條數據,每條60列.JVM虛擬機內存大小64M.
使用POI:運行到2800條左右就報內存溢出.
使用JXL:3000條全部出來,並且內存還有21M的空間.
可想而知,在對內存的消耗方面差距還是挺大的.
也許是由於JXL在對資源回收利用方面做的還挺不錯的。
1.4.2 速度效率(讀取excel數據)(來自網絡)
文件 POI加載耗時 POI總耗時 JXL加載耗時 Jxl總耗時
文件大小57KB 1172 ms 1172 ms 1265 ms 2250 ms
文件大小652KB 2297 ms 2313 ms 4406 ms 9750 ms
文件大小2.24M 3109ms 3140ms 16313ms 37453ms
1.4.3 寫excel速度效率
jxl插入數據比poi速度要快
1.4.4 功能對比
相比提供的功能的話,JXL相對弱了點.所以如果要實現的功能比較復雜的情況下可以考慮使用POI,但如果只想生成一些大數據量可以考慮使用JXL,或者CSV也是一個不錯的選擇,不過CSV並不是真正的excel,然而jxl插入數據比poi速度要快。
2 Jxl開發指南
2.1 介紹
jxl操作excel包括對象Workbook,Sheet ,Cell。
一個excel就對應一個Workbook對象,
一個Workbook可以有多個Sheet對象
一個Sheet對象可以有多個Cell對象
2.2 讀取excel操作
通過Workbook,Sheet ,Cell這三個對象我們就可以實現Excel文件的讀取工作。我們先想想一下讀取步驟,不管是什麽樣的Excel操作框架必定都要經歷
1、 選取Excel文件得到工作薄
2、 選擇工作表
3、 選擇Cell
4、 讀取信息
2.2.1 讀取工作薄
選取Excel文件得到工作薄Workbook
Workbook workbook = Workbook.getWorkbook(new File("myfile.xls"));
2.2.2 讀取工作表
通過Workbook的getSheet方法選擇第一個工作表(從0開始)
Sheet sheet = workbook.getSheet(0);
也可以通過工作的名稱來得到Sheet
2.2.3 讀取單元格
通過Sheet的getCell方法選擇位置為C2的單元格(兩個參數都從0開始)
Cell c2 = sheet.getCell(2,1);
2.2.3.1 讀取單元格的值
2.2.3.2 通過Cell的getContents方法
把單元格中的信息以字符的形式讀取出來String stringc2 = c2.getContents();
2.2.3.3 Cell提供了一個getType方法
能夠返回單元格的類型信息,同時JXL提供了一個CellType類用來預設Excel中的類型信息,而且JXL提供了一些Cell類的子類用來分別用來表示各種類型的單元格,如LabelCell,NumberCell,DateCell分別表示字符、數值、日期類型的單元格
if (c2.getType() == CellType. LABEL)
{
LabelCell nc = (LabelCell) c2;
String number b2 = nc. getString();
}
if (c2.getType() == CellType. DATE)
{
DateCell nc = (DateCell) c2;
Date number b2 = nc. getDate();
}
if (c2.getType() == CellType.NUMBER)
{
NumberCell nc = (NumberCell) c2;
double number b2 = nc.getValue();
}
API提供了以下基本類型,與Excel的數據格式相對應,如下圖所示
2.2.4 以釋放資源:workbook.close()
當你完成對Excel電子表格數據的處理後,一定要使用close()方法來關閉先前創建的對象,以釋放讀取數據表的過程中所占用的內存空間,在讀取大量數據時顯得尤為重要
最後不要忘記關閉workbook以釋放資源:workbook.close();
2.3 寫excel操作
通過WritableWorkbook,WritableSheet,Label這三個對象我們就可以實現Excel文件的插入工作。我們先想想一下插入,不管是什麽樣的Excel操作框架必定都要經歷
1、 創建Exce工作薄
2、 創建工作表
3、 創建單元格
2.3.1 創建工作薄
API提供了兩種方式來處理可寫入的輸出流,一種是直接生成本地文件,如果文件名不帶全路徑的話,缺省的文件會定位在當前目錄,如果文件名帶有全路徑的話,則生成的Excel文件則會定位在相應的目錄;另外一種是將Excel對象直接寫入到輸出流,例如:用戶通過瀏覽器來訪問web服務器,如果HTTP頭設置正確的話,瀏覽器自動調用客戶端的Excel應用程序,來顯示動態生成的Excel電子表格。
2.3.1.1 創建可寫入的Excel工作薄
WritableWorkbook
wwb = Workbook.createWorkbook(new File(targetfile));
2.3.1.2 將WritableWorkbook直接寫入到輸出流
OutputStream os = new FileOutputStream(targetfile);
WritableWorkbook wwb = Workbook.createWorkbook(os);
2.3.2 創建工作表
WritableSheet ws = wwb.createSheet("通訊錄", 0);//創建sheet
2.3.3 創建單元格
2.3.3.1 添加文本類單元格
Label labelC = new Label(0, 0, "This is a Label cell");
2.3.3.2 添加帶有字型Formatting的對象
WritableFont wf = new WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true);
WritableCellFormat wcfF = new WritableCellFormat(wf);
labelCF = new Label(1, 0, "This is a Label Cell", wcfF);
ws.addCell(labelCF);
2.3.3.3 添加帶有字體顏色Formatting的對象
WritableFont wfc = new WritableFont(WritableFont.ARIAL,10,WritableFont.NO_BOLD, false,
UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED);
WritableCellFormat wcfFC = new WritableCellFormat(wfc);
Label labelCFC = new Label(1, 0, "This is a Label Cell", wcfFC);
ws.addCell(labelCF);
2.3.3.4 添加Number對象
Number labelN = new jxl.write.Number(0, 1, 3.1415926);
ws.addCell(labelN);
2.3.3.5 添加帶有formatting的Number對象
NumberFormat nf = new NumberFormat("#.##");
WritableCellFormat wcfN = new WritableCellFormat(nf);
Number labelNF = new Number(1, 1, 3.1415926, wcfN);
ws.addCell(labelNF);
2.3.3.6 添加Boolean對象
Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(labelB);
2.3.3.7 添加DateTime對象
DateTime labelDT = new DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
2.3.3.8 添加帶有formatting的DateFormat對象
DateFormat df = new DateFormat("dd MM yyyy hh:mm:ss");
WritableCellFormat wcfDF = new WritableCellFormat(df);
DateTime labelDTF = new DateTime(1, 3, new Date(), wcfDF);
ws.addCell(labelDTF);
2.3.3.9 添加公式單元格
Fornual formual = new Formual(0,11,”Sum(A1:A9)”);
wrb.addCell(formual);
2.3.3.10 添加圖像
WritableImage wrimage=new WritableImage(1,5,10,10,new File(imageFilepath));
wrb.addImage(wrimage);
註意,API中註明只支持png文件。
2.3.4 合並單元格
通過writablesheet.mergeCells(int x,int y,int m,int n);來實現的。
表示將從第x+1列,y+1行到m+1列,n+1行合並 (四個點定義了兩個坐標,左上角和右下角)結果是合並了m-x+1行,n-y+1列,兩者乘積就是合並的單元格數量。
sheet.mergeCells(0, 6, 3, 8);
label = new Label(0, 6, "合並了12個單元格");
sheet.addCell(label);
2.3.5 添加單元格樣式
主要是改變單元格背景、字體、顏色等等。
WritableCellFormat wc = new WritableCellFormat();
wc.setAlignment(Alignment.CENTRE); // 設置居中
wc.setBorder(Border.ALL, BorderLineStyle.THIN); // 設置邊框線
wc.setBackground(jxl.format.Colour.RED); // 設置單元格的背景顏色
label = new Label(1, 5, "字體", wc);
sheet.addCell(label);
2.3.6 設置單元格字體
WritableFont wfont =
new WritableFont(WritableFont.createFont("楷書"), 20);
WritableCellFormat font = new WritableCellFormat(wfont);
label = new Label(2, 6, "楷書", font);
sheet.addCell(label);
2.3.7 寫入到文件
wwb.write();// 寫入數據
wwb.close();// 關閉文件
2.4 拷貝、更新Excel工作薄
//創建只讀的Excel工作薄的對象
jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile));
//創建可寫入的Excel工作薄對象
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();
為了提高性能,在讀取工作表時,與數據相關的一些輸出信息,所有的格式信息,如:字體、顏色等等,是不被處理的,因為我們的目的是獲得行數據的值,既使沒有了修飾,也不會對行數據的值產生什麽影響。唯一的不利之處就是,在內存中會同時保存兩個同樣的工作表,這樣當工作表體積比較大時,會占用相當大的內存,但現在好像內存的大小並不是什麽關鍵因素了。
一旦獲得了可寫入的工作表對象,我們就可以對單元格對象進行更新的操作了,在這裏我們不必調用API提供的add()方法,因為單元格已經於工作表當中,所以我們只需要調用相應的setXXX()方法,就可以完成更新的操作了。
盡單元格原有的格式化修飾是不能去掉的,我們還是可以將新的單元格修飾加上去,以使單元格的內容以不同的形式表現。
新生成的工作表對象是可寫入的,我們除了更新原有的單元格外,還可以添加新的單元格到工作表中。
最後,不要忘記調用write()方法,將更新的內容寫入到文件中,然後關閉工作薄對象,這裏有兩個工作薄對象要關閉,一個是只讀的,另外一個是可寫入的。
3 JXL讀寫excel文件的例子 (來自網絡)
3.1 實例一
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import jxl.*;
import jxl.format.Alignment;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.CellFormat;
import jxl.write.Boolean;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
public class JXLExample {
/**
*
* @author smart *
*/
public static void main(String[] args) {
// 準備設置excel工作表的標題
String[] title = {"編號","產品名稱","產品價格","產品數量","生產日期","產地","是否出口"};
try {
// 獲得開始時間
long start = System.currentTimeMillis();
// 輸出的excel的路徑
String filePath = "c:\\test.xls";
// 創建Excel工作薄
WritableWorkbook wwb;
// 新建立一個jxl文件,即在C盤下生成test.xls
OutputStream os = new FileOutputStream(filePath);
wwb=Workbook.createWorkbook(os);
// 添加第一個工作表並設置第一個Sheet的名字
WritableSheet sheet = wwb.createSheet("產品清單", 0);
Label label;
for(int i=0;i<title.length;i++){
label = new Label(i,0,title[i]);
// 將定義好的單元格添加到工作表中
sheet.addCell(label);
}
/*
* 保存數字到單元格,需要使用jxl.write.Number
* 必須使用其完整路徑,否則會出現錯誤
* */
// 填充產品編號
jxl.write.Number number = new jxl.write.Number(0,1,20071001);
sheet.addCell(number);
// 填充產品名稱
label = new Label(1,1,"金鴿瓜子");
sheet.addCell(label);
/*
* 定義對於顯示金額的公共格式
* jxl會自動實現四舍五入
* 例如 2.456會被格式化為2.46,2.454會被格式化為2.45
* */
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
jxl.write.WritableCellFormat wcf = new jxl.write.WritableCellFormat(nf);
// 填充產品價格
jxl.write.Number nb = new jxl.write.Number(2,1,2.45,wcf);
sheet.addCell(nb);
// 填充產品數量
jxl.write.Number numb = new jxl.write.Number(3,1,200);
sheet.addCell(numb);
/*
* 定義顯示日期的公共格式
* 如:yyyy-MM-dd hh:mm
* */
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String newdate = sdf.format(new Date());
// 填充出產日期
label = new Label(4,1,newdate);
sheet.addCell(label);
// 填充產地
label = new Label(5,1,"陜西西安");
sheet.addCell(label);
/*
* 顯示布爾值
* */
jxl.write.Boolean bool = new jxl.write.Boolean(6,1,true);
sheet.addCell(bool);
/*
* 合並單元格
* 通過writablesheet.mergeCells(int x,int y,int m,int n);來實現的
* 表示將從第x+1列,y+1行到m+1列,n+1行合並
*
* */
sheet.mergeCells(0,3,2,3);
label = new Label(0,3,"合並了三個單元格");
sheet.addCell(label);
/*
*
* 定義公共字體格式
* 通過獲取一個字體的樣式來作為模板
* 首先通過web.getSheet(0)獲得第一個sheet
* 然後取得第一個sheet的第二列,第一行也就是"產品名稱"的字體
* */
CellFormat cf = wwb.getSheet(0).getCell(1, 0).getCellFormat();
WritableCellFormat wc = new WritableCellFormat();
// 設置居中
wc.setAlignment(Alignment.CENTRE);
// 設置邊框線
wc.setBorder(Border.ALL, BorderLineStyle.THIN);
// 設置單元格的背景顏色
wc.setBackground(jxl.format.Colour.RED);
label = new Label(1,5,"字體",wc);
sheet.addCell(label);
// 設置字體
WritableFont wfont=new WritableFont(WritableFont.createFont("隸書"),20);
WritableCellFormat font = new WritableCellFormat(wfont);
label = new Label(2,6,"隸書",font);
sheet.addCell(label);
// 寫入數據
wwb.write();
// 關閉文件
wwb.close();
long end = System.currentTimeMillis();
System.out.println("----完成該操作共用的時間是:"+(end-start)/1000);
} catch (Exception e) {
System.out.println("---出現異常---");
e.printStackTrace();
}
}
}
3.2 實例二
package com.test;
import java.io.File;
import java.io.IOException;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.format.Border;
import jxl.format.BorderLineStyle;
import jxl.format.Colour;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.WritableCellFormat;
import jxl.write.WritableFont;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;
public class JexcelSample {
/**
* 寫excel文件
*
*/
public void writeExc(File filename){
WritableWorkbook wwb = null;
try
{
wwb = Workbook.createWorkbook(filename);
}
catch (Exception e){
e.printStackTrace();
}
//創建Excel工作表
WritableSheet ws = wwb.createSheet("通訊錄", 0);//創建sheet
try {
ws.mergeCells(0, 0, 2, 1);//合並單元格(左列,左行,右列,右行)從第1行第1列到第2行第3列
Label header = new Label(0, 0, "通訊錄(191026班)", getHeader());
ws.addCell(header);//寫入頭
Label l = new Label(0, 2, "姓名", getTitle());//第3行
ws.addCell(l);
l = new Label(1, 2, "電話", getTitle());
ws.addCell(l);
l = new Label(2, 2, "地址", getTitle());
ws.addCell(l);
l = new Label(0, 3, "小祝", getNormolCell());//第4行
ws.addCell(l);
l = new Label(1, 3, "1314***0974", getNormolCell());
ws.addCell(l);
l = new Label(2, 3, "武漢武昌", getNormolCell());
ws.addCell(l);
l = new Label(0, 4, "小施", getNormolCell());//第5行
ws.addCell(l);
l = new Label(1, 4, "1347***5057", getNormolCell());
ws.addCell(l);
l = new Label(2, 4, "武漢武昌", getNormolCell());
ws.addCell(l);
ws.setColumnView(0,20);//設置列寬
ws.setColumnView(1,20);
ws.setColumnView(2,40);
ws.setRowView(0,400);//設置行高
ws.setRowView(1,400);
ws.setRowView(2,500);
ws.setRowView(3,500);
ws.setRowView(4,500);
} catch (RowsExceededException e1) {
e1.printStackTrace();
} catch (WriteException e1) {
e1.printStackTrace();
}
//輸出流
try {
wwb.write();
} catch (IOException ex) {
// TODO 自動生成 catch 塊
ex.printStackTrace();
}
//關閉流
try {
wwb.close();
} catch (WriteException ex) {
// TODO 自動生成 catch 塊
ex.printStackTrace();
} catch (IOException ex) {
// TODO 自動生成 catch 塊
ex.printStackTrace();
}
//outStream.close();
System.out.println("寫入成功!\n");
}
public void readExc(File filename) throws BiffException, IOException{
Workbook wb = Workbook.getWorkbook(filename);
Sheet s = wb.getSheet(0);//第1個sheet
Cell c = null;
int row = s.getRows();//總行數
int col = s.getColumns();//總列數
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
c = s.getCell(j,i);
System.out.print(c.getContents()+" ");
}
System.out.println();
}
}
/**
* 設置頭的樣式
* @return
*/
public static WritableCellFormat getHeader(){
WritableFont font = new WritableFont(WritableFont.TIMES, 24 ,WritableFont.BOLD);//定義字體
try {
font.setColour(Colour.BLUE);//藍色字體
} catch (WriteException e1) {
// TODO 自動生成 catch 塊
e1.printStackTrace();
}
WritableCellFormat format = new WritableCellFormat(font);
try {
format.setAlignment(jxl.format.Alignment.CENTRE);//左右居中
format.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);//上下居中
format.setBorder(Border.ALL,BorderLineStyle.THIN,Colour.BLACK);//黑色邊框
format.setBackground(Colour.YELLOW);//黃色背景
} catch (WriteException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
return format;
}
/**
* 設置標題樣式
* @return
*/
public static WritableCellFormat getTitle(){
WritableFont font = new WritableFont(WritableFont.TIMES, 14);
try {
font.setColour(Colour.BLUE);//藍色字體
} catch (WriteException e1) {
// TODO 自動生成 catch 塊
e1.printStackTrace();
}
WritableCellFormat format = new WritableCellFormat(font);
try {
format.setAlignment(jxl.format.Alignment.CENTRE);
format.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
format.setBorder(Border.ALL,BorderLineStyle.THIN,Colour.BLACK);
} catch (WriteException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
return format;
}
/**
* 設置其他單元格樣式
* @return
*/
public static WritableCellFormat getNormolCell(){//12號字體,上下左右居中,帶黑色邊框
WritableFont font = new WritableFont(WritableFont.TIMES, 12);
WritableCellFormat format = new WritableCellFormat(font);
try {
format.setAlignment(jxl.format.Alignment.CENTRE);
format.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
format.setBorder(Border.ALL,BorderLineStyle.THIN,Colour.BLACK);
} catch (WriteException e) {
// TODO 自動生成 catch 塊
e.printStackTrace();
}
return format;
}
public static void main(String[] args) throws IOException, BiffException{
JexcelSample js = new JexcelSample();
File f = new File("D:\\address.xls");
f.createNewFile();
js.writeExc(f);
js.readExc(f);
}
}
生成的excel表格如下:
4 jxl常用api
4.1.1 1、Workbook類提供的方法
int getNumberOfSheets() 獲取工作表的總個數
Sheet[] getSheets() 獲取數組型的工作表
Sheet getSheet(String name);//得到此對應名稱的工作表
4.1.2 2、Sheet接口提供的方法
String getName() 獲取工作表的名稱
int getColumns() 獲取Sheet表中所包含的總列數
Cell[] getColumn(int column) 獲取某一列的所有單元格,
返回的是單元格對象數組
int getRows() 獲取Sheet表中所包含的總行數
Cell[] getRow(int row) 獲取某一行的所有單元格,返回的是單元格對象數組
Cell getCell(int column, int row)獲取指定單元格的對象引用,需要註意的是它的兩個參數,第一個是列數,第二個是行數,這與通常的行、列組合有些不同
WritableSheet.setRowView(int i,int height); 指定第i+1行的高度
WritableSheet.setColumnView(int i,int width); 指定第i+1列的寬度
摘:JAVA JXL API的詳細使用