概览
1. 什么叫做CSV
Comma-Separated Value ([卡门 赛婆乱提的]逗号分隔)(CSV),因分隔符没有严格的要求,可以使用逗号,也可以使用其他字符(如制表符\t,分号等),所以CSV也被称为逗号分隔或者其他字符分隔值。csv文件是使用纯文本来存储表格数据(只能存储文本,不能存储二进制)。
OpenCSV
package com.mkyong.io.csv.opencsv;import com.opencsv.CSVReader;import com.opencsv.exceptions.CsvException;import java.io.FileReader;import java.io.IOException;import java.util.Arrays;import java.util.List;public class OpenCsvExample {public static void main(String[] args) throws IOException, CsvException {String fileName = "c:\\test\\csv\\country.csv";try (CSVReader reader = new CSVReader(new FileReader(fileName))) {List<String[]> r = reader.readAll();r.forEach(x -> System.out.println(Arrays.toString(x)));}}}
List<String[]> collect =Files.lines(Paths.get("c:\\test\\csv\\country.csv")).map(line -> line.split(",")).collect(Collectors.toList());
// Java code to illustrate reading a// all data at oncepublic static void readAllDataAtOnce(String file){try {// Create an object of file reader// class with CSV file as a parameter.FileReader filereader = new FileReader(file);// create csvReader object and skip first LineCSVReader csvReader = new CSVReaderBuilder(filereader).withSkipLines(1).build();List<String[]> allData = csvReader.readAll();// print Datafor (String[] row : allData) {for (String cell : row) {System.out.print(cell + "\t");}System.out.println();}}catch (Exception e) {e.printStackTrace();}}
// Java code to illustrate// Reading CSV File with different separatorpublic static void readDataFromCustomSeparator(String file){try {// Create an object of file reader class with CSV file as a parameter.FileReader filereader = new FileReader(file);// create csvParser object with// custom separator semi-colonCSVParser parser = new CSVParserBuilder().withSeparator(';').build();// create csvReader object with parameter// filereader and parserCSVReader csvReader = new CSVReaderBuilder(filereader).withCSVParser(parser).build();// Read all data at onceList<String[]> allData = csvReader.readAll();// Print Data.for (String[] row : allData) {for (String cell : row) {System.out.print(cell + "\t");}System.out.println();}}catch (Exception e) {e.printStackTrace();}}
每次读一行
// Java program to illustrate reading// two CSV files// with different separatorsimport java.io.FileReader;import java.util.List;import com.opencsv.*;public class ReadCSVData {private static final String CSV_FILE_PATH= "D:\\EclipseWorkSpace\\CSVOperations\\results.csv";private static final String CSV_FILE_CUSTOM_SEPARATOR= "D:\\EclipseWorkSpace\\CSVOperations\\results_semicolon_Separator.csv";public static void main(String[] args){System.out.println("Read Data Line by Line With Header \n");readDataLineByLine(CSV_FILE_PATH);System.out.println("_______________________________________________");System.out.println("Read All Data at Once and Hide the Header also \n");readAllDataAtOnce(CSV_FILE_PATH);System.out.println("_______________________________________________");System.out.println("Custom Separator here semi-colon\n");readDataFromCustomSeparator(CSV_FILE_CUSTOM_SEPARATOR);System.out.println("_______________________________________________");}public static void readDataLineByLine(String file){try {// Create an object of filereader class// with CSV file as a parameter.FileReader filereader = new FileReader(file);// create csvReader object passing// filereader as parameterCSVReader csvReader = new CSVReader(filereader);String[] nextRecord;// we are going to read data line by linewhile ((nextRecord = csvReader.readNext()) != null) {for (String cell : nextRecord) {System.out.print(cell + "\t");}System.out.println();}}catch (Exception e) {e.printStackTrace();}}public static void readAllDataAtOnce(String file){try {// Create an object of filereader class// with CSV file as a parameter.FileReader filereader = new FileReader(file);// create csvReader object// and skip first LineCSVReader csvReader = new CSVReaderBuilder(filereader).withSkipLines(1).build();List<String[]> allData = csvReader.readAll();// print Datafor (String[] row : allData) {for (String cell : row) {System.out.print(cell + "\t");}System.out.println();}}catch (Exception e) {e.printStackTrace();}}public static void readDataFromCustomSeparator(String file){try {// Create object of filereader// class with csv file as parameter.FileReader filereader = new FileReader(file);// create csvParser object with// custom separator semi-colonCSVParser parser = new CSVParserBuilder().withSeparator(';').build();// create csvReader object with// parameter filereader and parserCSVReader csvReader = new CSVReaderBuilder(filereader).withCSVParser(parser).build();// Read all data at onceList<String[]> allData = csvReader.readAll();// print Datafor (String[] row : allData) {for (String cell : row) {System.out.print(cell + "\t");}System.out.println();}}catch (Exception e) {e.printStackTrace();}}}
pom.xml
<!-- csv文件解析依赖 --><dependency><groupId>com.opencsv</groupId><artifactId>opencsv</artifactId><version>5.4</version></dependency>
手动解析CSV文件
// 析csv文件并转成bean(方法一)public static List<CsvFile> getCsvDataMethod1(MultipartFile file) {ArrayList<CsvFile> csvFileList = new ArrayList<>();InputStreamReader in = null;String s = null;try {in = new InputStreamReader(file.getInputStream(), "utf-8");BufferedReader bufferedReader = new BufferedReader(in);String line = null;while ((line = bufferedReader.readLine()) != null) {String[] split = line.split(",");CsvFile csvFile = new CsvFile();csvFile.setName(splitResult(split[0]));csvFile.setTitle(splitResult(split[1]));csvFile.setNumber(splitResult(split[2]));csvFile.setType(splitResult(split[3]));csvFile.setPersonnel(splitResult(split[4]));csvFile.setTime(splitResult(split[5]));csvFileList.add(csvFile);}} catch (IOException e) {e.printStackTrace();}return csvFileList;}
去重引号“”
private static String splitResult(String once) {String result = "";for (int i = 0; i < once.length(); i++) {if (once.charAt(i) != '"') {result += once.charAt(i);}}return result;}
openCSV解析CSV文件
/*** 解析csv文件并转成bean(方法二)** @param file csv文件* @return 数组*/public static List<String[]> getCsvDataMethod2(MultipartFile file) {List<String[]> list = new ArrayList<String[]>();int i = 0;try {CSVReader csvReader = new CSVReaderBuilder(new BufferedReader(new InputStreamReader(file.getInputStream(), "utf-8"))).build();Iterator<String[]> iterator = csvReader.iterator();while (iterator.hasNext()) {String[] next = iterator.next();//去除第一行的表头,从第二行开始if (i >= 1) {list.add(next);}i++;}return list;} catch (Exception e) {System.out.println("CSV文件读取异常");return list;}}
openCSV解析CSV文件(结果为实体类)
工具类
/*** 解析csv文件并转成bean(方法三)** @param file csv文件* @param clazz 类* @param <T> 泛型* @return 泛型bean集合*/public static <T> List<T> getCsvDataMethod3(MultipartFile file, Class<T> clazz) {InputStreamReader in = null;CsvToBean<T> csvToBean = null;try {in = new InputStreamReader(file.getInputStream(), "utf-8");HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<>();strategy.setType(clazz);csvToBean = new CsvToBeanBuilder<T>(in).withMappingStrategy(strategy).build();} catch (Exception e) {logger.error("数据转化失败");return null;}return csvToBean.parse();}
实体类
import com.opencsv.bean.CsvBindByName;import lombok.Data;@Datapublic class CsvFile {@CsvBindByName(column = "name")private String name;@CsvBindByName(column = "title")private String title;@CsvBindByName(column = "number")private String number;@CsvBindByName(column = "type")private String type;@CsvBindByName(column = "personnel")private String personnel;@CsvBindByName(column = "time")private String time;}
整理完成的CsvUtils
import com.lydms.testopencsv.domain.CsvFile;import com.opencsv.CSVReader;import com.opencsv.CSVReaderBuilder;import com.opencsv.bean.CsvToBean;import com.opencsv.bean.CsvToBeanBuilder;import com.opencsv.bean.HeaderColumnNameMappingStrategy;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.web.multipart.MultipartFile;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class CsvUtils {private static final Logger logger = LogManager.getLogger(CsvUtils.class);/*** 解析csv文件并转成bean(方法二)** @param file csv文件* @return 数组*/public static List<String[]> getCsvDataMethod2(MultipartFile file) {List<String[]> list = new ArrayList<String[]>();int i = 0;try {CSVReader csvReader = new CSVReaderBuilder(new BufferedReader(new InputStreamReader(file.getInputStream(), "utf-8"))).build();Iterator<String[]> iterator = csvReader.iterator();while (iterator.hasNext()) {String[] next = iterator.next();//去除第一行的表头,从第二行开始if (i >= 1) {list.add(next);}i++;}return list;} catch (Exception e) {System.out.println("CSV文件读取异常");return list;}}/*** 解析csv文件并转成bean(方法三)** @param file csv文件* @param clazz 类* @param <T> 泛型* @return 泛型bean集合*/public static <T> List<T> getCsvDataMethod3(MultipartFile file, Class<T> clazz) {InputStreamReader in = null;CsvToBean<T> csvToBean = null;try {in = new InputStreamReader(file.getInputStream(), "utf-8");HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<>();strategy.setType(clazz);csvToBean = new CsvToBeanBuilder<T>(in).withMappingStrategy(strategy).build();} catch (Exception e) {logger.error("数据转化失败");return null;}return csvToBean.parse();}/*** 解析csv文件并转成bean(方法一)** @param file* @return*/public static List<CsvFile> getCsvDataMethod1(MultipartFile file) {ArrayList<CsvFile> csvFileList = new ArrayList<>();InputStreamReader in = null;String s = null;try {in = new InputStreamReader(file.getInputStream(), "utf-8");BufferedReader bufferedReader = new BufferedReader(in);String line = null;while ((line = bufferedReader.readLine()) != null) {String[] split = line.split(",");CsvFile csvFile = new CsvFile();csvFile.setName(splitResult(split[0]));csvFile.setTitle(splitResult(split[1]));csvFile.setNumber(splitResult(split[2]));csvFile.setType(splitResult(split[3]));csvFile.setPersonnel(splitResult(split[4]));csvFile.setTime(splitResult(split[5]));csvFileList.add(csvFile);}} catch (IOException e) {e.printStackTrace();}return csvFileList;}private static String splitResult(String once) {String result = "";for (int i = 0; i < once.length(); i++) {if (once.charAt(i) != '"') {result += once.charAt(i);}}return result;}}
根据java对象生成csv文件
readCsv
public void readCsv(String finalPath) {try {Reader reader = new InputStreamReader(new FileInputStream(finalPath), StandardCharsets.UTF_8);CSVReader csvReader = new CSVReaderBuilder(reader).build();// 列名的映射HeaderColumnNameTranslateMappingStrategy<Person> strategy =new HeaderColumnNameTranslateMappingStrategy<>();strategy.setType(Person.class);Map<String, String> columnMapping = new HashMap<>();columnMapping.put("编号", "id");columnMapping.put("姓名", "name");columnMapping.put("年龄", "age");strategy.setColumnMapping(columnMapping);CsvToBean<Person> csvToBean = new CsvToBeanBuilder(csvReader).withSeparator(CSVWriter.DEFAULT_SEPARATOR).withQuoteChar(CSVWriter.NO_QUOTE_CHARACTER).withMappingStrategy(strategy).build();List<Person> list = csvToBean.parse();for (Person p : list) {System.out.println(p.toString());}csvReader.close();reader.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
writeCsv
public void writeCsv(List<Person> dataList, String finalPath) {try {Writer writer = new FileWriter(finalPath);// 设置显示的顺序String[] columnMapping = {"id", "name", "age"};ColumnPositionMappingStrategy<Person> mapper =new ColumnPositionMappingStrategy<>();mapper.setType(Person.class);mapper.setColumnMapping(columnMapping);// 写表头CSVWriter csvWriter = new CSVWriter(writer, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, '\\', "\n");String[] header = { "编号", "姓名", "年龄"};csvWriter.writeNext(header);StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).withMappingStrategy(mapper).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).withSeparator(CSVWriter.DEFAULT_SEPARATOR).withEscapechar('\\').build();beanToCsv.write(dataList);csvWriter.close();writer.close();} catch (IOException e) {e.printStackTrace();} catch (CsvDataTypeMismatchException e) {e.printStackTrace();} catch (CsvRequiredFieldEmptyException e) {e.printStackTrace();}System.out.println(finalPath + "数据导出成功");}
实体
@Data@AllArgsConstructor@NoArgsConstructorpublic class Person {private Integer id;private String name;private Integer age;}
测试类的方法(maven项目结构中的测试类)
finalPath 是绝对路径+文件名,请确保欲生成的文件所在目录已创建好。
@Testvoid writeCsv() {// test dataPerson person0 = new Person(11, "钱多多", 18);Person person1 = new Person(22, "王多鱼", 19);Person person2 = new Person(33, "喜羊羊", 20);List<Person> personList = new ArrayList<>();personList.add(person0);personList.add(person1);personList.add(person2);String finalPath = "/Users/qianshijie/Temporary/skycomm/devsyn/test.csv";personService.writeCsv(personList, finalPath);}@Testvoid readCsv() {String finalPath = "/Users/qianshijie/Temporary/skycomm/devsyn/test.csv";personService.readCsv(finalPath);}
上述方法中,csv 文件的列名均已被替换(已不是实体类的属性名)。如果想让生成的 csv 文件列名和实体类属性名保持一致。请使用如下代码(只列举有变化的代码,未列出则代码无变动,变动已将原代码注释,以供对比):
public void writeCsv(List<Person> dataList, String finalPath) {try {Writer writer = new FileWriter(finalPath);// 设置显示的顺序String[] columnMapping = {"id", "name", "age"};ColumnPositionMappingStrategy<Person> mapper =new ColumnPositionMappingStrategy<>();mapper.setType(Person.class);mapper.setColumnMapping(columnMapping);// 写表头CSVWriter csvWriter = new CSVWriter(writer, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER, '\\', "\n");// String[] header = { "编号", "姓名", "年龄"};String[] header = { "id", "name", "age"};csvWriter.writeNext(header);StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer).withMappingStrategy(mapper).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).withSeparator(CSVWriter.DEFAULT_SEPARATOR).withEscapechar('\\').build();beanToCsv.write(dataList);csvWriter.close();writer.close();} catch (IOException e) {e.printStackTrace();} catch (CsvDataTypeMismatchException e) {e.printStackTrace();} catch (CsvRequiredFieldEmptyException e) {e.printStackTrace();}System.out.println(finalPath + "数据导出成功");}
public void readCsv(String finalPath) {try {Reader reader = new InputStreamReader(new FileInputStream(finalPath), StandardCharsets.UTF_8);CSVReader csvReader = new CSVReaderBuilder(reader).build();// 列名的映射// HeaderColumnNameTranslateMappingStrategy<Person> strategy =// new HeaderColumnNameTranslateMappingStrategy<>();// strategy.setType(Person.class);// Map<String, String> columnMapping = new HashMap<>();// columnMapping.put("编号", "id");// columnMapping.put("姓名", "name");// columnMapping.put("年龄", "age");// strategy.setColumnMapping(columnMapping);CsvToBean<Person> csvToBean = new CsvToBeanBuilder<Person>(csvReader).withSeparator(CSVWriter.DEFAULT_SEPARATOR).withQuoteChar(CSVWriter.NO_QUOTE_CHARACTER)// .withMappingStrategy(strategy).withType(Person.class).build();List<Person> list = csvToBean.parse();for (Person p : list) {System.out.println(p.toString());}csvReader.close();reader.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
中文乱码问题
String filePath = "F:/test.csv";File file = new File(filePath);CSVReader csvReader = null;AccountLFFChannelDto accountLFFChannelDto = new AccountLFFChannelDto();DataInputStream in = new DataInputStream(new FileInputStream(file));csvReader = new CSVReader(new InputStreamReader(in,"gbk"));List<String[]> list = csvReader.readAll();... 以下代码省略。。。
@Testpublic void readCsv() throws IOException, CsvException {try {String filePath = "/Users/jiadongpo/Downloads/【重要】加密数据/【保密】统一权限最新数据-20220517/ry.csv";File file = new File(filePath);DataInputStream in = new DataInputStream(new FileInputStream(file));CSVReader csvReader = new CSVReader(new InputStreamReader(in, "gbk"));String[] nextRecord;while ((nextRecord = csvReader.readNext()) != null) {System.out.println(nextRecord[0]);System.out.println(nextRecord[1]);System.out.println(nextRecord[2]);System.out.println(nextRecord[3]);System.out.println(nextRecord[4]);System.out.println(nextRecord[5]);/*for (String cell : nextRecord) {System.out.print(cell + "\t");}*/System.out.println();}} catch (Exception e) {e.printStackTrace();}}
跳过前几行
CSVReader reader = new CSVReaderBuilder(inputStreamReader).withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS)// Skip the header.withSkipLines(1).build();
String filePath = "/Users/xxx/Downloads/10_230_21_200_389.csv";File file = new File(filePath);DataInputStream in = new DataInputStream(new FileInputStream(file));CSVReader csvReader = new CSVReaderBuilder(new InputStreamReader(in, "gbk")).withFieldAsNull(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS)// Skip the header.withSkipLines(3).build();
