java讀取xlsx
1. java如何讀取整個excel文件的內容
本例使用java來讀取excel的內容並展出出結果,代碼如下:
復制代碼 代碼如下:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class ExcelOperate {
public static void main(String[] args) throws Exception {
File file = new File("ExcelDemo.xls");
String[][] result = getData(file, 1);
int rowLength = result.length;
for(int i=0;i<rowLength;i++) {
for(int j=0;j<result[i].length;j++) {
System.out.print(result[i][j]+"\t\t");
}
System.out.println();
}
}
/**
* 讀取Excel的內容,第一維數組存儲的是一行中格列的值,二維數組存儲的是多少個行
* @param file 讀取數據的源Excel
* @param ignoreRows 讀取數據忽略的行數,比喻行頭不需要讀入 忽略的行數為1
* @return 讀出的Excel中數據的內容
* @throws FileNotFoundException
* @throws IOException
*/
public static String[][] getData(File file, int ignoreRows)
throws FileNotFoundException, IOException {
List<String[]> result = new ArrayList<String[]>();
int rowSize = 0;
BufferedInputStream in = new BufferedInputStream(new FileInputStream(
file));
// 打開HSSFWorkbook
POIFSFileSystem fs = new POIFSFileSystem(in);
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFCell cell = null;
for (int sheetIndex = 0; sheetIndex < wb.getNumberOfSheets(); sheetIndex++) {
HSSFSheet st = wb.getSheetAt(sheetIndex);
// 第一行為標題,不取
for (int rowIndex = ignoreRows; rowIndex <= st.getLastRowNum(); rowIndex++) {
HSSFRow row = st.getRow(rowIndex);
if (row == null) {
continue;
}
int tempRowSize = row.getLastCellNum() + 1;
if (tempRowSize > rowSize) {
rowSize = tempRowSize;
}
String[] values = new String[rowSize];
Arrays.fill(values, "");
boolean hasValue = false;
for (short columnIndex = 0; columnIndex <= row.getLastCellNum(); columnIndex++) {
String value = "";
cell = row.getCell(columnIndex);
if (cell != null) {
// 注意:一定要設成這個,否則可能會出現亂碼
cell.setEncoding(HSSFCell.ENCODING_UTF_16);
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_STRING:
value = cell.getStringCellValue();
break;
case HSSFCell.CELL_TYPE_NUMERIC:
if (HSSFDateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
if (date != null) {
value = new SimpleDateFormat("yyyy-MM-dd")
.format(date);
} else {
value = "";
}
} else {
value = new DecimalFormat("0").format(cell
.getNumericCellValue());
}
break;
case HSSFCell.CELL_TYPE_FORMULA:
// 導入時如果為公式生成的數據則無值
if (!cell.getStringCellValue().equals("")) {
value = cell.getStringCellValue();
} else {
value = cell.getNumericCellValue() + "";
}
break;
case HSSFCell.CELL_TYPE_BLANK:
break;
case HSSFCell.CELL_TYPE_ERROR:
value = "";
break;
case HSSFCell.CELL_TYPE_BOOLEAN:
value = (cell.getBooleanCellValue() == true ? "Y"
: "N");
break;
default:
value = "";
}
}
if (columnIndex == 0 && value.trim().equals("")) {
break;
}
values[columnIndex] = rightTrim(value);
hasValue = true;
}
if (hasValue) {
result.add(values);
}
}
}
in.close();
String[][] returnArray = new String[result.size()][rowSize];
for (int i = 0; i < returnArray.length; i++) {
returnArray[i] = (String[]) result.get(i);
}
return returnArray;
}
/**
* 去掉字元串右邊的空格
* @param str 要處理的字元串
* @return 處理後的字元串
*/
public static String rightTrim(String str) {
if (str == null) {
return "";
}
int length = str.length();
for (int i = length - 1; i >= 0; i--) {
if (str.charAt(i) != 0x20) {
break;
}
length--;
}
return str.substring(0, length);
}
}
2. java如何讀取一個加密後的.xls文件
近日來,研究了一下Excel Biff8(xls 97-2007)與OpenXML(ECMA-376)的加密文檔的讀取(這還是為了我們世界先進Grid而做的 ^__^)。有些成果,寫在這里,希望能給要做類似功能的XD們一些參考。
如有不詳,請聯系:[email protected] / [email protected]
前提:
1. 加密文檔:指Wookbook級的加密,就是在Save Excel文檔時在General Settings中設置open password之後的文檔;
2. 打開:需要用戶傳入密碼。並非破解。但請勿將本文方法添加暴力模塊使用 :-) ;
3. 本文涉及較多為,密鑰計算,關於解密細節請參考微軟相關文檔;
使用的加密演算法: RC4, SHA1, MD5, AES-128(其中RC4並不包含在所有版本的.NET Framework中,AES演算法可以在.NET Framework 3.5中找到)
本文示例依賴 .NET Framework 3.5
A. Biff8 的加密文檔讀取
1. 通過文檔中FILEPASS的record取得,文檔的加密信息(關於Biff文檔的格式問題,請參閱Biff的微軟文檔)
其中Biff8可以使用兩種方法加密:Biff8標准加密演算法和Biff8擴充加密演算法。本文主要討論最常用的Biff標准加密演算法
2. 通過FILEPASS的結構,獲得如下信息:
salt(加密隨機數,16 bytes)
password verifier (密碼效驗器,16 bytes)
password verifier hash(密碼效驗器Hash,16 bytes)
3. 通過以上信息,生成解密key。並通過密碼效驗器,驗證密碼:
i. 將密碼轉化成unicode數組,並進行MD5 Hash;
ii. 將hash結果與salt串聯,然後將byte數組,反復串聯16次(336 bytes) ,然後再進行MD5 Hash;
iii. 將上步hash結果的前五位,串聯上4 bytes的block值(在密碼驗證階段為0,在以後解密階段為block的index) ,然後進行MD5 Hash;
iv. 將上步hash結果的前16位,作為key
v. 使用RC4對稱加密演算法,將password verifier和password verifier hash分別解密,然後對password verifier的解密結果進行MD5 hash,其值應和password verifier hash的解密結果一致,即為密碼正確。
vi. 之後進行逐個record的解密。excel biff8加密原則基本為,record的標示不加密,長度不加密,個別record不加密(見文檔);另外,在record解密時,還需要通過block的值重新計算解密key,block的大小為1024.
4. 詳細請參照示例代碼;
B. OpenXML(ECMA-376) 加密文檔的讀取
1. 通常來說,xlsx文件相當於一個zip文件,可以用zip程序,直接打開。而在加密後,為了安全性考慮,微軟使用了 structured storage(一種OLE文檔存儲方式)存儲(可以用7-zip或者OLE document viewer打開,windows也有相應API來操作此類結構)。在上述文檔中,有一個叫做「EncryptedPackage」加密的package,就是一個zip包通過AES演算法進行加密之後的結果。我們將使用和A一樣的方式來檢查密碼,但生成key的方法不同;OpenXML的加密類型也有多種,我們這里就討論常用的用AES-128進行加密的流程;
2. 通過文檔的「EncryptedInfo」部分,需要過的一下信息(關於此部分的結構,請參考[MS-OFFCRYPTO].pdf)
salt(加密隨機數,16 bytes)
password verifier (密碼效驗器,16 bytes)
password verifier hash(密碼效驗器Hash,32 bytes)
3. 通過以上信息,生成解密key。並通過密碼效驗器,驗證密碼:
i. 首先,定義一個H函數,其有兩個輸入,內部使用SHA1演算法將兩個輸入串聯之後的結果hash返回;
ii. 先將salt與password(password的unicode數組)進行H計算,h = H(salt, password) ;
iii.然後設iterator為0x00000000,將其轉為4byte的數組,然後進行H計算,h1 = H(iterator, h);
iv.將上面的iterator遞增一,然後再與h1進行H計算,h2 = H(iterator,h1),然後將這個遞增和計算過程重復50000次,最後計算過的iterator為49999即可;
v. 現在有計算結果h50000,將h50000再與0x00000000(4 byte數組)進行H計算,Hfinal = H(h50000, 0x00000000);
vi. 生成一個64byte的數組,將每位都初始化成0x36,然後將這個數組與Hfinal異或;(關於這個地方,微軟文檔中寫的有錯誤,按照原文的方法生成的key不正確,要不是文檔的作者回信告訴我要使用這個法子,就算我想破頭也想不出來啊 T__T)
vii.將異或結果,進行SHA1 hash,結果的前16byte就是解密的key;
viii.初始化AES演算法,key長度為128,模式為ECB模式,Padding為none; 然後將password verifier 和password verifier hash分別解密;
ix. password verifier 解密後的SHA1 hash結果應該與password verifier hash解密後的前20byte相同;
4. 關於"EncryptedPackage" 的解密則更為簡單,只許將「EncryptedPackage」讀入,去除前8byte的size信息後,進行AES解密,即為未加密的標准openxml文檔。
參考:
[MS-OFFCRYPTO].pdf
[MS-XLS].pdf
ECMA-376 standards
Reply by "winnow", 2008-09-10, 1:17
-----------------------------------------------------
總結一下, 關於這兩種基於密碼的加密方法, 基本上都是基於RFC2898 建議, 思想是這樣:
輸入是用戶的密碼:password, 輸出是提供給加密函數的密鑰:key.
考慮安全, 需要使同樣的password生成的key不一樣, 這樣用相同的password加密後的結果就無法比較. 需要一個隨機數salt.
另外, 為了使暴力破解的代價增大, 考慮使用一個循環多次的過程, 需要循環次數:iteration_count.
概念上, 生成方法為: 將password和salt進行某種運算, 配合一個Hash函數, 以某種方式循環iteration_count次, 在最後的結果里取一部分作為key輸出.
具體參照RFC2898中的建議方法PBKDF1和PBKDF2.
這樣, 用戶輸入的密碼與一個隨機數組合, 經過一定代價的運算, 就生成了可以供加密函數使用的密鑰. 使用這個密鑰和一個加密函數, 就可以進行加密了.
在應用中, 為了快速判斷密碼是否錯誤. 生成一個隨機數verifier, 用一個Hash函數計算verifier的hash值:verifier_hash, 分別加密verifier和verifier_hash並保存.
解密的時候, 先分別解密出verifier和verifier_hash, 計算verifier的hash值, 與verifier_hash比較, 如果一致, 即說明密碼正確.
3. 用java讀excel的數據。
通過java的poi讀取xlsx文件:
將excel文件使用文件流讀取
把excel的文件流轉化成excel的工作薄
獲取工作薄的sheet(工作表),迭代獲取
最後再次迭代每一個sheet,獲取每一行的每一個單元格,把數據取出存儲起來