我有以下问题:我试图在java中解析.csv文件,并在2维数组中专门存储3列。该方法的代码如下所示:
public static void parseFile(String filename) throws IOException{
FileReader readFile = new FileReader(filename);
BufferedReader buffer = new BufferedReader(readFile);
String line;
String[][] result = new String[10000][3];
String[] b = new String[6];
for(int i = 0; i<10000; i++){
while((line = buffer.readLine()) != null){
b = line.split(";",6);
System.out.println("ID: "+b[0]+" Title: "+b[3]+ "Description: "+b[4]); // Here is where the outofbounds exception occurs...
result[i][0] = b[0];
result[i][1] = b[3];
result[i][2] = b[4];
}
}
buffer.close();
}
我觉得我必须指定:.csv文件是巨大的。它有32列,(几乎)10.000个条目(!)。 解析时,我不断得到以下内容:
XXXXX CHUNKS OF SUCCESFULLY EXTRACTED CODE
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:3
at ParseCSV.parseFile(ParseCSV.java:24)
at ParseCSV.main(ParseCSV.java:41)
然而,我意识到文件中的某些东西有一种奇怪的格式,例如例如,其中的一些文本在其中有新行,但没有任何方式涉及换行符。但是,如果我手动删除这些空白行,则生成的输出(在提示错误消息之前)会将数据添加到数组中,直到下一个空白行... 有谁知道如何解决这个问题?任何帮助都会受到高度赞赏......
答案 0 :(得分:2)
您的第一个问题是您的csv文件中可能至少有一个空行。您需要替换:
b = line.split(";", 6);
与
b = line.split(";");
if(b.length() < 5){
System.err.println("Warning, line has only " + b.length() +
"entries, so skipping it:\n" + line);
continue;
}
如果您的输入可以合法地在条目中包含新行或嵌入的分号,那么这是一个更复杂的解析问题,您可能最好使用第三方解析库,因为有几个非常好的解析库。
如果您的输入不应该包含新行,则问题可能是\ r \ n。 Windows使用\ r \ n来表示新行,而大多数其他系统只使用\ n。如果多个人/程序编辑了你的文本文件,那么完全有可能自己最终得到stray \ r \ n,大多数解析器都不容易处理它们。
在分割线条之前轻松检查问题是否存在的方法,执行
line = line.replace("\r","").
如果这是您重复多次的过程,则可能需要考虑使用扫描程序(或库)来获得更有效的文本处理。否则,你可以做到这一点。
答案 1 :(得分:0)
当您在CSV文件中有新行时,请在此行之后 while((line = buffer.readLine())!= null){ 变量行不会有CSV行,而只有一些没有的文本;
例如,如果您有文件
column1;column2;column
3 value
在第一次迭代后变量行将有
列1;列2;柱
在第二次迭代之后它会有 3值
当你调用“3 value”.split(“;”,6)时,它将返回带有一个元素的数组。然后当你调用b [3]时,它会抛出异常。
CSV格式有许多小东西,要实现你将花费大量时间。这是一篇关于所有可能的csv示例的好文章 http://en.wikipedia.org/wiki/Comma-separated_values#Basic_rules_and_examples
我会向你推荐一些像这样的现成的CSV解析器
https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVParser.html
答案 2 :(得分:0)
请在访问b.length>0
之前检查b[]
。
答案 3 :(得分:0)
字符串的split(pattern,limit)方法返回一个数组,该数组的大小与找到的标记数一样,最多可达limit参数指定的数字。限制是最大值,而不是返回的最小数组元素数。
&#34; 1,2,3&#34;与(&#34;,&#34;,6)分开,返回3个元素的数组:&#34; 1&#34;,&#34; 2&#34;和&#34; 3&#34;。
&#34; 1,2,3,4,5,6,7&#34;将返回6个元素:&#34; 1&#34;,&#34; 2&#34;,&#34; 3&#34;,&#34; 4&#34;,&#34; 5&#34;和&#34;&#34; 6,7&#34;最后一个元素是愚蠢的,因为split方法在5之后停止了拆分,并将其余的源字符串作为第六个元素返回。
空行表示为空字符串(&#34;&#34;)。拆分&#34;&#34;将返回1个元素的数组,即空字符串。
在您的情况下,此处创建的字符串数组
String[] b = new String[6];
并将分配给b替换为
返回的数组b = line.split(";",6);
并且在看不见和不受欢迎的垃圾收集器的手中遇到它的最终命运。
更糟糕的是,在空行的情况下,它被一个元素数组替换,所以
System.out.println("ID: "+b[0]+" Title: "+b[3]+ "Description: "+b[4]);
尝试访问b [3]时爆炸。
建议的解决方案是
while((line = buffer.readLine()) != null){
if (line.length() != 0)
{
b = line.split(";",6);
System.out.println("ID: "+b[0]+" Title: "+b[3]+ "Description: "+b[4]); // Here is where the outofbounds exception occurs...
...
}
或(更好,因为前者可能会在错误的线路上跳闸)
while((line = buffer.readLine()) != null){
b = line.split(";",6);
if (b.length() == 6)
{
System.out.println("ID: "+b[0]+" Title: "+b[3]+ "Description: "+b[4]); // Here is where the outofbounds exception occurs...
...
}
您可能还想考虑for循环。我不认为它对你有益。
while((line = buffer.readLine()) != null)
将读取文件中的每一行,所以
for(int i = 0; i<10000; i++){
while((line = buffer.readLine()) != null){
将首次读取文件中的每一行。然后它将有9999次尝试读取文件,找不到任何新内容,并退出while循环。
因为while循环因为while循环将读取第1000个元素并且如果文件中有超过10000行而超出数组,则不会保护您不会读取超过10000个元素。考虑用arraylist或vector替换大数组,因为它们的大小将适合您的文件。