我们使用POI中的HSSFWorkbook来读取Excel数据。 ! W* k' T5 J- |6 vpublic void test(File file) throws IOException { 5 T% O, L5 [' g! h) z, X InputStream inp = new FileInputStream(file); ; q0 p; E+ i9 G, Z* m" o8 l HSSFWorkbook workbook = new HSSFWorkbook(inp); + T" y9 Z" F& c6 J 4 b0 O! w# O' C7 v // workbook...遍历操作. u/ Z! T& n1 t$ F
}- J. m- i8 j. u
3 U* B% Q; c6 |3 s! ~- @; Y
上边代码,读取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)” + i9 t2 H+ q- d/ O. b# m查阅了资料,Excel2007版本的Excel文件需要使用XSSFWorkbook来读取,如下:, O! X/ r9 j( l: R. X) V" Y
public void test(File file) throws IOException { ( X$ N! g4 k3 c) I/ | InputStream inp = new FileInputStream(file); $ d$ ]* s L1 A$ [) z, ` E- O: q" R- e XSSFWorkbook workbook = new XSSFWorkbook(inp);" O% y9 d* S' i, F! d
9 N* ^# I: d; [; L
// workbook...遍历操作, v# A# h# H. a: V
} 5 Q6 i6 F M! w9 D9 i/ _注意:XSSFWorkbook需要额外导入poi-ooxml-3.9-sources.jar和poi-ooxml-schemas-3.9.jar。0 W4 u ]0 I3 g, X
这样,Excel2007的导入没问题了,但是导入Excel2003又报异常。. Q; Y( `" Z) _% ^* ~" u
所以,在导入Excel的时候,尽量能判断导入Excel的版本,调用不同的方法。 " J6 ~* W& C# H& u( t6 t% g+ {我想到过使用文件后缀名来判断类型,但是如果有人将xlsx的后缀改为xls时,如果使用xlsx的函数来读取,结果是报错;虽然后缀名对了,但是文件内容编码等都不对。7 [9 Y: {& n: V/ Z) G6 g6 x F, |/ r
最后,推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。代码如下: + H `* {2 n6 f5 r4 r; K' ~Workbook wb = WorkbookFactory.create(is); 8 D. M# n1 K& \+ `9 s- ]# m2 \3 {" b- o2 T/ R
可想而知,在WorkbookFactory.create()函数中,肯定有做过对文件类型的判断,一起来看一下源码是如何判断的: $ c- _0 k' p, H3 r" j6 C/**: e0 r9 _* u B9 `7 U! z
* Creates the appropriate HSSFWorkbook / XSSFWorkbook from : n! i9 N* m! M* Q * the given InputStream.: T/ k/ U' Z+ s1 Y0 e
* Your input stream MUST either support mark/reset, or7 Z2 w$ \6 |7 \
* be wrapped as a {@link PushbackInputStream}! ; y4 T1 j# J; K7 D& h9 Y1 {& b */, d. @: Y d+ L" T; q
public static Workbook create(InputStream inp) throws IOException, InvalidFormatException {5 ~" N5 v1 m& D8 a1 F8 s
// If clearly doesn't do mark/reset, wrap up2 ]8 A" g I/ C, F3 ~ }
if(! inp.markSupported()) {( R7 b; Y" C4 O! R" ]# a) K
inp = new PushbackInputStream(inp, 8); n* Z. q# ?8 G* {( y- l' L. s } ; u3 m' ]9 l! h & F6 X5 |4 o9 w0 V5 n6 f7 J" e4 [ if(POIFSFileSystem.hasPOIFSHeader(inp)) {% X$ S- ^9 g- X
return new HSSFWorkbook(inp);, C+ U: G% o2 u/ Y. u$ {4 E
} 0 X' ?( v4 \0 @9 }! s0 C9 u if(POIXMLDocument.hasOOXMLHeader(inp)) {4 C& | _ m3 Z: S4 Z, c# `
return new XSSFWorkbook(OPCPackage.open(inp));! W2 P4 ~) L! f8 c* z
} % l& b: C- A6 s) ?1 Y. e throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); 9 W" }2 t: D# O% P; i' g } ! h5 S& v5 s6 d' _ _1 P 5 j; w, c, U3 L" j2 L可以看到,有根据文件类型来分别创建合适的Workbook对象。是根据文件的头部信息去比对进行判断的,此时,就算改了后缀名,还是一样通不过。$ c1 F7 }, c6 Z7 v* ~
D& |7 A9 `! G2 \! K; @( k