解决CsvWriter:中文乱码、末尾行多一行空格(/r)、非第一列空字符串""显示null问题

时间:2022-10-14 15:50:39

一:主要内容

  • 解决CsvWriter存csv,csv文件打开后中文乱码问题
  • 解决CsvWriter存csv,csv文件最后一行总是多一行空行的问题
  • 解决CsvWriter存csv,csv文件不是第一列的时候,想存入""即空字符串无法存入显示null的问题

二:解决问题前:需要做的事情

因为网上的CsvWrite的jar包导入到我们的工程中是class文件,针对上面的问题是无法修改源码的,但是我们又想用这个工具来操作csv,所以可以在自己的工程中首先pom引用这个jar包

 <dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
<version>2.0</version>
</dependency>

然后我们在自己的工程中创建一个类:CsvWriterExtend来继承CsvWriter,这样我们就能用网上CsvWriter这个jar中的方法,还能基于这个去修改代码,解决上诉的问题

public class CsvWriterExtend extends CsvWriter {}

三:优化解决CsvWriter工具存在的三个问题:中文乱码、末尾行多一行空格(/r)、非第一列空字符串""显示null问题

此处废话不多说,先上CsvWriterExtend类的代码,然后我们在代码中红色标注的地方会有说明,这段用来解决什么问题的,说明一下:CsvWriterExtend代码只是在CsvWriter类的基础上做了一些修改

 /**
* Copyright (C), 2015-2019, XXX有限公司
* FileName: CsvWriterExtend
* Author: yml
* Date: 2019/5/17 15:42
* Description:
* History:
* <author> <time> <version> <desc>
* tester 2019.5.17 1.0.0 优化CsvWriter工具
*/
package com.test.csv.tool; import com.csvreader.CsvWriter; import java.io.*;
import java.nio.charset.Charset; /**
* @创建人 tester
* @创建时间 2019/5/17
* @描述 优化CsvWriter工具,解决了写入csv打开后中文乱码问题,解决了写入csv最后一行有/r换行的问题
*
*/
public class CsvWriterExtend extends CsvWriter {
private PrintWriter outputStream;
private String fileName;
private boolean firstColumn;
private boolean useCustomRecordDelimiter;
private Charset charset;
private CsvWriterExtend.UserSettings userSettings;
private boolean initialized;
private boolean closed;
public static final int ESCAPE_MODE_DOUBLED = 1;
public static final int ESCAPE_MODE_BACKSLASH = 2;
private String sheetFirstName; public CsvWriterExtend(String var1, char var2, Charset var3,String sheetFirstName) {
super(var1,var2,var3);
this.outputStream = null;
this.fileName = null;
this.firstColumn = true;
this.useCustomRecordDelimiter = false;
this.charset = null;
this.userSettings = new CsvWriterExtend.UserSettings();
this.initialized = false;
this.closed = false;
//1:这里加了一个csv表头的第一个名字字段,用来解决第一个问题:中文乱码问题
this.sheetFirstName = sheetFirstName;
if (var1 == null) {
throw new IllegalArgumentException("Parameter fileName can not be null.");
} else if (var3 == null) {
throw new IllegalArgumentException("Parameter charset can not be null.");
} else {
this.fileName = var1;
this.userSettings.Delimiter = var2;
this.charset = var3;
}
} public CsvWriterExtend(Writer var1, char var2) {
super(var1,var2);
this.outputStream = null;
this.fileName = null;
this.firstColumn = true;
this.useCustomRecordDelimiter = false;
this.charset = null;
this.userSettings = new CsvWriterExtend.UserSettings();
this.initialized = false;
this.closed = false;
if (var1 == null) {
throw new IllegalArgumentException("Parameter outputStream can not be null.");
} else {
this.outputStream = new PrintWriter(var1);
this.userSettings.Delimiter = var2;
this.initialized = true;
}
} public CsvWriterExtend(OutputStream var1, char var2, Charset var3) {
this(new OutputStreamWriter(var1, var3), var2);
} public char getDelimiter() {
return this.userSettings.Delimiter;
} public void setDelimiter(char var1) {
this.userSettings.Delimiter = var1;
} public char getRecordDelimiter() {
return this.userSettings.RecordDelimiter;
} public void setRecordDelimiter(char var1) {
this.useCustomRecordDelimiter = true;
this.userSettings.RecordDelimiter = var1;
} public char getTextQualifier() {
return this.userSettings.TextQualifier;
} public void setTextQualifier(char var1) {
this.userSettings.TextQualifier = var1;
} public boolean getUseTextQualifier() {
return this.userSettings.UseTextQualifier;
} public void setUseTextQualifier(boolean var1) {
this.userSettings.UseTextQualifier = var1;
} public int getEscapeMode() {
return this.userSettings.EscapeMode;
} public void setEscapeMode(int var1) {
this.userSettings.EscapeMode = var1;
} public void setComment(char var1) {
this.userSettings.Comment = var1;
} public char getComment() {
return this.userSettings.Comment;
} public boolean getForceQualifier() {
return this.userSettings.ForceQualifier;
} public void setForceQualifier(boolean var1) {
this.userSettings.ForceQualifier = var1;
} public void write(String var1, boolean var2) throws IOException {
this.checkClosed();
this.checkInit();
if (var1 == null) {
var1 = "";
}
//2:这里加了一个判断条件,用来解决第一个问题:中文乱码问题
//加的目的是:如果是写入bom则bom后面不追加逗号,即在bom后面和第一个表头前面,即两者之间不追加逗号,sheetFirstName为第一个表头的名字根据实际传入
if (!this.firstColumn && !var1.contentEquals(sheetFirstName) ){
this.outputStream.write(this.userSettings.Delimiter);
} boolean var3 = this.userSettings.ForceQualifier;
if (!var2 && var1.length() > 0) {
var1 = var1.trim();
} if (!var3 && this.userSettings.UseTextQualifier && (var1.indexOf(this.userSettings.TextQualifier) > -1 || var1.indexOf(this.userSettings.Delimiter) > -1 || !this.useCustomRecordDelimiter && (var1.indexOf(10) > -1 || var1.indexOf(13) > -1) || this.useCustomRecordDelimiter && var1.indexOf(this.userSettings.RecordDelimiter) > -1 || this.firstColumn && var1.length() > 0 && var1.charAt(0) == this.userSettings.Comment || this.firstColumn && var1.length() == 0)) {
var3 = true;
} if (this.userSettings.UseTextQualifier && !var3 && var1.length() > 0 && var2) {
char var4 = var1.charAt(0);
if (var4 == ' ' || var4 == '\t') {
var3 = true;
} if (!var3 && var1.length() > 1) {
char var5 = var1.charAt(var1.length() - 1);
if (var5 == ' ' || var5 == '\t') {
var3 = true;
}
}
}
//3:这里加了一个if语句,是为了解决第三个问题:csv""显示null的问题
if(!this.firstColumn && var1.length()==0){
var3=true;
}
if (var3) {
this.outputStream.write(this.userSettings.TextQualifier);
if (this.userSettings.EscapeMode == 2) {
var1 = replace(var1, "\\", "\\\\");
var1 = replace(var1, "" + this.userSettings.TextQualifier, "\\" + this.userSettings.TextQualifier);
} else {
var1 = replace(var1, "" + this.userSettings.TextQualifier, "" + this.userSettings.TextQualifier + this.userSettings.TextQualifier);
}
} else if (this.userSettings.EscapeMode == 2) {
var1 = replace(var1, "\\", "\\\\");
var1 = replace(var1, "" + this.userSettings.Delimiter, "\\" + this.userSettings.Delimiter);
if (this.useCustomRecordDelimiter) {
var1 = replace(var1, "" + this.userSettings.RecordDelimiter, "\\" + this.userSettings.RecordDelimiter);
} else {
var1 = replace(var1, "\r", "\\\r");
var1 = replace(var1, "\n", "\\\n");
} if (this.firstColumn && var1.length() > 0 && var1.charAt(0) == this.userSettings.Comment) {
if (var1.length() > 1) {
var1 = "\\" + this.userSettings.Comment + var1.substring(1);
} else {
var1 = "\\" + this.userSettings.Comment;
}
}
} this.outputStream.write(var1); if (var3) {
this.outputStream.write(this.userSettings.TextQualifier);
} this.firstColumn = false;
} public void write(String var1) throws IOException {
this.write(var1, false);
} public void writeComment(String var1) throws IOException {
this.checkClosed();
this.checkInit();
this.outputStream.write(this.userSettings.Comment);
this.outputStream.write(var1);
if (this.useCustomRecordDelimiter) {
this.outputStream.write(this.userSettings.RecordDelimiter);
} else {
this.outputStream.println();
} this.firstColumn = true;
} public void writeRecord(String[] var1, boolean var2) throws IOException {
if (var1 != null && var1.length > 0) {
for(int var3 = 0; var3 < var1.length; ++var3) {
this.write(var1[var3], var2);
} this.endRecord();
} } public void writeRecord(String[] var1) throws IOException {
this.writeRecord(var1, false);
} public void writeLastRecord(String[] var1) throws IOException {
this.writeLastRecord(var1, false);
} //4:这里加了两个方法writeLastRecord和endLastRecord,用来解决第二个问题:某尾总是多一行空行的问题
public void writeLastRecord(String[] var1, boolean var2) throws IOException {
if (var1 != null && var1.length > 0) {
for(int var3 = 0; var3 < var1.length; ++var3) {
this.write(var1[var3], var2);
} this.endLastRecord();
} }
public void endLastRecord() throws IOException {
this.checkClosed();
this.checkInit();
if (this.useCustomRecordDelimiter) {
this.outputStream.write(this.userSettings.RecordDelimiter);
} else {//主要在下面这一行,当执行这个方法来结尾的时候是不追加换行符的
this.outputStream.print("");
} this.firstColumn = true;
} public void endRecord() throws IOException {
this.checkClosed();
this.checkInit();
if (this.useCustomRecordDelimiter) {
this.outputStream.write(this.userSettings.RecordDelimiter);
} else {
this.outputStream.println();
} this.firstColumn = true;
} private void checkInit() throws IOException {
if (!this.initialized) {
if (this.fileName != null) {
this.outputStream = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.fileName), this.charset));
} this.initialized = true;
} } public void flush() {
this.outputStream.flush();
} public void close() {
if (!this.closed) {
this.close(true);
this.closed = true;
} } private void close(boolean var1) {
if (!this.closed) {
if (var1) {
this.charset = null;
} try {
if (this.initialized) {
this.outputStream.close();
}
} catch (Exception var3) {
;
} this.outputStream = null;
this.closed = true;
} } private void checkClosed() throws IOException {
if (this.closed) {
throw new IOException("This instance of the CsvWriter class has already been closed.");
}
} protected void finalize() {
this.close(false);
} public static String replace(String var0, String var1, String var2) {
int var3 = var1.length();
int var4 = var0.indexOf(var1);
if (var4 <= -1) {
return var0;
} else {
StringBuffer var5 = new StringBuffer(); int var6;
for(var6 = 0; var4 != -1; var4 = var0.indexOf(var1, var6)) {
var5.append(var0.substring(var6, var4));
var5.append(var2);
var6 = var4 + var3;
} var5.append(var0.substring(var6));
return var5.toString();
}
} private class UserSettings {
public char TextQualifier = '"';
public boolean UseTextQualifier = true;
public char Delimiter = ',';
public char RecordDelimiter = 0;
public char Comment = '#';
public int EscapeMode = 1;
public boolean ForceQualifier = false; public UserSettings() {
}
} private class Letters {
public static final char LF = '\n';
public static final char CR = '\r';
public static final char QUOTE = '"';
public static final char COMMA = ',';
public static final char SPACE = ' ';
public static final char TAB = '\t';
public static final char POUND = '#';
public static final char BACKSLASH = '\\';
public static final char NULL = '\u0000'; private Letters() {
}
}
}

