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

 一:主要内容

  • 解决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类的基础上做了一些修改

  1 /**
  2  * Copyright (C), 2015-2019, XXX有限公司
  3  * FileName: CsvWriterExtend
  4  * Author:   yml
  5  * Date:     2019/5/17 15:42
  6  * Description:
  7  * History:
  8  * <author>          <time>          <version>          <desc>
  9  * tester           2019.5.17           1.0.0              优化CsvWriter工具
 10  */
 11 package com.test.csv.tool;
 12 
 13 import com.csvreader.CsvWriter;
 14 
 15 import java.io.*;
 16 import java.nio.charset.Charset;
 17 
 18 /**
 19  * @创建人 tester
 20  * @创建时间 2019/5/17
 21  * @描述 优化CsvWriter工具,解决了写入csv打开后中文乱码问题,解决了写入csv最后一行有/r换行的问题
 22  *
 23  */
 24 public class CsvWriterExtend extends CsvWriter {
 25     private PrintWriter outputStream;
 26     private String fileName;
 27     private boolean firstColumn;
 28     private boolean useCustomRecordDelimiter;
 29     private Charset charset;
 30     private CsvWriterExtend.UserSettings userSettings;
 31     private boolean initialized;
 32     private boolean closed;
 33     public static final int ESCAPE_MODE_DOUBLED = 1;
 34     public static final int ESCAPE_MODE_BACKSLASH = 2;
 35     private String sheetFirstName;
 36 
 37     public CsvWriterExtend(String var1, char var2, Charset var3,String sheetFirstName) {
 38         super(var1,var2,var3);
 39         this.outputStream = null;
 40         this.fileName = null;
 41         this.firstColumn = true;
 42         this.useCustomRecordDelimiter = false;
 43         this.charset = null;
 44         this.userSettings = new CsvWriterExtend.UserSettings();
 45         this.initialized = false;
 46         this.closed = false;
 47         //1:这里加了一个csv表头的第一个名字字段,用来解决第一个问题:中文乱码问题
 48         this.sheetFirstName = sheetFirstName;
 49         if (var1 == null) {
 50             throw new IllegalArgumentException("Parameter fileName can not be null.");
 51         } else if (var3 == null) {
 52             throw new IllegalArgumentException("Parameter charset can not be null.");
 53         } else {
 54             this.fileName = var1;
 55             this.userSettings.Delimiter = var2;
 56             this.charset = var3;
 57         }
 58     }
 59 
 60     public CsvWriterExtend(Writer var1, char var2) {
 61         super(var1,var2);
 62         this.outputStream = null;
 63         this.fileName = null;
 64         this.firstColumn = true;
 65         this.useCustomRecordDelimiter = false;
 66         this.charset = null;
 67         this.userSettings = new CsvWriterExtend.UserSettings();
 68         this.initialized = false;
 69         this.closed = false;
 70         if (var1 == null) {
 71             throw new IllegalArgumentException("Parameter outputStream can not be null.");
 72         } else {
 73             this.outputStream = new PrintWriter(var1);
 74             this.userSettings.Delimiter = var2;
 75             this.initialized = true;
 76         }
 77     }
 78 
 79     public CsvWriterExtend(OutputStream var1, char var2, Charset var3) {
 80         this(new OutputStreamWriter(var1, var3), var2);
 81     }
 82 
 83     public char getDelimiter() {
 84         return this.userSettings.Delimiter;
 85     }
 86 
 87     public void setDelimiter(char var1) {
 88         this.userSettings.Delimiter = var1;
 89     }
 90 
 91     public char getRecordDelimiter() {
 92         return this.userSettings.RecordDelimiter;
 93     }
 94 
 95     public void setRecordDelimiter(char var1) {
 96         this.useCustomRecordDelimiter = true;
 97         this.userSettings.RecordDelimiter = var1;
 98     }
 99 
100     public char getTextQualifier() {
101         return this.userSettings.TextQualifier;
102     }
103 
104     public void setTextQualifier(char var1) {
105         this.userSettings.TextQualifier = var1;
106     }
107 
108     public boolean getUseTextQualifier() {
109         return this.userSettings.UseTextQualifier;
110     }
111 
112     public void setUseTextQualifier(boolean var1) {
113         this.userSettings.UseTextQualifier = var1;
114     }
115 
116     public int getEscapeMode() {
117         return this.userSettings.EscapeMode;
118     }
119 
120     public void setEscapeMode(int var1) {
121         this.userSettings.EscapeMode = var1;
122     }
123 
124     public void setComment(char var1) {
125         this.userSettings.Comment = var1;
126     }
127 
128     public char getComment() {
129         return this.userSettings.Comment;
130     }
131 
132     public boolean getForceQualifier() {
133         return this.userSettings.ForceQualifier;
134     }
135 
136     public void setForceQualifier(boolean var1) {
137         this.userSettings.ForceQualifier = var1;
138     }
139 
140     public void write(String var1, boolean var2) throws IOException {
141         this.checkClosed();
142         this.checkInit();
143         if (var1 == null) {
144             var1 = "";
145         }
146         //2:这里加了一个判断条件,用来解决第一个问题:中文乱码问题
147         //加的目的是:如果是写入bom则bom后面不追加逗号,即在bom后面和第一个表头前面,即两者之间不追加逗号,sheetFirstName为第一个表头的名字根据实际传入
148         if (!this.firstColumn && !var1.contentEquals(sheetFirstName) ){
149             this.outputStream.write(this.userSettings.Delimiter);
150         }
151 
152         boolean var3 = this.userSettings.ForceQualifier;
153         if (!var2 && var1.length() > 0) {
154             var1 = var1.trim();
155         }
156 
157         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)) {
158             var3 = true;
159         }
160 
161         if (this.userSettings.UseTextQualifier && !var3 && var1.length() > 0 && var2) {
162             char var4 = var1.charAt(0);
163             if (var4 == ' ' || var4 == '	') {
164                 var3 = true;
165             }
166 
167             if (!var3 && var1.length() > 1) {
168                 char var5 = var1.charAt(var1.length() - 1);
169                 if (var5 == ' ' || var5 == '	') {
170                     var3 = true;
171                 }
172             }
173         }
174         //3:这里加了一个if语句,是为了解决第三个问题:csv""显示null的问题
175         if(!this.firstColumn && var1.length()==0){
176             var3=true;
177         }
178         if (var3) {
179             this.outputStream.write(this.userSettings.TextQualifier);
180             if (this.userSettings.EscapeMode == 2) {
181                 var1 = replace(var1, "\", "\\");
182                 var1 = replace(var1, "" + this.userSettings.TextQualifier, "\" + this.userSettings.TextQualifier);
183             } else {
184                 var1 = replace(var1, "" + this.userSettings.TextQualifier, "" + this.userSettings.TextQualifier + this.userSettings.TextQualifier);
185             }
186         } else if (this.userSettings.EscapeMode == 2) {
187             var1 = replace(var1, "\", "\\");
188             var1 = replace(var1, "" + this.userSettings.Delimiter, "\" + this.userSettings.Delimiter);
189             if (this.useCustomRecordDelimiter) {
190                 var1 = replace(var1, "" + this.userSettings.RecordDelimiter, "\" + this.userSettings.RecordDelimiter);
191             } else {
192                 var1 = replace(var1, "
", "\
");
193                 var1 = replace(var1, "
", "\
");
194             }
195 
196             if (this.firstColumn && var1.length() > 0 && var1.charAt(0) == this.userSettings.Comment) {
197                 if (var1.length() > 1) {
198                     var1 = "\" + this.userSettings.Comment + var1.substring(1);
199                 } else {
200                     var1 = "\" + this.userSettings.Comment;
201                 }
202             }
203         }
204 
205 
206         this.outputStream.write(var1);
207 
208         if (var3) {
209             this.outputStream.write(this.userSettings.TextQualifier);
210         }
211 
212         this.firstColumn = false;
213     }
214 
215     public void write(String var1) throws IOException {
216         this.write(var1, false);
217     }
218 
219     public void writeComment(String var1) throws IOException {
220         this.checkClosed();
221         this.checkInit();
222         this.outputStream.write(this.userSettings.Comment);
223         this.outputStream.write(var1);
224         if (this.useCustomRecordDelimiter) {
225             this.outputStream.write(this.userSettings.RecordDelimiter);
226         } else {
227             this.outputStream.println();
228         }
229 
230         this.firstColumn = true;
231     }
232 
233     public void writeRecord(String[] var1, boolean var2) throws IOException {
234         if (var1 != null && var1.length > 0) {
235             for(int var3 = 0; var3 < var1.length; ++var3) {
236                 this.write(var1[var3], var2);
237             }
238 
239             this.endRecord();
240         }
241 
242     }
243 
244     public void writeRecord(String[] var1) throws IOException {
245         this.writeRecord(var1, false);
246     }
247     
248     public void writeLastRecord(String[] var1) throws IOException {
249         this.writeLastRecord(var1, false);
250     }
251     
252     //4:这里加了两个方法writeLastRecord和endLastRecord,用来解决第二个问题:某尾总是多一行空行的问题
253     public void writeLastRecord(String[] var1, boolean var2) throws IOException {
254         if (var1 != null && var1.length > 0) {
255             for(int var3 = 0; var3 < var1.length; ++var3) {
256                 this.write(var1[var3], var2);
257             }
258 
259             this.endLastRecord();
260         }
261 
262     }
263     public void endLastRecord() throws IOException {
264         this.checkClosed();
265         this.checkInit();
266         if (this.useCustomRecordDelimiter) {
267             this.outputStream.write(this.userSettings.RecordDelimiter);
268         } else {//主要在下面这一行,当执行这个方法来结尾的时候是不追加换行符的
269             this.outputStream.print("");
270         }
271 
272         this.firstColumn = true;
273     }
274 
275     public void endRecord() throws IOException {
276         this.checkClosed();
277         this.checkInit();
278         if (this.useCustomRecordDelimiter) {
279             this.outputStream.write(this.userSettings.RecordDelimiter);
280         } else {
281             this.outputStream.println();
282         }
283 
284         this.firstColumn = true;
285     }
286 
287     private void checkInit() throws IOException {
288         if (!this.initialized) {
289             if (this.fileName != null) {
290                 this.outputStream = new PrintWriter(new OutputStreamWriter(new FileOutputStream(this.fileName), this.charset));
291             }
292 
293             this.initialized = true;
294         }
295 
296     }
297 
298     public void flush() {
299         this.outputStream.flush();
300     }
301 
302     public void close() {
303         if (!this.closed) {
304             this.close(true);
305             this.closed = true;
306         }
307 
308     }
309 
310     private void close(boolean var1) {
311         if (!this.closed) {
312             if (var1) {
313                 this.charset = null;
314             }
315 
316             try {
317                 if (this.initialized) {
318                     this.outputStream.close();
319                 }
320             } catch (Exception var3) {
321                 ;
322             }
323 
324             this.outputStream = null;
325             this.closed = true;
326         }
327 
328     }
329 
330     private void checkClosed() throws IOException {
331         if (this.closed) {
332             throw new IOException("This instance of the CsvWriter class has already been closed.");
333         }
334     }
335 
336     protected void finalize() {
337         this.close(false);
338     }
339 
340     public static String replace(String var0, String var1, String var2) {
341         int var3 = var1.length();
342         int var4 = var0.indexOf(var1);
343         if (var4 <= -1) {
344             return var0;
345         } else {
346             StringBuffer var5 = new StringBuffer();
347 
348             int var6;
349             for(var6 = 0; var4 != -1; var4 = var0.indexOf(var1, var6)) {
350                 var5.append(var0.substring(var6, var4));
351                 var5.append(var2);
352                 var6 = var4 + var3;
353             }
354 
355             var5.append(var0.substring(var6));
356             return var5.toString();
357         }
358     }
359 
360     private class UserSettings {
361         public char TextQualifier = '"';
362         public boolean UseTextQualifier = true;
363         public char Delimiter = ',';
364         public char RecordDelimiter = 0;
365         public char Comment = '#';
366         public int EscapeMode = 1;
367         public boolean ForceQualifier = false;
368 
369         public UserSettings() {
370         }
371     }
372 
373     private class Letters {
374         public static final char LF = '
';
375         public static final char CR = '
';
376         public static final char QUOTE = '"';
377         public static final char COMMA = ',';
378         public static final char SPACE = ' ';
379         public static final char TAB = '	';
380         public static final char POUND = '#';
381         public static final char BACKSLASH = '\';
382         public static final char NULL = 'u0000';
383 
384         private Letters() {
385         }
386     }
387 }            

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

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

 1  /**
 2      * 写csv方法
 3      */
 4     public static <T> void writeCSV(Collection<T> dataset, String csvFilePath, String[] csvHeaders) {
 5 
 6         try {
 7             //集合长度,和循环次数,当循环到最后一条记录时不在末尾插入换行符
 8             int datasetLength = dataset.size();
 9             int loop=1;
10             // 定义路径,分隔符,编码d,第一个表头名称
11             //如果是写入bom则bom后面不追加逗号,即在bom后面和第一个表头前面,即两者之间不追加逗号,sheetFirstName为第一个表头的名字根据实际传入
12             CsvWriterExtend csvWriter = new CsvWriterExtend(csvFilePath, ',', Charset.forName("UTF-8"),"username"); // 写表头
13             //如果是写入bom解决文件乱码,则不在bom后面追加,号分隔符
14             csvWriter.write("ufeff");
15             csvWriter.writeRecord(csvHeaders); // 写内容
16             // 遍历集合
17             Iterator<T> it = dataset.iterator();
18             while (it.hasNext()) {
19                 T t = (T) it.next();
20                 //获取类属性
21                 Field[] fields = t.getClass().getDeclaredFields();
22                 String[] csvContent=new String[fields.length];
23                 for (short i = 0; i < fields.length; i++) {
24                     Field field = fields[i];
25                     String fieldName = field.getName();
26                     String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
27                     try {
28                         Class tCls = t.getClass();
29                         Method getMethod = tCls.getMethod(getMethodName,new Class[] {});
30                         Object value = getMethod.invoke(t, new Object[] {});
31                         if (value == null) {
32                             continue;
33                         }
34                         //取值并赋给数组
35                         String textvalue=value.toString();
36                         csvContent[i]=textvalue;
37                     }catch (Exception e) {
38                         e.getStackTrace();
39                     }
40                 }
41                 if(loop!=datasetLength){
42                     //迭代插入记录
43                     csvWriter.writeRecord(csvContent);
44                 }else{
45                     //插入最后一条记录
46                     csvWriter.writeLastRecord(csvContent);
47                 }
48 
49                 loop=loop+1;
50                 for(String csvs:csvContent) {
51                     System.out.println("记录数据:" + csvs);
52                 }
53             } csvWriter.close();
54             System.out.println("<--------CSV文件写入成功-------->");
55         } catch (IOException e) {
56             e.printStackTrace();
57         }
58     }

调用csv方法即执行类

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

生成csv的效果如图:

四:备注

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

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

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

原文地址:https://www.cnblogs.com/miaomiaokaixin/p/10885302.html