我们使用POI中的HSSFWorkbook来读取Excel数据。2 [9 C% C' q" f c
public void test(File file) throws IOException { # l9 N! ]; k( o1 I( d InputStream inp = new FileInputStream(file); 5 _* O4 b' @0 l' w1 t) S' B: y3 C HSSFWorkbook workbook = new HSSFWorkbook(inp);$ D9 k+ ]* w* o' P
4 a8 B0 x# t8 {5 \ w( P9 O // workbook...遍历操作 + {2 b- P s( g* y6 h7 P } 1 S! W' L# L" R a0 k : X0 l4 _6 [" T0 y7 k% M上边代码,读取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)”3 M: G1 @; c- m; o5 E. q4 i5 E: C
查阅了资料,Excel2007版本的Excel文件需要使用XSSFWorkbook来读取,如下: * I# Z. G0 w' P, m6 R8 F5 Vpublic void test(File file) throws IOException {' R- w. } a$ E9 p3 n
InputStream inp = new FileInputStream(file);9 z" D8 g; X+ R3 }8 S
XSSFWorkbook workbook = new XSSFWorkbook(inp); |$ Q- A6 g# |; ~$ o! P6 \$ g7 I
- J- J5 r0 M A# X% O# X5 | // workbook...遍历操作. f% k x) A4 o0 V7 F
}- V3 o1 e3 u, D6 P ]* @
注意:XSSFWorkbook需要额外导入poi-ooxml-3.9-sources.jar和poi-ooxml-schemas-3.9.jar。5 G; y& F& I: I. e* M
这样,Excel2007的导入没问题了,但是导入Excel2003又报异常。 , O4 L; o, t6 ]8 m, u* b0 i, W所以,在导入Excel的时候,尽量能判断导入Excel的版本,调用不同的方法。 8 w5 I5 f% w! B$ _5 l( V2 j9 Q我想到过使用文件后缀名来判断类型,但是如果有人将xlsx的后缀改为xls时,如果使用xlsx的函数来读取,结果是报错;虽然后缀名对了,但是文件内容编码等都不对。8 F/ P: X1 \$ w! D
最后,推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。代码如下: 2 Z4 W; Y8 i# y3 [& @Workbook wb = WorkbookFactory.create(is);+ }. z9 y! k6 v% j+ k2 C0 |
& l/ M/ ?' v9 K: T; X
可想而知,在WorkbookFactory.create()函数中,肯定有做过对文件类型的判断,一起来看一下源码是如何判断的:9 t% K0 P9 ?! G# M! V$ `5 P
/** , s6 A/ l0 \' h3 }* J% h3 B2 K$ _3 H * Creates the appropriate HSSFWorkbook / XSSFWorkbook from # K) ^$ f. w* S @) A3 b a. L * the given InputStream.+ y! i$ z! d- g% L2 Y! K
* Your input stream MUST either support mark/reset, or2 w: W0 O; h) d. Q' _, f6 W( y
* be wrapped as a {@link PushbackInputStream}! ; \2 ]6 C1 u4 { D6 H1 ^ */ 2 y- `, Z+ S& Y% p3 Y, b+ m0 p public static Workbook create(InputStream inp) throws IOException, InvalidFormatException { ; \3 S: F. j$ J o // If clearly doesn't do mark/reset, wrap up5 [, g4 g* Z( @
if(! inp.markSupported()) { 2 ?$ W C' n1 } inp = new PushbackInputStream(inp, 8);; W w% V: F, V* _4 Y
}- `! R8 m9 G1 z1 F$ o8 E9 A1 k
- A: F j" Z F- P8 N if(POIFSFileSystem.hasPOIFSHeader(inp)) { & B8 e6 D; `4 {! i3 z; Z return new HSSFWorkbook(inp);$ Q C1 W3 Y* N6 ? R. X3 K( L
}0 `5 @3 E5 N- T1 ~9 I: @
if(POIXMLDocument.hasOOXMLHeader(inp)) {) ?& A. S5 r* L$ _
return new XSSFWorkbook(OPCPackage.open(inp)); : O! w% B9 F' Q9 X* e2 R5 Q y }9 I" [! o0 D" o' {7 u- q
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream"); % J' y+ p2 z" n% W }2 y9 r" r6 v5 s, V+ v: @# R% J
6 P, h) m1 g4 n/ _
可以看到,有根据文件类型来分别创建合适的Workbook对象。是根据文件的头部信息去比对进行判断的,此时,就算改了后缀名,还是一样通不过。/ w, C" {7 P$ I
/ D% f8 J: a2 A8 k* y8 F