CSVReader读取数据缺失
来源:互联网 发布:c语言文件fclose 编辑:程序博客网 时间:2024/05/22 06:48
最近在项目中遇到一个导入CSV文件的程序数据缺失严重.2.4G的报表600多万行,导入数据库实际只有200多万行,最后终于找到了问题的所在,并解决了.记录Mark一下
前面的一些曲折过程,怀疑多线程来不及处理直接丢弃,就不讲了.
程序中用了while ((data = csvReader.readNext()) != null)
循环进行读取.
查看readNext源码,也是通过BufferedReader的readLine进行一行一行的读取,只是在字符串引用和转义进行了处理.CSV程序默认使用DEFAULT_SEPARATOR = ‘,’逗号作为一列与一列的分割符,DEFAULT_QUOTE_CHARACTER = ‘”’双引号作为字符串引用,就是当一列的内容中出现特殊字符如逗号时,怎么区分这个逗号的是列里面的内容还是列之间的分割,例如,一个文件里面某列内容为a,b,c为了区分这个a b c之间的逗号为本来的内容,所以用”a,b,c”这样表示,DEFAULT_ESCAPE_CHARACTER = ‘\’;反斜杠作为转义.
在字符串引用的处理,发现某列数据以双引号开头,但是在这一行没有发现与之对应的双引号,即是说这一行的双引号为奇数个,会读取下一行进行处理,直到找到与之匹配的双引号.例如,我们的报表在151行在Geometry dash后面出现了特殊字符换行符,在xStep后面也出现了换行符
用vim打开,这一行变成了三行,程序会把这三行当成一行处理,这本身没有什么问题.
但是程序中使用反斜杠作为转义,但是csv文件中使用双引号作为转义,这样就会造成\”这样的双引号不做特殊处理,导致双引号不匹配,程序继续读取下一行,造成数据丢失并且数据混乱.
由于CSVReader默认为反斜杠,又不能将转义设置为双引号,这样会和字符串引用的双引号重复,程序处理会混乱,并且程序会抛出异常The separator, quote, and escape characters must be different!,最后重写一个不带转义的CSVReader构造器,重新打个jar包,最后能够读取数据6340034行,解决
附readNext关键代码:
public String[] readNext() throws IOException {
String[] result = null; do { String nextLine = getNextLine(); if (!hasNext) { return result; // should throw if still pending? } String[] r = parser.parseLineMulti(nextLine); if (r.length > 0) { if (result == null) { result = r; } else { String[] t = new String[result.length+r.length]; System.arraycopy(result, 0, t, 0, result.length); System.arraycopy(r, 0, t, result.length, r.length); result = t; } } } while (parser.isPending()); return result;}private String[] parseLine(String nextLine, boolean multi) throws IOException { if (!multi && pending != null) { pending = null; } if (nextLine == null) { if (pending != null) { String s = pending; pending = null; return new String[]{s}; } else { return null; } } List<String> tokensOnThisLine = new ArrayList<String>(); StringBuilder sb = new StringBuilder(INITIAL_READ_SIZE); boolean inQuotes = false; if (pending != null) { sb.append(pending); pending = null; inQuotes = true; } for (int i = 0; i < nextLine.length(); i++) { char c = nextLine.charAt(i); if ( useEscape && c == this.escape) { if (isNextCharacterEscapable(nextLine, inQuotes || inField, i)) { sb.append(nextLine.charAt(i + 1)); i++; } } else if (c == quotechar) { if (isNextCharacterEscapedQuote(nextLine, inQuotes || inField, i)) { sb.append(nextLine.charAt(i + 1)); i++; } else { //inQuotes = !inQuotes; // the tricky case of an embedded quote in the middle: a,bc"d"ef,g if (!strictQuotes) { if (i > 2 //not on the beginning of the line && nextLine.charAt(i - 1) != this.separator //not at the beginning of an escape sequence && nextLine.length() > (i + 1) && nextLine.charAt(i + 1) != this.separator //not at the end of an escape sequence ) { if (ignoreLeadingWhiteSpace && sb.length() > 0 && isAllWhiteSpace(sb)) { sb.setLength(0); //discard white space leading up to quote } else { sb.append(c); //continue; } } } inQuotes = !inQuotes; } inField = !inField; } else if (c == separator && !inQuotes) { tokensOnThisLine.add(sb.toString()); sb.setLength(0); // start work on next token inField = false; } else { if (!strictQuotes || inQuotes) { sb.append(c); inField = true; } } } // line is done - check status if (inQuotes) { if (multi) { // continuing a quoted section, re-append newline sb.append("\n"); pending = sb.toString(); sb = null; // this partial content is not to be added to field list yet } else { throw new IOException("Un-terminated quoted field at end of CSV line"); } } if (sb != null) { tokensOnThisLine.add(sb.toString()); } return tokensOnThisLine.toArray(new String[tokensOnThisLine.size()]);}
- CSVReader读取数据缺失
- pandas读取Excel文件,以0开头的数据,出现数据缺失
- java使用CsvReader和CsvWriter对csv文件内容进行读取和写入操作
- InputStream——输入流读取数据缺失或多余现象
- 缺失数据检查
- pandas处理缺失数据
- Python处理缺失数据
- 关于数据缺失
- 数据挖掘填补缺失数据
- SAP ALO1 归档数据缺失
- 【R】数据缺失值处理
- sklearn 数据缺失值处理
- 数据中的缺失值处理
- 数据缺失的处理方法
- 数据清洗---缺失值处理
- 数据缺失的中文字符串
- 数据挖掘-处理缺失值
- pandas处理,填充缺失数据
- hdu1005Number Sequence(循环节)
- 大数据IMF传奇行动绝密课程第34课:Stage划分和Task最佳位置算法解密
- javascript中apply()和call()方法的区别
- 灵云语音唤醒
- cordic算法原理及verilog实现
- CSVReader读取数据缺失
- java 通过流的方式读取本地图片并显示在jsp 页面上(类型以jpg、png等结尾的图片)
- hbase源码分析-是否split
- 华为在线训练(10)
- Docker部署OpenStack API
- linx x86平台成功注入so 并且通道rel进行hook
- linu 用户及用户组命令操作
- Spring bean的作用域
- #11 Search Range in Binary Search Tree