POI是Apache的Jakata项目,POI 代表 Poor Obfuscation Implementation,即不良模糊化实现。POI 的目标就是提供一组 Java API 来使得基于 Microsoft OLE 2 Compound Document 格式的 Microsoft Office 文件易于操作。

POI的jar包现在为3.6版本的了,在网上搜索一下可以搜到2.5版本、3.01版本、3.5版本的,而且每个版本之间的差异很大。由于公司项目需要Excel的导入导出功能,而且公司项目中的POI jar包为2.5版本的,所以只能基于POI-2.5.1.jar进行开发。

POI的jar包主要包括以下几个:
poi-2.5.1-final-20040804.jar
poi-contrib-2.5.1-final-20040804.jar
poi-scratchpad-2.5.1-final-20040804.jar

在网上搜索了这几个包分别的作用,暂时没有查到,一般的文件操作只用第一个jar包就可以了。POI包中提供了一些HSSF对象的API。

HSSF 代表 Horrible Spreadsheet Format(可怕的电子表格格式)。HSSF提供给用户使用的对象在org.apache.poi.hssf.usermodel包中,主要部分包括Excell对象,样式和格式,还有辅助操作。有以下几种对象:
HSSFWorkbook excell的文档对象
HSSFSheet excell的表单
HSSFRow excell的行
HSSFCell excell的格子单元
HSSFFont excell字体
HSSFName 名称
HSSFDataFormat 日期格式
辅助操作包括
HSSFDateUtil 日期
HSSFPrintSetup 打印
HSSFErrorConstants 错误信息表
在poi1.7中才有以下3项:
HSSFHeader sheet头
HSSFFooter sheet尾
HSSFCellStyle cell样式


创建一个Excel的例子:


HSSFWorkbook workbook = new HSSFWorkbook(); // 产生工作簿对象 

HSSFSheet sheet = workbook.createSheet(); // 产生工作表对象 

// 设置第一个工作表的名称为firstSheet,为了工作表能支持中文,设置字符编码为UTF_16 

workbook.setSheetName(0, "firstSheet", HSSFWorkbook.ENCODING_COMPRESSED_UNICODE); 

// 产生一行 

HSSFRow row = sheet.createRow((short) 0); 

// 产生第一个单元格 

HSSFCell cell = row.createCell((short) 0); 

// 设置单元格内容为字符串型 

cell.setCellType(HSSFCell.CELL_TYPE_BOOLEAN); 

// 为了能在单元格中写入中文,设置字符编码为UTF_16。 

cell.setEncoding(HSSFCell.ENCODING_UTF_16); 

// 往第一个单元格中写入信息 

cell.setCellValue("测试成功"); 

FileOutputStream fOut = new FileOutputStream(xlsFile); 

workbook.write(fOut); 

fOut.flush(); 

fOut.close(); 

System.out.println("文件生成..."); 

// 以下语句读取生成的Excel文件内容 

FileInputStream fIn = new FileInputStream(xlsFile); 

HSSFWorkbook readWorkBook = new HSSFWorkbook(fIn); 

HSSFSheet readSheet = readWorkBook.getSheet("firstSheet"); 

HSSFRow readRow = readSheet.getRow(0); 

HSSFCell readCell = readRow.getCell((short) 0); 

System.out.println("第一个单元是:" + readCell.getStringCellValue());




从上面的一个例子,基本上可以明白POI操作Excel的一些方法与步骤,要生成一个HSSFWorkbook工作簿对象,关键是要有一个文件输入输出流对象,而这个IO留对象可以来自文件上的一个文件也可以来自上传时候得到的一个输入流对象(导入Excel的时候,可以得到Excel的输入流,将Excel里的数据写入数据库,这样就可以完成Excel的导入并且不需要将Excel上传到服务器。用struts上传就可以使用这种方式。)。得到了一个HSSFWorkbook工作簿对象,就可以做一些读取或写入或修改样式的操作了。

1)excel中只要是数字就是double型的通过cellgetNumericCellValue()读取
2)在excel中一份workbook中可能会有好几个表格,这些表格的顺序是从0开始的;行列也都是从下标0开始的。

网上关于POI的操作例子多半是关于Excel的操作,其实POI也能读写word,ppt,以下就是在网上找到的一个读写word实例:

import java.io.ByteArrayInputStream; 

import java.io.File; 

import java.io.FileInputStream; 

import java.io.FileOutputStream; 

import java.io.IOException; 

import java.io.InputStream; 

import java.util.ArrayList; 


import org.apache.poi.poifs.filesystem.DirectoryEntry; 

import org.apache.poi.poifs.filesystem.DocumentEntry; 

import org.apache.poi.poifs.filesystem.DocumentInputStream; 

import org.apache.poi.poifs.filesystem.POIFSFileSystem; 

import org.apache.poi.util.LittleEndian; 


public class WordExtractor { 

 public WordExtractor() { 

 } 


