ChiefSailor的歪酷Blog
 
chiefsailor @ 2008-01-01 00:33

Windows Live Space也停止提供博客空间了,所以现在所有博客都发表在 http://www.chiefsailor.net/blog ,欢迎访问!


----------------------------------------------------------------------------------------


以后的技术类文章集散地--chiefsailor的专栏
 
以后的生活文章集散地--chiefsailor的space空间
http://vickbond.spaces.live.com


——

chiefsailor记于2006.11.8日凌晨


-----------------------------------------------------------------------------------------


鉴于csdn博客的访问速度越来越慢,而且经常功能不好使,将技术博客迁移至新的主机上

http://www.haitingzhang.cn/wordpress/

欢迎访问!





 
chiefsailor @ 2006-11-05 22:05

作者:李小敏    本文选自:IBM DW中国  2002年08月21日  
 
所有的程序开发手册都包含了各种规则。一些习惯自由程序人员可能对这些规则很不适应,但是在多个开发人员共同写作的情况

下,这些规则是必需的。这不仅仅是为了开发效率来考虑,而且也是为了后期维护考虑。   

命名规范

定义这个规范的目的是让项目中所有的文档都看起来像一个人写的,增加可读性,减少项目组中因为换人而带来的损失。(这些

规范并不是一定要绝对遵守,但是一定要让程序有良好的可读性) 

● Package 的命名 

Package 的名字应该都是由一个小写单词组成。 

● Class 的命名 

Class 的名字必须由大写字母开头而其他字母都小写的单词组成 

● Class 变量的命名 

变量的名字必须用一个小写字母开头。后面的单词用大写字母开头。 

● Static Final 变量的命名 

Static Final 变量的名字应该都大写,并且指出完整含义。 

● 参数的命名 

参数的名字必须和变量的命名规范一致。 

● 数组的命名 

数组应该总是用下面的方式来命名: 

    byte[] buffer;
而不是: 
    byte buffer[];

● 方法的参数 

使用有意义的参数命名,如果可能的话,使用和要赋值的字段一样的名字: 

    SetCounter(int size){
    this.size = size;

    


Java 文件样式

所有的 Java(*.java) 文件都必须遵守如下的样式规则: 

● 版权信息 

版权信息必须在 java 文件的开头,比如: 

 /**
 * Copyright ?2000 Shanghai XXX Co. Ltd.
 * All right reserved.
 */

 其他不需要出现在 javadoc 的信息也可以包含在这里。 

● Package/Imports 

package 行要在 import 行之前,import 中标准的包名要在本地的包名之前,而且按照字母顺序排列。如果 import 行中包含

了同一个包中的不同子目录,则应该用 * 来处理。 

package hotlava.net.stats;
import java.io.*;
import java.util.Observable;
import hotlava.util.Application;

这里 java.io.* 使用来代替InputStream and OutputStream 的。 

● Class 

接下来的是类的注释,一般是用来解释类的。 

 /**
 * A class representing a set of packet and byte counters
 * It is observable to allow it to be watched, but only
 * reports changes when the current set is complete
 */

接下来是类定义,包含了在不同的行的 extends 和 implements : 

   public class CounterSet
        extends Observable
        implements Cloneable
   
 


● Class Fields 

接下来是类的成员变量: 

 /**
 * Packet counters
 */
protected int[] packets;

public 的成员变量必须生成文档(JavaDoc)。proceted、private和 package 定义的成员变量如果名字含义明确的话,可以

没有注释。 

● 存取方法 

接下来是类变量的存取的方法。它只是简单的用来将类的变量赋值获取值的话,可以简单的写在一行上。 

 /**
 * Get the counters
 * @return an array containing the statistical data.  This array has been
 * freshly allocated and can be modified by the caller.
 */
public int[] getPackets() { return copyArray(packets, offset); }
public int[] getBytes() { return copyArray(bytes, offset); }

public int[] getPackets() { return packets; }
public void setPackets(int[] packets) { this.packets = packets; }

● 构造函数 

接下来是构造函数,它应该用递增的方式写(比如:参数多的写在后面)。 

访问类型 ("public", "private" 等.) 和 任何 "static", "final" 或 "synchronized" 应该在一行中,并且方法和参数

另写一行,这样可以使方法和参数更易读。 

public
CounterSet(int size){
  this.size = size;
}
   

● 克隆方法 

如果这个类是可以被克隆的,那么下一步就是 clone 方法: 

public
Object clone() {
  try {
    CounterSet obj = (CounterSet)super.clone();
    obj.packets = (int[])packets.clone();
    obj.size = size;
    return obj;
  }catch(CloneNotSupportedException e) {
    throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());
  }
}
   
 


