2009年10月19日星期一

POI设定列宽度

如果想在工作表里指定列宽度的话,可以使用「HSSFSheet」类的「setColumnWidth」方法。


setColumnWidth
public void setColumnWidth(short column, short width)
set the width (in units of 1/256th of a character width) 
 
Parameters:
  column - - the column to set (0-based)
  width - - the width in units of 1/256th of a character width

指定列的序列号和宽度。宽度如果指定1的话,那就是一个文字的1/256,4个文字的宽度是1024。


另外,要取得列宽度可以使用「HSSFSheet」类的「getColumnWidth」方法。


getColumnWidth
public short getColumnWidth(short column)
get the width (in units of 1/256th of a character width ) 
 
Parameters:
  column - - the column to set (0-based) 
Returns:
  width - the width in units of 1/256th of a character width

指定列的序列号


示例程序


自己动手做一下吧。仍然按照下图准备一个Excel文件,取得从第0列到第2列的列宽、然后把第2列的列宽指定给第0列和第1列。


指定列宽


import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    short[] width = new short[3];
 
    for (int i = 0 ; i < 3 ; i++){
      width[i] = sheet.getColumnWidth((short)i);
      System.out.println(i + "列宽度:" + width[i]);
    }
 
    sheet.setColumnWidth((short)0, width[2]);
    sheet.setColumnWidth((short)1, width[2]);
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}

打开新生成的Excel文件看看。


0列宽度:1865
1列宽度:3986
2列宽度:2048

指定列宽


一个Excel文件新生成时,有自己默认的列宽度,当然我们也可以用POI来指定默认的列宽度。


指定默认的列宽度


指定默认的列宽度用「HSSFSheet」类的「setDefaultColumnWidth」方法。


setDefaultColumnWidth
public void setDefaultColumnWidth(short width)
set the default column width for the sheet (if the columns do not define 
their own width) in characters 
 
Parameters:
  width - default column width

这里要注意的就是,和刚才的方法不一样,这里的列宽度单位是1个文字,而不是刚才的一个文字的1/256。


要取得原来的默认列宽度,使用「getDefaultColumnWidth」方法。


getDefaultColumnWidth
public short getDefaultColumnWidth()
get the default column width for the sheet (if the columns do not define 
their own width) in characters 
 
Returns:
  default column width

这里的列宽度单位也是一个文字


示例程序


动手做做看吧。


import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
 
public class POISample{
  public static void main(String[] args){
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet();
 
    sheet.setDefaultColumnWidth((short)5);
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}

新生成的Excel文件打开来看看吧。


默认列宽度设定

POI合并单元格

现在再看看如果将指定的单元格进行合并操作。用POI进行合并操作,使用「HSSFSheet」类的「addMergedRegion」方法。


addMergedRegion
public int addMergedRegion(Region region)
adds a merged region of cells (hence those cells form one) 
 
Parameters:
  region - (rowfrom/colfrom-rowto/colto) to merge 
Returns:
  index of this region

合并范围必须使用「Region」类来指定,关于「Region」类的介绍如下。


「Region」类关系图


  • java.lang.Object
  • org.apache.poi.hssf.util.Region
  • public class Region extends java.lang.Object implements java.lang.Comparable

「Region」类的构造方法


Region
public Region(int rowFrom, short colFrom, int rowTo, short colTo)
--

指定范围时,从左上的单元格到右下的单元格指定,比方像下面这样。


Region(1, (short)1, 2, (short)3)

示例程序


动手做做看,还是使用原来的Excel文件。




把上图选中的单元格进行合并操作时,看下面的程序。


import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.util.Region;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    sheet.addMergedRegion(new Region(1, (short)1, 2, (short)3));
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}

把刚作成的新的Excel文件打开看看吧


POI调整工作表的显示比例

有时我们可能会手动去调整工作表Sheet的显示比例,用POI同样也能做到这一点。这时我们可以使用「HSSFSheet」类的「setZoom」方法。

setZoom
public void setZoom(int numerator, int denominator)
Sets the zoom magnication for the sheet. The zoom is expressed as a 
fraction. For example to express a zoom of 75% use 3 for the 
numerator and 4 for the denominator. 
 
Parameters:
  numerator - The numerator for the zoom magnification.
  denominator - The denominator for the zoom magnification.

这样就可以指定显示比例了,指定方法是用"numerator"÷"denominator",比方说,「setZoom(2, 1)」就是设定为200%的比例,「setZoom(3, 4)」就是设定为75%的比例。

示例程序

动手做一下吧。


import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    sheet.setZoom(2, 1);
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}

新生成的Excel文件如下图所示。


2009年9月22日星期二

Sheet里行的移动

如果要移动某一行的话,可以使用「HSSFSheet」类的「shiftRows」方法。
shiftRows
public void shiftRows(int startRow, int endRow, int n)
Shifts rows between startRow and endRow n number of rows. If you use 
a negative number, it will shift rows up. Code ensures that rows don't
wrap around. Calls shiftRows(startRow, endRow, n, false, false); 
 
