我们使用POI中的HSSFWorkbook来读取Excel数据。9 c: V8 N$ O3 {" }5 }
public void test(File file) throws IOException {: P' I" q! ?) X8 j' M0 ?
InputStream inp = new FileInputStream(file);, e/ J8 u% I$ }
HSSFWorkbook workbook = new HSSFWorkbook(inp);9 S$ b9 \2 z2 N/ n
/ R3 R7 T2 e1 O' g, i6 b // workbook...遍历操作 & W# h _, q- r0 P }6 ^& L! O$ \8 W$ r
* K0 w, K( Q! v" ^( y+ A上边代码,读取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)”- G; v5 g4 k7 U0 A
查阅了资料,Excel2007版本的Excel文件需要使用XSSFWorkbook来读取,如下: ( H5 N% x( z( R5 Q" Mpublic void test(File file) throws IOException {3 j, P t Y, P4 X
InputStream inp = new FileInputStream(file);5 `4 d( e4 C( v' s# \
XSSFWorkbook workbook = new XSSFWorkbook(inp);: P! b3 c; Z8 f3 ] Q$ C
$ J( b2 j# L! I$ C7 u/ o // workbook...遍历操作 ' b5 Q3 ` S' P+ b4 c, i }6 _, k: m$ f8 g/ h, ]+ H! T0 W
注意:XSSFWorkbook需要额外导入poi-ooxml-3.9-sources.jar和poi-ooxml-schemas-3.9.jar。 # k5 N2 H" ^1 w6 a, }- Z! o这样,Excel2007的导入没问题了,但是导入Excel2003又报异常。 7 t/ ^/ v6 a$ ]- G9 a& u所以,在导入Excel的时候,尽量能判断导入Excel的版本,调用不同的方法。 . V. B+ ^ J8 N8 `5 G! L我想到过使用文件后缀名来判断类型,但是如果有人将xlsx的后缀改为xls时,如果使用xlsx的函数来读取,结果是报错;虽然后缀名对了,但是文件内容编码等都不对。 5 A* E" m) \+ \5 o最后,推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。代码如下: ( ^9 ^/ l" P& x7 |6 v# V* JWorkbook wb = WorkbookFactory.create(is);: Y5 C6 E/ x& o5 u/ ~
! \* ^/ ~$ W0 w' ^) ]8 Q! J y
可想而知,在WorkbookFactory.create()函数中,肯定有做过对文件类型的判断,一起来看一下源码是如何判断的:. m0 }+ y% E* v/ R* r1 T* R
/** 1 U9 J0 D: E K# I( ~ * Creates the appropriate HSSFWorkbook / XSSFWorkbook from% Q: p: {2 ?, V% h3 `
* the given InputStream. * R1 l. R" h' f5 y+ n$ a * Your input stream MUST either support mark/reset, or7 G, B) I' @6 M* P. E5 Y
* be wrapped as a {@link PushbackInputStream}!8 i9 W: V% _% k4 r8 ^
*/1 I4 Z* I( x6 W2 l$ p, h
public static Workbook create(InputStream inp) throws IOException, InvalidFormatException {! b( G9 B: A+ f2 o# P* s. s9 f7 B
// If clearly doesn't do mark/reset, wrap up 2 A2 t5 {/ h2 _9 _/ T6 M! X) a if(! inp.markSupported()) {* w9 E4 f& M, q. i- f0 c6 J' y
inp = new PushbackInputStream(inp, 8); $ G& J% ^/ A7 }1 ^. i- [ }) K1 F7 v8 I- A$ W
5 }1 c% i. ]% n6 W* R. d! y& U' r
if(POIFSFileSystem.hasPOIFSHeader(inp)) {5 r1 |% u! J8 y z
return new HSSFWorkbook(inp); & [) ^, A0 N/ @. y s/ n6 v* h5 A } + N5 o9 `7 p6 B; p/ q if(POIXMLDocument.hasOOXMLHeader(inp)) { ; {$ Q0 ^7 X/ c8 }& f8 X# w return new XSSFWorkbook(OPCPackage.open(inp)); , R& z; c3 U1 q/ @0 ?7 y9 } } , b: g' I" f( Q( u throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); " @# w5 V, x. y0 e) b/ y } : }5 Z0 R ^2 q* H6 W _8 w* x5 ]) R; F( e1 L- n% Q
可以看到,有根据文件类型来分别创建合适的Workbook对象。是根据文件的头部信息去比对进行判断的,此时,就算改了后缀名,还是一样通不过。+ K9 f) G2 m7 J6 [0 z! @; R
$ t% s9 j6 m" D" t9 k9 t