● 类方法 

下面开始写类的方法: 

 /**
 * Set the packet counters
 * (such as when restoring from a database)
 */
protected final
void setArray(int[] r1, int[] r2, int[] r3, int[] r4)
  throws IllegalArgumentException
{
  //
  // Ensure the arrays are of equal size
  //
  if (r1.length != r2.length || r1.length != r3.length || r1.length != r4.length)
    throw new IllegalArgumentException("Arrays must be of the same size");
  System.arraycopy(r1, 0, r3, 0, r1.length);
  System.arraycopy(r2, 0, r4, 0, r1.length);
}
   
 


● toString 方法 

无论如何,每一个类都应该定义 toString 方法: 

public
String toString() {
  String retval = "CounterSet: ";
    for (int i = 0; i<data.length(); i++) {
      retval += data.bytes.toString();
      retval += data.packets.toString();
    }
    return retval;
  }
}

● main 方法 

如果main(String[]) 方法已经定义了,那么它应该写在类的底部。 

 


代码编写格式

● 代码样式 

代码应该用 unix 的格式,而不是 windows 的(比如:回车变成回车+换行) 。 

● 文档化 

必须用 javadoc 来为类生成文档。不仅因为它是标准,这也是被各种 java 编译器都认可的方法。使用 @author 标记是不被

推荐的,因为代码不应该是被个人拥有的。 

● 缩进 

缩进应该是每行2个空格。不要在源文件中保存Tab字符。在使用不同的源代码管理工具时Tab字符将因为用户设置的不同而扩展为

不同的宽度。 

如果你使用 UltrEdit 作为你的 Java 源代码编辑器的话,你可以通过如下操作来禁止保存Tab字符,方法是通过 UltrEdit中

先设定 Tab 使用的长度室2个空格,然后用 Format|Tabs to Spaces 菜单将 Tab 转换为空格。 

● 页宽 

页宽应该设置为80字符。源代码一般不会超过这个宽度,并导致无法完整显示,但这一设置也可以灵活调整。在任何情况下,超

长的语句应该在一个逗号或者一个操作符后折行。一条语句折行后,应该比原来的语句再缩进2个字符。 

● {} 对 

{} 中的语句应该单独作为一行。例如,下面的第1行是错误的第2行是正确的: 

if (i>0) { i ++ }; // 错误, { 和 } 在同一行 
if (i>0) { 
i ++ 
};       // 正确, { 单独作为一行 
} 语句永远单独作为一行。 