Additionally shifts merged regions that are completely defined in 
these rows (ie. merged 2 cells on a row to be shifted). 
 
Parameters:
  startRow - the row to start shifting
  endRow - the row to end shifting
   n - the number of rows to shift
指定要移动的行的范围从「startRow」行到「endRow」行。「n」如果是正数就往下移动,如果为负,就往上移动。

示例程序

按下图准备一个Excel文件。























import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    sheet.shiftRows(1, 2, 2);
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}
打开新建的Sample2.xls文件看看。























从上图可以看出,第二行和第三行的内容已经移动到第四行和第五行,并覆盖原第四行和第五行的内容。但第二行到第五行的行高却维持原样没有变化。
再来看看有没有办法可以既移动内容,又可以移动行高呢?从帮助文档里可以看出,对于「shiftRows」方法,还有另外一种用法。
shiftRows
public void shiftRows(int startRow, int endRow, int n,
              boolean copyRowHeight, boolean resetOriginalRowHeight)
Shifts rows between startRow and endRow n number of rows. If you use 
a negative number, it will shift rows up. Code ensures that rows don't
wrap around 
 
Additionally shifts merged regions that are completely defined in these
rows (ie. merged 2 cells on a row to be shifted). 
 
TODO Might want to add bounds checking here 
 
Parameters:
  startRow - the row to start shifting
  endRow - the row to end shifting
  n - the number of rows to shift
  copyRowHeight - whether to copy the row height during the shift
  resetOriginalRowHeight - whether to set the original row's height
    to the default
前面3个参数和之前一样。如要使行高也一起移动的话,设置「copyRowHeight」参数为「true」。
还有,移动后,原来的行是保留原行高不变还是恢复到默认行高呢?可以设置「resetOriginalRowHeight」参数。为「true」时,则可以恢复到默认行高。反之则保留原行高不变。

示例程序

import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    sheet.shiftRows(1, 2, 2, true, true);
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}
再打开新生成的Sample2.xls文件来看看。






















从上图可以看出,移动后,原行高也被移动了,而原行则恢复到默认行高。

2009年9月20日星期日

Sheet里行的读取


要取得Sheet里的某一行,可以使用「HSSFSheet」类的「getRow」方法。
getRow
public HSSFRow getRow(int rownum)
Returns the logical row (not physical) 0-based. If you ask for a row 
that is not defined you get a null. This is to say row 4 represents 
the fifth row on a sheet. 
 
Parameters:
  rownum - row to get 
Returns:
  HSSFRow representing the rownumber or null if its not defined on the 
    sheet
利用行号取得指定的行。如果行不存在,则返回NULL。

示例程序

动手做做看。
import java.io.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
 
public class POISample{
  public static void main(String[] args){
    HSSFWorkbook workbook = new HSSFWorkbook();
 
    HSSFSheet sheet = workbook.createSheet();
 
    HSSFRow row = sheet.createRow(1);
 
    for (int i = 0 ; i < 3 ; i++){
      HSSFRow r = sheet.getRow(i);
      if (r  == null){
        System.out.println("第" + i + "行不存在。");
      }else{
        System.out.println("第" + i + "行取得成功。");
      }
    }
  }
}
上面的程序里,先创建一个Sheet,然后创建第二行(行号为1)。最后读取第一行到第三行的三行。结果如下。

第0行不存在。
第1行取得成功。
第2行不存在。
这和予想的一样。

读取有值的行

按照下图准备一个Excel文件。



import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    for (int i = 0 ; i < 3 ; i++){
      HSSFRow r = sheet.getRow(i);
      if (r  == null){
        System.out.println("第" + i + "行不存在。");
      }else{
        System.out.println("第" + i + "行取得成功。");
      }
    }
  }
}
结果如下。
第0行取得成功。
第1行取得成功。
第2行不存在。
从上面的例子可以看出,如果当前行有值的话,那么读取这一行时肯定存在。

从取得的行里获取单元格的值。

这一次从已经取得的行里获取单元格的值。仍然使用刚才的Excel文件。用getRow方法先取得行对象,再从单元格里获取值。
import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    HSSFRow row = sheet.getRow(1);
 
    HSSFCell cell = row.getCell((short)1);
    System.out.println(cell.getStringCellValue());
  }
}
结果如下。
sample
可以看出,把第二行第二列的值取出来了。

在现有的行上创建行

最后,再来试试看,在现有的行上,用「createRow」方法创建一行看看会是什么结果。还是使用刚才的Excel文件,在第二行上创建一行,再把值取出来。
import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    HSSFRow row = sheet.createRow(1);
 
    HSSFCell cell = row.getCell((short)1);
 
    System.out.println(cell.getStringCellValue());
  }
}
结果如下。
Exception in thread "main" java.lang.NullPointerException
        at POISample.main(POISample.java:35)
