直接上代码:
import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.util.*; import java.util.Map.Entry; /** * CSV导出工具类 */ public class CsvExportKit { public static void main(String[] args) throws Exception { LinkedHashMap<String, String> headerMap = new LinkedHashMap<>(); headerMap.put("key1", "字段1"); headerMap.put("key2", "字段2"); headerMap.put("key3", "字段3"); headerMap.put("key4", "字段4"); headerMap.put("key5", "字段5"); List<Map<String, String>> dataList = new ArrayList<>(); Map<String, String> item; for (int i = 0; i < 4000000; i++) { item = new HashMap<>(); item.put("key1", "序号" + i); item.put("key2", "订单号2019-" + i); item.put("key3", "2019-07-10"); item.put("key4", "300.15"); item.put("key5", "备注" + i); dataList.add(item); } System.out.println("数据准备完成,开始导出......"); /*String fileName = "csv导出"; HttpServletResponse response = null; response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes(), "ISO8859-1") + ".csv"); response.setContentType("text/csv"); response.setCharacterEncoding("UTF-8"); OutputStream out = response.getOutputStream();*/ OutputStream out = new FileOutputStream(new File("D:\\导出测试" + System.currentTimeMillis() + ".csv")); long start = System.currentTimeMillis(); export(out, headerMap, dataList); out.flush(); out.close(); System.out.println("导出完成, 耗时" + (System.currentTimeMillis() - start) + "毫秒!"); } /** * 导出CSV文件 * @param out 输出流 * @param headerMap 表头与字段对应的有序集合 * @param dataList 导出的数据 * @throws Exception */ public static <T> void export(OutputStream out, LinkedHashMap<String, String> headerMap, List<T> dataList) throws Exception { String seprator = ","; try { // 输出表头 StringBuilder builder = new StringBuilder(); for (Entry<String, String> i : headerMap.entrySet()) { builder.append("\"").append(i.getValue()).append("\"").append(seprator); } builder.append("\r"); // 输出内容 int size = dataList.size(); T data; for (int i = 0; i < size; i++) { for (String field : headerMap.keySet()) { data = dataList.get(i); builder.append("\"").append(getValue(data, field)).append("\"").append(seprator); } builder.append("\r"); // 每500000写入一次,防止Java heap space if (i > 0 && (i + 1) % 500000 == 0) { out.write(builder.toString().getBytes("GB2312")); builder = new StringBuilder(); } } if (size % 500000 > 0) { out.write(builder.toString().getBytes("GB2312")); } } catch (Exception e) { throw new Exception(e.getMessage(), e); } } /** * 根据属性字段(key)获取对应属性字段(key)的值 * @param dataObj 数据对象 * @param field 字段属性(key) * @return String 属性(key)值 */ private static String getValue(Object dataObj, String field) { Object value = null; try { if (Map.class.isAssignableFrom(dataObj.getClass())) { @SuppressWarnings("unchecked") Map<String, Object> map = (Map<String, Object>) dataObj; value = map.get(field); } else { Field[] fields = getFields(dataObj.getClass()); for (Field item : fields) { item.setAccessible(true); if (item.getName().equalsIgnoreCase(field)) { value = item.get(dataObj); break; } } } } catch (IllegalAccessException | IllegalArgumentException | SecurityException e) { e.printStackTrace(); } if (value != null) { return String.valueOf(value); } return null; } /** * 获取类属性字段 * @param clazz * @return */ private static Field[] getFields(Class<?> clazz) { Set<Field> fieldSet = new HashSet<>(); Field[] selfFields = clazz.getDeclaredFields(); Field[] superClassFields = clazz.getSuperclass().getDeclaredFields(); fieldSet.addAll(Arrays.asList(selfFields)); fieldSet.addAll(Arrays.asList(superClassFields)); return fieldSet.toArray(new Field[0]); } }
另外,在本机测试时发现,当数据在400万以内时,导出很快,几秒钟完成,但是当调到500万时,导出却要耗时20多秒甚至半分钟,按数据量级倍数计算,加上其他影响,耗时应该10几秒就能完成,但事实却不是,有点不太明白,知道原因的小伙伴可以解答一下!