如果 } 语句应该缩进到与其相对应的 { 那一行相对齐的位置。 

● 括号 

左括号和后一个字符之间不应该出现空格,同样,右括号和前一个字符之间也不应该出现空格。下面的例子说明括号和空格的错

误及正确使用: 

CallProc( AParameter ); // 错误
CallProc(AParameter); // 正确

不要在语句中使用无意义的括号。括号只应该为达到某种目的而出现在源代码中。下面的例子说明错误和正确的用法: 

if ((I) = 42) { // 错误 - 括号毫无意义
if (I == 42) or (J == 42) then // 正确 - 的确需要括号

程序编写规范
● exit() 

exit除了在main中可以被调用外,其他的地方不应该调用。因为这样做不给任何代码代码机会来截获退出。一个类似后台服务地

程序不应该因为某一个库模块决定了要退出就退出。 

● 异常 

申明的错误应该抛出一个RuntimeException或者派生的异常。 

顶层的main()函数应该截获所有的异常,并且打印(或者记录在日志中)在屏幕上。 

● 垃圾收集 

JAVA使用成熟的后台垃圾收集技术来代替引用计数。但是这样会导致一个问题:你必须在使用完对象的实例以后进行清场工作。

比如一个prel的程序员可能这么写: 

   ...
    {
        FileOutputStream fos = new FileOutputStream(projectFile);
        project.save(fos, "IDE Project File"); 
    }
    ...

除非输出流一出作用域就关闭,非引用计数的程序语言,比如JAVA,是不能自动完成变量的清场工作的。必须象下面一样写: 

    FileOutputStream fos = new FileOutputStream(projectFile);
    project.save(fos, "IDE Project File"); 
    fos.close();

● Clone 

下面是一种有用的方法: 

    implements Cloneable

  public
    Object clone()
    {
      try {
        ThisClass obj = (ThisClass)super.clone();
        obj.field1 = (int[])field1.clone();
        obj.field2 = field2;
        return obj;
      } catch(CloneNotSupportedException e) {
        throw new InternalError("Unexpected CloneNotSUpportedException: " + e.getMessage());
      }
  } 
    
 
● final 类 

绝对不要因为性能的原因将类定义为 final 的(除非程序的框架要求)。 

如果一个类还没有准备好被继承,最好在类文档中注明,而不要将她定义为 final 的。这是因为没有人可以保证会不会由于什么

原因需要继承她。 

● 访问类的成员变量 

大部分的类成员变量应该定义为 protected 的来防止继承类使用他们。 

注意,要用"int[] packets",而不是"int packets[]",后一种永远也不要用。 

      public void setPackets(int[] packets) { this.packets = packets; }

      CounterSet(int size)
        {
          this.size = size;
        }
   
● Utility 类 

Utility 类(仅仅提供方法的类)应该被申明为抽象的来防止被继承或被初始化。 

● 初始化 

下面的代码是一种很好的初始化数组的方法: 

objectArguments = new Object[] { arguments }; 

● 枚举类型 

JAVA 对枚举的支持不好,但是下面的代码是一种很有用的模板: 

  class Colour {
  public static final Colour BLACK = new Colour(0, 0, 0);
  public static final Colour RED = new Colour(0xFF, 0, 0);
  public static final Colour GREEN = new Colour(0, 0xFF, 0);
  public static final Colour BLUE = new Colour(0, 0, 0xFF);
  public static final Colour WHITE = new Colour(0xFF, 0xFF, 0xFF);

    
 
这种技术实现了RED, GREEN, BLUE 等可以象其他语言的枚举类型一样使用的常量。 他们可以用 '==' 操作符来比较。 

但是这样使用有一个缺陷:如果一个用户用这样的方法来创建颜色 BLACK 

new Colour(0,0,0) 

那么这就是另外一个对象,'=='操作符就会产生错误。她的 equal() 方法仍然有效。由于这个原因,这个技术的缺陷最好注明

在文档中,或者只在自己的包中使用。 


●Swing

避免使用 AWT 组件 

● 混合使用 AWT 和 Swing 组件 

如果要将 AWT 组件和 Swing 组件混合起来使用的话,请小心使用。实际上,尽量不要将他们混合起来使用。 

● 滚动的 AWT 组件 

AWT 组件绝对不要用 JscrollPane 类来实现滚动。滚动 AWT 组件的时候一定要用 AWT ScrollPane 组件来实现。 

● 避免在 InternalFrame 组件中使用 AWT 组件 

尽量不要这么做,要不然会出现不可预料的后果。 

● Z-Order 问题 

AWT 组件总是显示在 Swing 组件之上。当使用包含 AWT 组件的 POP-UP 菜单的时候要小心,尽量不要这样使用。 


调试


调试在软件开发中是一个很重要的部分,存在软件生命周期的各个部分中。调试能够用配置开、关是最基本的。 

很常用的一种调试方法就是用一个 PrintStream 类成员,在没有定义调试流的时候就为 null,类要定义一个 debug 方法来设

置调试用的流。 


性能


● 在写代码的时候,从头至尾都应该考虑性能问题。这不是说时间都应该浪费在优化代码上,而是我们时刻应该提醒自己要注意

代码的效率。比如:如果没有时间来实现一个高效的算法,那么我们应该在文档中记录下来,以便在以后有空的时候再来实现她

。 

不是所有的人都同意在写代码的时候应该优化性能这个观点的,他们认为性能优化的问题应该在项目的后期再去考虑,也就是在

程序的轮廓已经实现了以后。 

● 不必要的对象构造 

不要在循环中构造和释放对象。 

使用 StringBuffer 对象: 

在处理 String 的时候要尽量使用 StringBuffer 类,StringBuffer 类是构成 String 类的基础。String 类将 

StringBuffer 类封装了起来,(以花费更多时间为代价)为开发人员提供了一个安全的接口。当我们在构造字符串的时候,我

们应该用 StringBuffer 来实现大部分的工作,当工作完成后将 StringBuffer 对象再转换为需要的 String 对象。比如:如

果有一个字符串必须不断地在其后添加许多字符来完成构造,那么我们应该使用 StringBuffer 对象和她的 append() 方法。

如果我们用 String 对象代替 StringBuffer 对象的话,会花费许多不必要的创建和释放对象的 CPU 时间。 

● 避免太多的使用 synchronized 关键字 

避免不必要的使用关键字 synchronized,应该在必要的时候再使用她,这是一个避免死锁的好方法。 


可移植性

Borland Jbulider 不喜欢 synchronized 这个关键字,如果你的断点设在这些关键字的作用域内的话,调试的时候你会发现的

断点会到处乱跳,让你不知所措。除非必须,尽量不要使用。 

● 换行 

如果需要换行的话,尽量用 println 来代替在字符串中使用"\n"。 

你不要这样: 

System.out.print("Hello,world!\n"); 

要这样: 

System.out.println("Hello,world!"); 

或者你构造一个带换行符的字符串,至少要象这样: 

String newline = System.getProperty("line.separator"); 

System.out.println("Hello world" + newline); 

● PrintStream 

PrintStream 已经被不赞成(deprecated)使用,用 PrintWrite 来代替她。




 
chiefsailor @ 2006-10-26 15:49

  至今仍然用着当初买的西门子的小2,当初它是那么的火爆。但是今天,似乎西门子手机即将真正的退出历史舞台。

  大约一年前,西门子手机被明基收购。不过当初的感受不是很深,毕竟是西门子把手机业务送给了明基,并同时给了2.5亿欧元。当时想西门子以后就会变成国产品牌,也曾经幻想过下一部手机还是出自严谨认真的德国工程师的手中。

  但是,所谓的成也萧何,败也萧何,似乎从来都没有少过印证的例子。

  德国的人的严谨认真成就了伟大的日耳曼民族,使她的磁悬浮列车可以高速的奔跑,也造就了西门子这个有着158年历史的庞大企业。但是,今天,它的严谨认真似乎同样造成了自己的毁灭。当一个企业面临着业务严重下降的时候,西门子的欧洲员工们仍然不紧不慢的开展着他们的开发业务,尤其是其中的手机软件开发。德国人拒绝了加班,同样也是德国人也拒绝销售不稳定的西门子新推出的旗舰手机。

  除了惋惜,似乎更多的是无奈。无论是我,还是李焜耀。

        链接:南方周末--明基兵败西门子始末
  http://www.donews.com/Content/200610/298e4d15-6c78-4f08-924c-cf5f227d8f03.shtm



 
chiefsailor @ 2006-10-23 21:43

关键词: 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();

}
}
}



 
chiefsailor @ 2006-10-23 21:36

