Java实现CSV文件的导出

栏目: Java · 发布时间: 8年前

内容简介:Java实现CSV文件的导出

相信大家对于后台导出数据到excel表的需求很熟悉的。最近在开发项目过程中,就有用户的导入导出功能。开始我思路是用户导出导入都使用excel格式,但是到后面发现 其实在导出大量数据的时候,excel表是有很大局性的。一次导出10W条数据的时候,发现导出为excel失败,查看错误信息就是excel表对于数据的行数有限制,excel2003 是65535条,excel2007会更多(还是会有限制)。考虑到管理员电脑的excel版本有高有低(必须兼容最低版本03),加上导出这么多数据,内存占用会比较大,弄不好会出现内存泄漏。随着用户量的不断增加,导出为excel显得越来不可取。于是就采用导出为csv 格式,加上csv可以使用excel表打开,这看来是不错的做法。

什么是CSV

那什么是csv?格式又是怎么样的呢? 大家看一下百度百科的定义: CSV:逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号), 其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数 字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段 间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。通常都 是纯文本文件。 给大家举例子:

用户昵称,用户账号,用户等级

圣诞老人1,13800138000,VIP7

圣诞老人2,13800138000,VIP7

圣诞老人3,13800138000,VIP8

第一行写数据对应的标题: 用户昵称,用户账号,用户等级

第二行根据标题的顺序写数据,一行表示一条数据,多条数据多行写就可以了:圣诞老人2,13800138000,VIP7

代码实现

源码

这里结合代码给大家讲解一下一个具体demo的实现,使用的是spring-boot来搭建web环境的,不熟悉spring-boot的朋友,可以使用springmvc也行,其实是一样的。 不需要依赖任何jar。

首先是Controller层的实现,就不多解释了,注释有了大家可以看懂

package com.example.demo.controller;

import com.example.demo.dto.UserExportToCsvDTO;
import com.example.demo.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @author wunanliang
 * @date 2017/12/24
 * @since 1.0.0
 */
@RestController
public class FileController {


    @Autowired
    private FileService fileService;

    @PostMapping("/api/v1/export/csv/users")
    public void exportCsv(HttpServletResponse response, HttpServletRequest request) throws IOException {

        // 模拟导出数据,这里数据可以是从数据库获取回来的,也可以是前端传过来再解析的
        // 这里的数据应该放在dao层获取的,就先简单放在这里,大家不必介意,只是demo演示
        List<UserExportToCsvDTO> users = new ArrayList<>();
        users.add(new UserExportToCsvDTO("13800138001", "圣诞老人1", "VIP1"));
        users.add(new UserExportToCsvDTO("13800138002", "圣诞老人2", "VIP7"));
        users.add(new UserExportToCsvDTO("13800138003", "圣诞老人3", "VIP8"));
        // csv文件名字,为了方便默认给个名字,当然名字可以自定义,看实际需求了
        String fileName = "我是csv文件.csv";
        // 解决不同浏览器出现的乱码
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);
        FileCopyUtils.copy(fileService.exportUsersToCsv(users), response.getOutputStream());
    }
}

我们再来看FileService代码:

package com.example.demo.service;

import com.example.demo.CsvUtils;
import com.example.demo.dto.UserExportToCsvDTO;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * 为了方便,就不写接口和实现分离了
 *
 * @author wunanliang
 * @date 2017/12/24
 * @since 1.0.0
 */
@Service
public class FileService {


    /**
     * 导出用户到csv文件
     *
     * @param users 导出的数据(用户)
     * @return
     */
    public byte[] exportUsersToCsv(List<UserExportToCsvDTO> users) {
        // 为了方便,也不写dao层
        List<LinkedHashMap<String, Object>> exportData = new ArrayList<>(users.size());
        // 行数据
        for (UserExportToCsvDTO user : users) {
            LinkedHashMap<String, Object> rowData = new LinkedHashMap<>();
            rowData.put("1", user.getUsername());
            rowData.put("2", user.getNickname());
            rowData.put("3", user.getLevel());
            exportData.add(rowData);
        }
        LinkedHashMap<String, String> header = new LinkedHashMap<>();
        header.put("1", "用户账号");
        header.put("2", "用户昵称");
        header.put("3", "用户等级");
        return CsvUtils.exportCSV(header, exportData);
    }

}

