`

使用 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;
    }
}

 

分享到:
评论

相关推荐

    java poi 导入大数据量Excel数据 防止内存溢出处理.zip

    然而,当处理大数据量的Excel文件时,POI可能会导致内存溢出(Out of Memory, OOM),因为默认情况下它会将整个工作簿加载到内存中。为了防止这种问题,我们需要采用优化策略来高效地处理大量数据。 1. **分块读取*...

    poi大量数据读取gc内存溢出解决方案

    poi读取大量数据会造成gc内存溢出的报错,由于垃圾回收机制无法将大量的对象及时的回收,而这些对象又会保存在内存中,会导致内存不够用的情况,这时候我们就需要使用新的方法,读取为cvs即可.此解决方案可支持千万数据的...

    解决大批量数据导出Excel产生内存溢出的方案

    这是因为POI或JXL在导出大量数据时,将每一个单元格生成一个Cell对象,从而导致内存溢出。解决这个问题的唯一方法是弄清楚Excel的二进制格式,并用流的方式读写Excel。POI和JXL提供了二进制方式读写Excel的API,但是...

    java poi导出大量数据到Excel

    当面对大量数据时,直接将所有数据一次性写入单个工作表可能会导致内存溢出等问题。因此,一种常见的做法是将数据分批写入不同的工作表中。 #### 四、具体实现步骤 ##### 1. 导入库依赖 首先,确保项目中引入了...

    java解决大批量数据导出Excel产生内存溢出的方案

    这是因为Excel文件格式本身的设计,以及Java默认处理大数据的方式,可能导致内存占用过高,尤其是在一次性加载大量数据到内存中进行处理时。为了解决这个问题,我们可以采用以下几种策略: 1. **分批导出**: - ...

    使用POI导出大数据量到EXCEL

    "使用POI导出大数据量到EXCEL"这个主题涉及到如何高效地利用POI处理大量数据并将其导出到Excel文件中。以下是对这个主题的详细讲解。 1. **Apache POI简介** Apache POI 是一个开源项目,它提供了Java API来创建、...

    完美解决java读取excel内存溢出问题.rar

    这通常是由于Java的默认内存设置不足以处理大量数据导致的。本解决方案主要针对使用Apache POI库进行Excel读取时遇到的这类问题。 首先,Apache POI是Java中广泛使用的处理Microsoft Office文档(包括Excel)的库。...

    POI实现的基于动态模板的EXCEL数据导出

    5. 如果数据量大,可能需要分批写入,以避免一次性加载过多数据导致内存溢出。 在实际应用中,为了提高性能,可能还需要考虑异步处理、多线程等技术,以实现更高效的批量数据导出。此外,优化内存管理和设置适当的...

    java使用poi导出大量数据

    1. **内存管理**:当处理大数据时,一次性加载所有数据到内存可能导致内存溢出。为避免这种情况,可以分批从数据库中获取数据,每批数据处理完后再写入Excel。例如,可以设置一个合适的批处理大小,如1000行,然后在...

    关于Poi读取Excel引发内存溢出问题的解决方法

    在处理大量数据时,使用 POI 的默认用户模式(UserModel)读取 Excel 文件可能会导致内存溢出问题,因为该模式会将整个文件加载到内存中。本文将详细介绍如何解决由 POI 用户模式引发的内存溢出问题,并提供相应的...

    poi导出根据模板导出excel和简单列表导出excel源码

    大量数据导出时,一次性加载到内存可能导致内存溢出。为解决这个问题,可以采用流式处理(Streaming User Model)或分批处理。例如,使用SXSSF(Streaming Usermodel API)可以避免一次性加载所有数据,它会在磁盘...

    ssm通过POI技术把excel数据导入mysql

    7. **性能优化**:考虑到大数据量导入,可以考虑分批插入,避免一次性加载过多数据导致内存溢出。此外,合理设置数据库的批量插入大小,如`setBatchSize(int batchSize)`,能有效提高性能。 8. **测试与调试**:...

    poi多线程大数据导出excel文件.zip

    由于Excel文件可能非常大,直接在内存中加载所有数据可能导致内存溢出。因此,项目可能采用了流式处理或者分批读取数据的方式,减少内存占用。此外,还可以利用SXSSFWorkbook(POI的一个子类)进行低内存使用,因为...

    Java读取大数据量Excel的方法(POI)

    4. **优化性能**:处理大数据时,直接将所有数据加载到内存可能导致内存溢出。可以使用迭代器模式(`RowIterator`和`CellIterator`)来避免一次性加载所有数据,或者只读取需要的数据范围,例如: ```java for ...

    POI实现大数据量的excel文件解析

    标题中的“POI实现大数据量的excel文件解析”是指使用Apache POI库来处理大量数据的Excel文件。Apache POI是Java平台上的一个开源项目,它提供了读取和写入Microsoft Office格式文件的能力,包括Excel(XLS和XLSX)...

    使用POI从数据库导出对应EXCEL格式数据

    大量数据导出可能导致内存溢出。为解决这个问题,POI提供了一个叫做SXSSF的API,它是基于SXSSF(Streaming Usermodel API)的,可以处理大型数据集而不占用大量内存。 6. **网页下载流程**: 在Web应用中,当用户...

    POI读写海量Excel(详细解读)

    然而,对于较低版本的 Excel 2003,POI 使用用户模式,可能会导致内存溢出,特别是当数据量超过一定阈值(如3万条,每条8列)时。 值得注意的是,Excel 2003每个电子表格的行数限制为65536行,超出这个限制将引发...

    poi导出excel2007

    在处理大量数据时,使用Java导出Excel文件可能会遇到内存溢出的问题,尤其是在导出Excel 2007(.xlsx格式)时更为常见。这是因为传统的`XSSFWorkbook`对象会将整个工作簿保存在内存中,导致内存消耗巨大。 #### ...

    java向excel 写入海量数据内存溢出问题的解决.pdf

    当执行`hssfTest()`时,随着行数增加,内存消耗也随之增加,最终可能导致内存溢出。 在命令行中运行程序时,通过使用`-Xms`、`-Xmx`、`-XX:PermSize`和`-XX:MaxPermSize`这些JVM参数来调整堆内存大小。例如,`java ...

    Springboot+Poi实现Excel的导入导出

    4. **性能优化**:如果数据量较大,可以考虑分批读写,避免一次性加载大量数据导致内存溢出。同时,对于数据库操作,可以使用批量插入以提高效率。 5. **安全考虑**:在处理用户上传的Excel文件时,需要防止SQL注入...

Global site tag (gtag.js) - Google Analytics