发生了空指针异常。本来对于已经存在的行用「createRow」方法进行创建行操作,可能你会以为会复制原来的行,但事实并非如此。
让我们在原来程序的基础上再稍作一些变化,已经存在的行用「createRow」方法进行创建行操作后,再在该行的空白单元格设上值,保存为新的文件。
import java.io.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
 
public class POISample{
  public static void main(String[] args){
    FileInputStream in = null;
    HSSFWorkbook workbook = null;
 
    try{
      in = new FileInputStream("sample.xls");
      POIFSFileSystem fs = new POIFSFileSystem(in);
      workbook = new HSSFWorkbook(fs);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try{
        in.close();
      }catch (IOException e){
        System.out.println(e.toString());
      }
    }
 
    HSSFSheet sheet = workbook.getSheetAt(0);
 
    HSSFRow row = sheet.createRow(1);
 
    HSSFCell cell = row.createCell((short)3);
    cell.setCellValue("news");
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample2.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}
执行上面程序后,打开新的Excel文件如下。























对于已经存在的行再用「createRow」方法执行的话,那从原来行里有值的单元格取值时会发生空指针异常。但如果新创建一个单元格再设值的话,那之前单元格的值也会被保留下来。虽然是猜测,不过大家可以自己亲自动手来验证一下。

Sheet里行的创建

之前仅仅新建了Sheet,虽然可以看到新建的Sheet里有无数的单元格,但还不能直接往这些单元格设值。要想往这些单元格里设值,你还必须创建行。
因此,再来看看行创建的方法。
在Sheet里创建行,使用「HSSFSheet」类的「createRow」方法。
createRow
public HSSFRow createRow(int rownum)
Create a new row within the sheet and return the high level representation 
 
Parameters:
  rownum - row number 
Returns:
  High level HSSFRow object representing a row in the sheet
创建指定行号的行。行号是从0开始的整数,最大是65535。创建行所返回的值是「HSSFRow」类对象,关于「HSSFRow」类定义的说明,以后再详细说。
创建方法很多,要说详细挺复杂。比方说,即使第一行(行号为0)和第二行不创建,也能直接创建第三行。

示例程序

亲自动手做一下吧。
import java.io.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
 
public class POISample{
  public static void main(String[] args){
    HSSFWorkbook workbook = new HSSFWorkbook();
 
    HSSFSheet sheet = workbook.createSheet();
 
    HSSFRow row = sheet.createRow(2);
 
    /* 下記はセルを作成し、セルに値を代入しています */
    HSSFCell cell = row.createCell((short)0);
    cell.setCellValue("test");
 
    FileOutputStream out = null;
    try{
      out = new FileOutputStream("sample.xls");
      workbook.write(out);
    }catch(IOException e){
      System.out.println(e.toString());
    }finally{
      try {
        out.close();
      }catch(IOException e){
        System.out.println(e.toString());
      }
    }
  }
}
在上面的程序里,生成一个Sheet,然后单独创建了第三行(行号为2),接着又创建了一个单元格,最后给这个单元格设了值。执行后,打开「sample.xls」文件看看。






















可以看到,在第三行第一列,值已经被设定好了。

HSSFSheet类定义

用POI来作成一个Sheet,可以用「HSSFSheet」类,它的类定义如下。
  • java.lang.Object
  • org.apache.poi.hssf.usermodel.HSSFSheet
  • public class HSSFSheet extends java.lang.Object
它有两个构造方法。
构建器
protected HSSFSheet(Workbook book)
Creates new HSSFSheet - called by HSSFWorkbook to create a sheet from scratch.
protected HSSFSheet(Workbook book, Sheet sheet)
Creates an HSSFSheet representing the given Sheet object.
虽然有两个构建器,但都是protected的,所以要新建Sheet,只能通过Workbook。

新建Sheet

在Workbook里新建Sheet时,还是使用「HSSFWorkbook」类的「createSheet」的方法,详细可以参照「在Workbook里创建Sheet」。
使用方法如下。
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet();

读取现有的Sheet

对于在Workbook已经存在的Sheet来说,可以用「HSSFWorkbook」类的「getSheet」方法来读取。
getSheet
public HSSFSheet getSheet(java.lang.String name)
Get sheet with the given name 
 
Parameters:
  name - of the sheet 
Returns:
  HSSFSheet with the name provided or null if it does not exist

参数为Sheet名称。
使用方法如下。
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.getSheet("sheet1")
不用Sheet名而用Sheet的序列号来取得Sheet的话,可以用「HSSFWorkbook」类的「getSheetAt」方法。
getSheetAt
public HSSFSheet getSheetAt(int index)
Get the HSSFSheet object at the given index. 
 
Parameters:
  index - of the sheet number (0-based physical & logical) 
Returns:
  HSSFSheet at the provided index
使用方法如下。
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.getSheetAt(1);