四:调用写好的CsvWriterExtend类,实现写csv功能

下面给出写csv的方法,如下红色部分是解决上诉三个问题的关键:中文乱码、末尾行多一行空格(/r)、非第一列空字符串""显示null问题

  /**
* 写csv方法
*/
public static <T> void writeCSV(Collection<T> dataset, String csvFilePath, String[] csvHeaders) { try {
//集合长度,和循环次数,当循环到最后一条记录时不在末尾插入换行符
int datasetLength = dataset.size();
int loop=1;
// 定义路径,分隔符,编码d,第一个表头名称
//如果是写入bom则bom后面不追加逗号,即在bom后面和第一个表头前面,即两者之间不追加逗号,sheetFirstName为第一个表头的名字根据实际传入
CsvWriterExtend csvWriter = new CsvWriterExtend(csvFilePath, ',', Charset.forName("UTF-8"),"username"); // 写表头
//如果是写入bom解决文件乱码,则不在bom后面追加,号分隔符
csvWriter.write("\ufeff");
csvWriter.writeRecord(csvHeaders); // 写内容
// 遍历集合
Iterator<T> it = dataset.iterator();
while (it.hasNext()) {
T t = (T) it.next();
//获取类属性
Field[] fields = t.getClass().getDeclaredFields();
String[] csvContent=new String[fields.length];
for (short i = 0; i < fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
try {
Class tCls = t.getClass();
Method getMethod = tCls.getMethod(getMethodName,new Class[] {});
Object value = getMethod.invoke(t, new Object[] {});
if (value == null) {
continue;
}
//取值并赋给数组
String textvalue=value.toString();
csvContent[i]=textvalue;
}catch (Exception e) {
e.getStackTrace();
}
}
if(loop!=datasetLength){
//迭代插入记录
csvWriter.writeRecord(csvContent);
}else{
//插入最后一条记录
csvWriter.writeLastRecord(csvContent);
} loop=loop+1;
for(String csvs:csvContent) {
System.out.println("记录数据:" + csvs);
}
} csvWriter.close();
System.out.println("<--------CSV文件写入成功-------->");
} catch (IOException e) {
e.printStackTrace();
}
}

调用csv方法即执行类

 public static void main(String[] args) throws Exception{
//造测试数据
List<DataEntity> data = CreateDataModel.createUserData();
String csvFilePath = "E://data.csv";
//表头名称
//注册用户名、注册密码、登录用户名、登录密码、记住我、邮箱、分类名称、文章标题、文章路径、文章标签、文章内容、评论文章、期望结果
String[] csvHeaders = { "username", "password", "loginusername","loginpassword","remeber","email","cname","title","slug","tags","content","comment","expectresult" };
CreateDataModel.writeCSV(data,csvFilePath,csvHeaders); }

生成csv的效果如图:

解决CsvWriter:中文乱码、末尾行多一行空格(/r)、非第一列空字符串""显示null问题

四:备注

如果想看更详细的代码,可参考我的github地址,如上csv的生成已全部上传github中,地址如下:

https://github.com/mmkxyu/auto-create-test-data.git

博文均为原创文章,转载请注明出处,感谢!