使用 poi導大量數據到excel 2007導致內存溢出

v

剛開始的時候,我執行到6萬條記錄就內存溢出了,我電腦內存完全被佔用了。後來通過查資料,使用SXSSFWorkbook 這個類來寫excel,並且在內存中記錄滿100條的時候就往硬盤上輸出。這樣我電腦內存一直有空餘。代碼出錯在187行,workbook.write(os);這一段。我的數據量並沒有達到Integer的最大值。我感覺是在寫excel的過程中,有大量的對象被創建,而沒有被gc及時清理,而導致內存不足。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package com.hzqy.web.music.stat.poiutil;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
 
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
import com.hzqy.web.music.stat.refutil.GetValueByRef;
 
/**
 * poi實現excel的生成
 *
 * @author sd
 *
 */
public class POIUtil {
    private static final Log LOG = LogFactory.getLog(POIUtil.class);
 
    public static int start_index = 0;// 寫入序號
    public static int start_row = 0;// 從第幾列開始寫
 
     
    public static final int RAM_MAX_SIZE = 100;//內存中記錄緩存數量
 
    public static final int BUFF_SIZE = 1024;//字節緩衝數量
    //TODO 建立樣式
    public void getStyle(){
         
    }
     
    /**
     * 初始化excel
     *
     * @param fileName
     *            excel名稱(XXX.xls或者XXX.xlsx)
     * @param sheetIndex
     *            第幾個sheet
     * @param title
     *            報表標題
     * @param colName
     *            報表列明
     * @param widthArr
     *            報表寬度
     */
    public static void initExcel(String fileName, int sheetIndex, String title,
            String[] colName, int[] widthArr) {
        if (null == fileName || fileName.equals("")) {
            LOG.error("請傳入文件名 ");
            return;
        }
        start_index = 0;// 設置爲初始值。不然static的index會一直遞增
        start_row = 0;
        int init = 0;
        SXSSFWorkbook  workbook = null;
        OutputStream os = null;
        try {
            workbook = new SXSSFWorkbook(RAM_MAX_SIZE);//內存中保留 10000 條數據,以免內存溢出,其餘寫入 硬盤 
            CellStyle style = workbook.createCellStyle();
            style.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);// 垂直居中
            style.setAlignment(XSSFCellStyle.ALIGN_CENTER);// 水平居中
            Font font = workbook.createFont();
            font.setFontHeightInPoints((short) 16);//字體大小
            // 把字體應用到當前的樣式
            style.setFont(font);
            LOG.debug("工作環境創建成功");
            Sheet sheet = workbook.createSheet("sheet" + sheetIndex);// 獲得要操作的單個sheet
            Row hssrow = sheet.createRow(0);// 創建一行,作爲標題
            if (null != title && !title.equals("")) {
                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0,
                        colName.length - 1));// 合併單元格
                Cell cell = hssrow.createCell(0);// 創建一個單元格
                cell.setCellStyle(style);// 設置樣式
                cell.setCellValue(title);// 寫入標題
                init++;
            }
            int col = 0;//  從第幾列開始寫 //設置單元格寬度
            Row tr_row = sheet.createRow(init);
            if(colName != null){
                for (col = 0; col < colName.length; col++) {
                    sheet.setColumnWidth(col, widthArr[col] * 256);// 以256像素爲一單位
                    Cell cell = tr_row.createCell(col);// 創建一個單元格
                    cell.setCellValue(colName[col]);// 寫入標題
                }
                init++;
            }
            start_row = init;
            os = new FileOutputStream(fileName,true);
            workbook.write(os);
            LOG.debug("基本excel建立成功");
        } catch (FileNotFoundException e) {
            LOG.error("找不到指定文件:" + fileName);
            e.printStackTrace();
        } catch (IOException e) {
            LOG.debug("io 異常");
            e.printStackTrace();
        } finally {
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    LOG.error("輸出流關閉失敗");
                    e.printStackTrace();
                }
            }
        }
    }
 
    /**
     * 將voList 寫入 excel
     *
     * @param sheetIndex
     *            第幾個表單
     * @param objList
     *            要插入的數據
     * @param fileName
     *            操作的excel表
     * @param fieldArr
     *            bean 字段
     */
    public static <T> void writeObjListToExcel(int sheetIndex,final List<T> objList,
            String fileName, String[] fieldArr) {
        if (objList != null && objList.size() > 0) {
            SXSSFWorkbook workbook = null;
            FileInputStream in = null;
            OutputStream os = null;
            XSSFWorkbook xssbook = null;
            try {
                /**
                 * 讀取原來寫入的文件
                 */
                in = new FileInputStream(fileName);
                xssbook = new XSSFWorkbook(in);
                workbook = new SXSSFWorkbook(xssbook,RAM_MAX_SIZE);// 通過已存在的excel獲取workbook
                SXSSFSheet  sheet = (SXSSFSheet) workbook.getSheetAt(sheetIndex);// 獲取指定的sheet
                /**
                 * 寫入數據
                 */
                for (Object tmp : objList) {
                    int col = 0;
                    start_index++;
                    Row hssrow = sheet.createRow(start_row);
                    Cell cellindex = hssrow.createCell(0);// cellindex用來寫序號
                    cellindex.setCellValue(start_index);// 第一列用來寫序號
                    col++;
                    /**
                     * 通過反射取值,並且寫入到excel中
                     */
                    for (int i = 0; i < fieldArr.length; i++) {
                        String fieldName = fieldArr[i];
                        Object value = GetValueByRef.getValueByRef(tmp,
                                fieldName);
                        String str = null;
                        if (value == null) {
                            str = "";
                        } else {
                            str = String.valueOf(value);
                        }
                        Cell cellvalue = hssrow.createCell(col);// cellvalue用來寫字段對應的值
                        cellvalue.setCellValue(str);
                        col++;
                    }
                    start_row++;
                    if(start_row % RAM_MAX_SIZE ==0){//數據到達內存最緩存最大值,寫入到zip中
                        sheet.flushRows();//全部寫入到硬盤
                    }
                }
//              sheet.flushRows();
                os = new FileOutputStream(fileName);
//              System.out.println(os.);
                workbook.write(os);
                LOG.debug("報表寫入成功,寫入數據 "+start_row+"行");
            } catch (IOException e) {
                LOG.debug("io 異常");
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        LOG.debug(" 讀取文件流異常");
                        e.printStackTrace();
                    }
                }
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        LOG.error("關閉文件流異常");
                        e.printStackTrace();
                    }
                }
            }
 
        }
    }
 
}

poiutil用到的工具類:GetValueByRef

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.hzqy.web.music.stat.refutil;
 
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
import com.hzqy.web.commons.vo.AreaVo;
 
public class GetValueByRef {
     
    /**
     * 用反射獲取 字段的值
     * @param srcObj 作用對象
     * @param fieldName 字段名稱
     * @return
     */
     
    public static Object getValueByRef(Object srcObj, String fieldName){
        Object value = null;
        Class objClass = srcObj.getClass();
        fieldName =fieldName.replaceFirst(fieldName.substring(0, 1), fieldName.substring(0, 1).toUpperCase());
        String getMethodName = "get"+fieldName;
        try {
            Method method = objClass.getMethod(getMethodName);//第一個參數爲調用的方法名。第二個爲方法的返回值:類型  
            value = method.invoke(srcObj);///第一個參數表示要調用的對象,後者爲傳給這個方法的參數  
        catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return value;
    }
}

 

發佈了396 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章