POI的Unable to read entire block明顯是已經久懸未決的問題了,至今在網上查找資料,都沒有一個能確定解決的方案。上周在客戶那里碰到這個問題,弄了4天,才算搞定。這個解決方式倒是沒有發現有描述的,較為簡單,而且還沒有經過長時間測試,不敢保證能夠徹底解決問題,但希望能給在泥潭中苦苦掙扎的朋友們提供一個思路。
我的程序需要將加密的Doc文件先解密出來,存為一個臨時的解碼原文件,從這個原文件中抽取索引,再刪除臨時文件。這時候Unable to read entire block的問題就很明顯。做了測試,如果直接拿原文件來抽取沒問題,就是不經過加密、寫出這步,并且確信加密解密不會造成文件的數據混亂或丟失,那么問題肯定是寫出的文件和原文件不同咯。于是拿兩個文件來對比,發現字節數不一樣,如我的異常報的是Unable to read entire block;81 bytes read; expected 512 bytes ,兩個文件之間差的字節數正是81byte。于是再用UE編輯器打開兩個文件來比較,發現無法抽取的Doc文件最后部分比原文件多了81個0。
查看代碼,發現我的字節數組是這樣定義的byte[] b = byte[255]; 每個字節數組塊是255的大小,當文件寫出到末尾時,會把初始化卻沒有用到的最后一批0一起寫到文件中。偏偏POI以512為單位來讀取,當讀到Doc文檔的末尾,發現還有字節,就報錯,表示這個文件不正確。
解決方式有兩種,我同事使用的是將POI源碼修改了,碰到多出來的字節不校驗,直接通過,但是這樣造成后面的字符串截取子串出問題,不能確保解決。另外一種就很簡單了,將程序中所有的byte初始化定義成byte[512],這樣定義的字節數組塊跟POI讀取的字節塊是一致的,問題也隨之解決了。
PS:另外,早在2006年的一篇資料(忘記原址了,sorry),已指出是用FileOutputStrem和FileInputStream輸入輸出的字節數不一致造成的,不過解決方案使用的是用ByteArrayInputStream來進行讀取,難道ByteArrayInputStream能夠將用不到的byte[]截取掉嗎?沒有驗證過,但是照他的方式來修改也無法解決這個問題。最后還是用byte[512]的方式來解決的。先觀察一段時間再說