摘要:使用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);
支持字体、数字、日期的格式化;
支持单元格的阴影操作,以及颜色操作;
修改已经存在的数据表;
现在还不支持以下功能,但不久就会提供了:

不能够读取图表信息;
可以读,但是不能生成公式,任何类型公式最后的计算值都可以读出; 

应用示例

1 从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);

2 生成新的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电子表格。

接下来就是要创建工作表,创建工作表的方法与创建工作薄的方法几乎一样,同样是通过工厂模式方法获得相应的对象,该方法需要两个参数,一个是工作表的名称,另一个是工作表在工作薄中的位置,参考下面的代码片段:


//创建Excel工作表
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);


"这锅也支好了,材料也准备齐全了,可以开始下锅了!",现在要做的只是实例化API所提供的Excel基本数据类型,并将它们添加到工作表中就可以了,参考下面的代码片段:

//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(labelB);

//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工作薄对象,以释放占用的内存,参见下面的代码片段:


//写入Exel工作表
wwb.write();

//关闭Excel工作薄对象
wwb.close();

这可能与读取Excel文件的操作有少少不同,在关闭Excel对象之前,你必须要先调用write()方法,因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文件中。如果你先关闭了Excel对象,那么只能得到一张空的工作薄了。

3 拷贝、更新Excel工作薄

接下来简要介绍一下如何更新一个已经存在的工作薄,主要是下面二步操作,第一步是构造只读的Excel工作薄,第二步是利用已经创建的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段:(完整代码见ExcelModifying.java)


//创建只读的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()方法,将更新的内容写入到文件中,然后关闭工作薄对象,这里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的。



 
日历
网志分类
· 所有网志
· 生活点滴
· 学习生涯
· 物语
· 我贫我掰
· C/C++
· 技术文档
· .NET
· JAVA
· Linux
· Network
· Database
精华文章
人生必看十大动画片
历届奥斯卡奖获奖名单回顾
帮你参悟人生十个故事
冷评热论央视记者
考研吧,悟空!
国内热门软件作者真人照片(多图)
C++程序设计之四书五经(上)
C++程序设计之四书五经(下)
C++资源之不完全导引(上)
C++资源之不完全导引(下)
最新博客地址
Chiefsailor的博客