问题背景

在利用Tablesaw进行数据分析和处理后,我想要将所有的表格数据存入同一个.xlsx文件的不同sheet当中。但是Tablesaw只支持将表格写入.csv文件,因此我就需要将.csv文件中的数据读取后存入.xlsx的指定sheet当中。

本文基于EasyExcel库实现上述功能,关于EasyExcel的介绍、安装和基本操作参考:

需要注意的是,文章中的方法读取到Excel的数据均为Srting字符串格式,因此数字也被存为String类型,将String类型的数字存入Excel文件后会引发警告,因此需要将String类型的数字转化为Double类型,详情请参考:

public static void CsvToXlsx(String oripath, String despath, String sheet) 
{        
    ExcelWriter excelWriter = null;
    File destFile = new File(despath);
    File oriFile = new File(oripath);
    File transFile = new File(destFile.getParent(),"trans.xlsx");
    try {
        if (destFile.exists()) 
        {
            //创建中转文件
            //追加数据,中转文件与目标文件不能是同一个文件名
            //withTemplate()指定模板文件,即复制一份; file() 中间文件名; autoCloseStream() 必须为True,自动关闭输入流         
            excelWriter = EasyExcel.write().withTemplate(destFile)
                    //.file() 指定目标文件,不能与模板文件是同一个文件
                    .file(transFile).autoCloseStream(true).build(); //
        } 
        else 
        {
            excelWriter = EasyExcel.write(destFile).build();
        }
        WriteSheet writeSheet = EasyExcel.writerSheet(sheet).needHead(false).build();

        List<Map<Integer,Object>> list = importdata(oriFile); //返回的数据全部都是String类型的

        //将列表中值为数字的字符串转化为Double型
        Pattern pattern = Pattern.compile("-?[0-9]+.?[0-9]*");
        for(int i=0;i<list.size();i++)
        {
            Map<Integer, Object> map = list.get(i);
            for(int j=0;j<map.size();j++)
            {
                if(map.get(j)==null)continue;
                String value = map.get(j).toString();
                if(pattern.matcher(value).matches())
                {
                    map.put(j, Double.parseDouble(value));
                }
                else
                {
                    map.put(j, value);
                }
            }
            list.set(i, map);
        }

        excelWriter.write(list, writeSheet);
    } 
    finally 
    {

        if (excelWriter != null)
        {
            excelWriter.finish();
        }
    }

    if (transFile.exists()) 
    {
        //删除原文件
        destFile.delete();    
        boolean result = transFile.renameTo(destFile);
        if(result)System.out.println("改名成功");
        else System.out.println("改名失败");
    }                    
}

//导入数据
public static List<Map<Integer,Object>> importdata(File file) 
{        
    List<Map<Integer,Object>> list = new LinkedList<>();

    EasyExcel.read(file)
            .excelType(ExcelTypeEnum.CSV) //如果原始为.xlsx文件则改成.XLSX
            .sheet()
            .registerReadListener(new AnalysisEventListener<Map<Integer,Object>>() {

                @Override
                public void invoke(Map<Integer, Object> integerStringMap, AnalysisContext analysisContext) {
                    // TODO Auto-generated method stub
                    list.add(integerStringMap);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    // TODO Auto-generated method stub
                    System.out.println("数据读取完毕");
                }
            }).headRowNumber(0).doRead();
    return list;
}

调用CsvToXlsx(String oripath, String despath, String sheet) 即可,若原始文件为.xlsx格式,则需要修改函数importdata(File file)中的.excelType(ExcelTypeEnum.CSV)

CsvToXlsx(String oripath, String despath, String sheet)函数的输入参数分别表示:

  • oripath:原始文件的路径,即分散的表格文件;
  • despath:想要写入目标文件的路径,如果不存在会自动创建;
  • sheet:想要写入目标文件中指定sheet的名称。
    下面我将以一个简单的案例介绍一下函数的使用方法。

案例介绍

假设我有如下两个表格,名称分别为a.csvb.csv

运行下面这两句程序,会生成一个名为text.xlsx的文件:

CsvToXlsx("data/a.csv", "data/test.xlsx", "a");
CsvToXlsx("data/b.csv", "data/test.xlsx", "b");

打开文件,可以看到两个表格的内容均写入了文件的不同sheet当中: