我们使用POI中的HSSFWorkbook来读取Excel数据。 ! F+ C& e8 T& K# D+ K/ O7 Z8 Vpublic void test(File file) throws IOException { ! @$ Y4 o) X4 m: u InputStream inp = new FileInputStream(file); 1 e& S, F1 w$ Q* O! e! y HSSFWorkbook workbook = new HSSFWorkbook(inp); 7 q/ c. `$ A1 v" g5 ? + P2 V$ Q2 ^% C/ i7 |- o
// workbook...遍历操作 , }& R& G4 S$ u. b }' @) T4 @ j: i+ E' D5 q
3 a, O2 ~$ Z% N H$ n* e6 J上边代码,读取Excel2003(xls)的文件没问题,但是一旦读取的是Excel2007(xlsx)的文件,就会报异常:“The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)”- ~4 }5 _6 @; B$ ]
查阅了资料,Excel2007版本的Excel文件需要使用XSSFWorkbook来读取,如下:8 d! L2 y% t# K) N
public void test(File file) throws IOException {. e& v% V8 r2 z' @* \! N6 ~
InputStream inp = new FileInputStream(file);( ?0 y& p* A) p2 l: _4 t7 u
XSSFWorkbook workbook = new XSSFWorkbook(inp); ) b7 [# t( D I. O' m2 V) Y 3 ?4 R; A& ~2 m! {
// workbook...遍历操作& d3 b2 M/ {4 q& C. M
}6 K0 k) _, k- ^, c9 T
注意:XSSFWorkbook需要额外导入poi-ooxml-3.9-sources.jar和poi-ooxml-schemas-3.9.jar。 ) R! s7 k" v+ A! _/ \这样,Excel2007的导入没问题了,但是导入Excel2003又报异常。3 t* L0 }! \1 X+ E
所以,在导入Excel的时候,尽量能判断导入Excel的版本,调用不同的方法。 9 [9 q, ?: m/ x" X6 `4 N) z我想到过使用文件后缀名来判断类型,但是如果有人将xlsx的后缀改为xls时,如果使用xlsx的函数来读取,结果是报错;虽然后缀名对了,但是文件内容编码等都不对。$ ~0 l1 L$ @* _3 u9 E9 X" M
最后,推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。代码如下: M2 ~3 }4 a# s3 ?. Q) G& iWorkbook wb = WorkbookFactory.create(is); 5 _* M) _2 P; v8 L+ q% a3 @# A* o" J ]7 f& }9 H
可想而知,在WorkbookFactory.create()函数中,肯定有做过对文件类型的判断,一起来看一下源码是如何判断的: / H6 `2 Q! `, r3 ^- p/** 9 Y1 S' A( s& a5 @ * Creates the appropriate HSSFWorkbook / XSSFWorkbook from 4 K7 E: M* a; O: v, K; `2 J * the given InputStream.) _( a! ^5 W; F0 B% @# H
* Your input stream MUST either support mark/reset, or; F1 E7 l6 M0 z* f/ a7 k+ W h
* be wrapped as a {@link PushbackInputStream}! * F6 p( F; {# v$ O% @6 |3 x# i7 x */ 8 K/ U/ s9 u9 ]1 e4 s/ u% t public static Workbook create(InputStream inp) throws IOException, InvalidFormatException { % }; \2 y" R' K; E; x h+ [& L // If clearly doesn't do mark/reset, wrap up! c9 O$ d2 m7 w9 e$ Z* B$ \" A0 U
if(! inp.markSupported()) { 5 q' c7 |; t5 X. ~8 i inp = new PushbackInputStream(inp, 8);7 C% u, l, y& V( C
} 1 G6 b+ X7 w5 h, T ' _, P# S. ?: F/ m2 l( W if(POIFSFileSystem.hasPOIFSHeader(inp)) { ! }4 k7 c( f( |: ~% g return new HSSFWorkbook(inp);" v3 E1 k" ?7 C# J' S5 ]8 |
}! z8 M) v S j$ L* A/ \% u
if(POIXMLDocument.hasOOXMLHeader(inp)) {) O H& j7 K; C% b6 M2 T
return new XSSFWorkbook(OPCPackage.open(inp));' ^* ^ ~2 B* o3 e2 c
}" ?4 ?4 g' p: x; O8 l0 b3 H
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");" Z3 l, A7 _2 O1 U
} ; \! w# B) I8 y/ I- E/ ]2 z! O+ S* A& f( M' X E. Z* }- l: O
可以看到,有根据文件类型来分别创建合适的Workbook对象。是根据文件的头部信息去比对进行判断的,此时,就算改了后缀名,还是一样通不过。 * A: d& }( M% a; G % u: Q; c! L! h/ `