java操作Excel详解
之前参加了一个项目,里面包含了大量关于对excel的操作,基于此,将操作excel中的遇到的坑给大家填一填。
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
//Poi写Excel
public class PoiWriteDemo
{
public static void main(String[] args) throws IOException
{
// 创建excel对象,通过该对象操作excel
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建工作表,就是excel下面的sheet
HSSFSheet sheet = workbook.createSheet("sheet");
//创建一行,通过rows对行操作
HSSFRow rows = sheet.createRow(row);
// 通过rows行对象创建一个单元格并设置值
rows.createCell(0).setCellValue("第一格");
File xlsFile = new File("poi.xls");
FileOutputStream xlsStream = new FileOutputStream(xlsFile);
//将内存中的值写入excel中
workbook.write(xlsStream);
}
}
这是写入excel的方法,读的方法与其类似。
// Poi写Excel
public class PoiReadDemo
{
public static void main(String[] args) throws IOException,
InvalidFormatException
{
File xlsFile = new File("poi.xls");
// 获取excel对象,通过该对象操作excel
Workbook workbook = workBook = new XSSFWorkbook(file);
// 通过workbook对象获取工作簿的数量,即下面excel中sheet的数量
int sheetCount = workbook.getNumberOfSheets();
// 遍历工作簿
for (int i = 0; i < sheetCount; i++)
{
//获取工作簿对象
Sheet sheet = workbook.getSheetAt(i);
// 获得总行数
int rows = sheet.getPhysicalNumberOfCells();
// 循环行数
for (int i= 0; i < rows; i++)
{
Row row = sheet.getRow(row);
int cols = row.getPhysicalNumberOfCells();
//循环每行的单元格数
for (int j = 0; j < cols; j++)
{
//输出单元格中的数据
System.out.printf("%10s", r.getCell(col).getStringCellValue());
}
System.out.println();
}
}
}
}
由上面的方法就可以对excel中的数据进行相应的操作,但是因为对excel中的数据进行操作时候都是将数据先放入内存中再进行操作,因此会造成内存消耗很高并且会产生内存溢出问题。
想解决该问题可以通过分批读取或写入的方法,但可能会使代码更加复杂。因此我们可以使用XSSFWorkbook来操作Excel,该方法将excel中的数据打成压缩包从而解决了内存溢出的问题。
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class SXSSFWORKBookUtils {
public static void main(String[] args) throws FileNotFoundException, InvalidFormatException {
String filePath = "D:test.xlsx";
SXSSFWorkbook sxssfWorkbook = null;
BufferedOutputStream outputStream = null;
try {
//这样表示SXSSFWorkbook只会保留1000条数据在内存中,其它的数据都会写到磁盘里,这样的话占用的内存就会很少
sxssfWorkbook = new SXSSFWorkbook(getXSSFWorkbook(filePath),1000);
//获取第一个Sheet页
SXSSFSheet sheet = sxssfWorkbook.getSheetAt(0);
for (int i = 0; i < 10; i++) {
SXSSFRow row = sheet.createRow(i);
for (int j = 0; j < 10; j++) {
row.createCell(j).setCellValue("j:"+j);
}
}
outputStream = new BufferedOutputStream(new FileOutputStream(filePath));
sxssfWorkbook.write(outputStream);
outputStream.flush();
sxssfWorkbook.dispose();// 释放workbook所占用的所有windows资源,注意,若包的版本不对可能报无该方法的错误
} catch (IOException e) {
e.printStackTrace();
}finally {
if(outputStream!=null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 先创建一个XSSFWorkbook对象
* @param filePath
* @return
*/
public static XSSFWorkbook getXSSFWorkbook(String filePath) {
XSSFWorkbook workbook = null;
BufferedOutputStream outputStream = null;
try {
File fileXlsxPath = new File(filePath);
outputStream = new BufferedOutputStream(new FileOutputStream(fileXlsxPath));
workbook = new XSSFWorkbook();
workbook.createSheet("测试Sheet");
workbook.write(outputStream);
} catch (Exception e) {
e.printStackTrace();
}finally {
if(outputStream!=null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return workbook;
}
}
通过上述代码即可解决内存溢出问题。
不过我在查这个方法的时候又无意中发现了另一种解决方法,阿里的easyexcel也能对excel进行操作的方法,它对重写了poi对Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出。
至于源码,大家可以自行去网上翻阅,我就不给大家赘述了。