我们使用POI中的HSSFWorkbook来读取Excel数据。 + D; t9 s; n# V) p$ p* `+ |; Ipublic void test(File file) throws IOException { # V& j3 o4 W# D InputStream inp = new FileInputStream(file);! G! [ e, d$ x$ l
HSSFWorkbook workbook = new HSSFWorkbook(inp);. q2 Y: m) K, R, L' ~9 f- O w
4 y- b+ y l2 N) e1 L // workbook...遍历操作 1 \( M' w; j& N }/ M. s$ f' f- Q' z( C
+ j* U ?+ L* ]+ N5 V
上边代码,读取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)” ! ~/ T# T3 U' J6 l) {& L9 m查阅了资料,Excel2007版本的Excel文件需要使用XSSFWorkbook来读取,如下: " t. `: m4 Q1 i' n( t- t+ Cpublic void test(File file) throws IOException {' d6 e( v' V, ?, h5 ^! _9 N2 ^) _2 i/ c
InputStream inp = new FileInputStream(file);0 j" s- B& q- X+ c/ ^# V; ~
XSSFWorkbook workbook = new XSSFWorkbook(inp); ( m. R# D" X5 M b: F' T$ q9 ]6 B/ |3 }! m
// workbook...遍历操作 : h' Q5 _/ t3 ]8 x, h } g- @6 W" u7 Y- Y5 }
注意:XSSFWorkbook需要额外导入poi-ooxml-3.9-sources.jar和poi-ooxml-schemas-3.9.jar。 1 A& X% y" |7 u1 B5 i# s# F这样,Excel2007的导入没问题了,但是导入Excel2003又报异常。* t6 i8 G: R/ P Z" W( U9 {9 q* _6 z. b
所以,在导入Excel的时候,尽量能判断导入Excel的版本,调用不同的方法。 7 P% X1 R( [; p我想到过使用文件后缀名来判断类型,但是如果有人将xlsx的后缀改为xls时,如果使用xlsx的函数来读取,结果是报错;虽然后缀名对了,但是文件内容编码等都不对。 + ~+ l2 u& G7 E# l; f o8 d5 k最后,推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。代码如下: / `8 h) [% p+ N& ?Workbook wb = WorkbookFactory.create(is);4 Y; j5 P( z, ]' d6 W
6 j5 A" z& n0 u' k9 i8 r+ Q# C2 ?
可想而知,在WorkbookFactory.create()函数中,肯定有做过对文件类型的判断,一起来看一下源码是如何判断的:3 b( z9 }9 e$ H
/**; `6 V$ {! T1 g# p; h0 G+ _ d" ~
* Creates the appropriate HSSFWorkbook / XSSFWorkbook from/ |1 W2 O, C* M, l5 [
* the given InputStream. " p% E, ?1 u* r! B. m8 @ * Your input stream MUST either support mark/reset, or 1 H) C) Z$ c- E" l1 k3 @ * be wrapped as a {@link PushbackInputStream}! , H: q5 M. W0 d. I2 C8 h */ ! X `5 F: e; m5 _( [ public static Workbook create(InputStream inp) throws IOException, InvalidFormatException { ( D9 b6 Q6 O+ K) m: X1 r // If clearly doesn't do mark/reset, wrap up+ @ E1 {) {6 U1 U
if(! inp.markSupported()) {6 P# M, U2 Z3 a5 ?2 ~( q+ l
inp = new PushbackInputStream(inp, 8); ) V! I; z6 y" ~! m5 ? } : O$ J3 J$ {, z8 h$ }% T0 V* q# f 7 h8 l! Y3 b+ ^" ]* e8 U if(POIFSFileSystem.hasPOIFSHeader(inp)) {7 v# Z* b H- V9 x
return new HSSFWorkbook(inp); 4 X( N; h# i' \ }2 `3 x+ T) n; P- n
if(POIXMLDocument.hasOOXMLHeader(inp)) {# F- `7 X m; m4 t
return new XSSFWorkbook(OPCPackage.open(inp)); ) d4 q3 ?, r8 j |+ k& y9 T }' \0 I$ \& m/ f& M2 p- G2 _
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");. x! ?9 R# t! i7 P7 K0 m
}# F1 r/ a* v; d/ K
" a; [! h5 Z6 Q3 v$ d8 @/ O' |可以看到,有根据文件类型来分别创建合适的Workbook对象。是根据文件的头部信息去比对进行判断的,此时,就算改了后缀名,还是一样通不过。5 Z) d" V5 t8 e4 P8 m5 P