 public String extractText(InputStream in) throws IOException { 

 ArrayList text = new ArrayList(); 

 POIFSFileSystem fsys = new POIFSFileSystem(in); 


 DocumentEntry headerProps = (DocumentEntry) fsys.getRoot().getEntry( 

 "WordDocument"); 

 DocumentInputStream din = fsys 

 .createDocumentInputStream("WordDocument"); 

 byte[] header = new byte[headerProps.getSize()]; 


 din.read(header); 

 din.close(); 

 // Prende le informazioni dall'header del documento 

 int info = LittleEndian.getShort(header, 0xa); 


 boolean useTable1 = (info & 0x200) != 0; 


 // boolean useTable1 = true; 


 // Prende informazioni dalla piece table 

 int complexOffset = LittleEndian.getInt(header, 0x1a2); 

 // int complexOffset = LittleEndian.getInt(header); 


 String tableName = null; 

 if (useTable1) { 

 tableName = "1Table"; 

 } else { 

 tableName = "0Table"; 

 } 


 DocumentEntry table = (DocumentEntry) fsys.getRoot() 

 .getEntry(tableName); 

 byte[] tableStream = new byte[table.getSize()]; 


 din = fsys.createDocumentInputStream(tableName); 


 din.read(tableStream); 

 din.close(); 


 din = null; 

 fsys = null; 

 table = null; 

 headerProps = null; 


 int multiple = findText(tableStream, complexOffset, text); 


 StringBuffer sb = new StringBuffer(); 

 int size = text.size(); 

 tableStream = null; 


 for (int x = 0; x < size; x++) { 


 WordTextPiece nextPiece = (WordTextPiece) text.get(x); 

 int start = nextPiece.getStart(); 

 int length = nextPiece.getLength(); 


 boolean unicode = nextPiece.usesUnicode(); 

 String toStr = null; 

 if (unicode) { 

 toStr = new String(header, start, length * multiple, "UTF-16LE"); 

 } else { 

 toStr = new String(header, start, length, "ISO-8859-1"); 

 } 

 sb.append(toStr).append(" "); 


 } 

 return sb.toString(); 

 } 


 private static int findText(byte[] tableStream, int complexOffset, 

 ArrayList text) throws IOException { 

 // actual text 

 int pos = complexOffset; 

 int multiple = 2; 

 // skips through the prms before we reach the piece table. These contain 

 // data 

 // for actual fast saved files 

 while (tableStream[pos] == 1) { 

 pos++; 

 int skip = LittleEndian.getShort(tableStream, pos); 

 pos += 2 + skip; 

 } 

 if (tableStream[pos] != 2) { 

 throw new IOException("corrupted Word file"); 

 } else { 

 // parse out the text pieces 

 int pieceTableSize = LittleEndian.getInt(tableStream, ++pos); 

 pos += 4; 

 int pieces = (pieceTableSize - 4) / 12; 

 for (int x = 0; x < pieces; x++) { 

 int filePos = LittleEndian.getInt(tableStream, pos 

 + ((pieces + 1) * 4) + (x * 8) + 2); 

 boolean unicode = false; 

 if ((filePos & 0x40000000) == 0) { 

 unicode = true; 

 } else { 

 unicode = false; 

 multiple = 1; 

 filePos &= ~(0x40000000); // gives me FC in doc stream 

 filePos /= 2; 

 } 

 int totLength = LittleEndian.getInt(tableStream, pos + (x + 1) 

 * 4) 

 - LittleEndian.getInt(tableStream, pos + (x * 4)); 


 WordTextPiece piece = new WordTextPiece(filePos, totLength, 

 unicode); 

 text.add(piece); 


 } 


 } 

 return multiple; 

 } 


 public boolean writeWordFile(String path, String content) { 

 boolean w = false; 

 try { 


 // byte b[] = content.getBytes("ISO-8859-1"); 

 byte b[] = content.getBytes(); 


 ByteArrayInputStream bais = new ByteArrayInputStream(b); 


 POIFSFileSystem fs = new POIFSFileSystem(); 

 DirectoryEntry directory = fs.getRoot(); 


 DocumentEntry de = directory.createDocument("WordDocument", bais); 


 FileOutputStream ostream = new FileOutputStream(path); 


 fs.writeFilesystem(ostream); 


 bais.close(); 

 ostream.close(); 


 } catch (IOException e) { 

 e.printStackTrace(); 

 } 


 return w; 

 } 


 public static void main(String[] args) { 

 WordExtractor w = new WordExtractor(); 

 POIFSFileSystem ps = new POIFSFileSystem(); 

 try { 


 File file = new File("C:\\test.doc"); 


 InputStream in = new FileInputStream(file); 

 String s = w.extractText(in); 

 System.out.println(s); 


 w.writeWordFile("D:\\test.doc", "hello "); 

 } catch (Exception e) { 

 e.printStackTrace(); 

 } 


 } 


} 


class WordTextPiece { 

 private int _fcStart; 

 private boolean _usesUnicode; 

 private int _length; 


 public WordTextPiece(int start, int length, boolean unicode) { 

 _usesUnicode = unicode; 

 _length = length; 

 _fcStart = start; 

 } 


 public boolean usesUnicode() { 

 return _usesUnicode; 

 } 


 public int getStart() { 

 return _fcStart; 

 } 


 public int getLength() { 

 return _length; 

 } 


}