CsvUtils代码:

package com.example.demo;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * CSV文件帮助类
 *
 * @author wunanliang
 * @date 2017/12/24
 * @since 1.0.0
 */
public class CsvUtils {

    /**
     * 导出csv文件
     *
     * @param headers    内容标题
     *                   注意:headers类型是LinkedHashMap,保证遍历输出顺序和添加顺序一致。
     *                   而HashMap的话不保证添加数据的顺序和遍历出来的数据顺序一致,这样就出现
     *                   数据的标题不搭的情况的
     * @param exportData 要导出的数据集合
     * @return
     */
    public static byte[] exportCSV(LinkedHashMap<String, String> headers, List<LinkedHashMap<String, Object>> exportData) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        BufferedWriter buffCvsWriter = null;

        try {
            // 编码gb2312,处理excel打开csv的时候会出现的标题中文乱码
            buffCvsWriter = new BufferedWriter(new OutputStreamWriter(baos, "gb2312"));
            // 写入cvs文件的头部
            Map.Entry propertyEntry = null;
            for (Iterator<Map.Entry<String, String>> propertyIterator = headers.entrySet().iterator(); propertyIterator.hasNext(); ) {
                propertyEntry = propertyIterator.next();
                buffCvsWriter.write("\"" + propertyEntry.getValue().toString() + "\"");
                if (propertyIterator.hasNext()) {
                    buffCvsWriter.write(",");
                }
            }
            buffCvsWriter.newLine();
            // 写入文件内容
            LinkedHashMap row = null;
            for (Iterator<LinkedHashMap<String, Object>> iterator = exportData.iterator(); iterator.hasNext(); ) {
                row = iterator.next();
                for (Iterator<Map.Entry> propertyIterator = row.entrySet().iterator(); propertyIterator.hasNext(); ) {
                    propertyEntry = propertyIterator.next();
                    buffCvsWriter.write("\"" + propertyEntry.getValue().toString() + "\"");
                    if (propertyIterator.hasNext()) {
                        buffCvsWriter.write(",");
                    }
                }
                if (iterator.hasNext()) {
                    buffCvsWriter.newLine();
                }
            }
            // 记得刷新缓冲区,不然数可能会不全的,当然close的话也会flush的,不加也没问题
            buffCvsWriter.flush();
        } catch (IOException e) {

        } finally {
            // 释放资源
            if (buffCvsWriter != null) {
                try {
                    buffCvsWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return baos.toByteArray();
    }
}

下面看看实现效果:

输入url:

Java实现CSV文件的导出

点击导出用户,再点击csv文件,excel打开:

Java实现CSV文件的导出

我们看到,号码出现科学计数,我们点击任何一个单元格三次就可以了

Java实现CSV文件的导出

用文本 工具 打开:

Java实现CSV文件的导出

具体的就不多说了,大家看源码带就可以啦。 最后,祝大家平安夜快乐哈!!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C语言程序设计

C语言程序设计

K. N. King / 吕秀锋、黄倩 / 人民邮电出版社 / 2010-4 / 79.00元

时至今日, C语言仍然是计算机领域的通用语言之一,但今天的 C语言已经和最初的时候大不相同了。本书最主要的一个目的就是通过一种“现代方法”来介绍 C语言,书中强调标准 C,强调软件工程,不再强调“手工优化”。这一版中紧密结合了 C99标准,并与 C89标准进行对照,补充了 C99中的最新特性。本书分为 C语言的基础特性、 C语言的高级特性、 C语言标准库和参考资料 4个部分。每章末尾都有一个“问与......一起来看看 《C语言程序设计》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具