CSV解析异常:含引号包裹逗号字段时抛出ArrayIndexOutOfBoundsException
解决CSV含逗号字段解析时的ArrayIndexOutOfBoundsException问题
嘿,这个坑我之前手动写CSV解析器的时候踩过好几次!问题出在你大概率是直接用了String.split(",")来分割每行,这种简单处理完全没法识别引号包裹的字段里的逗号——它会把引号里的逗号也当成分隔符,导致分割出来的数组元素数量和你预期的不一致,最后调用r.get(1)的时候自然就越界了。
最省心的解决方案:用成熟的CSV解析库
别自己造轮子了,手动处理CSV的各种边缘情况(比如引号里的引号、字段内换行、转义字符等)太容易出错。推荐用OpenCSV,这是Java/Android生态里最常用的CSV处理库之一,专门处理这些场景。
举个在AsyncTask里使用的例子:
import com.opencsv.CSVReader; import java.io.FileReader; import java.io.IOException; // 你的AsyncTask子类 private class CsvParseTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... voids) { CSVReader reader = null; try { // 替换成你的CSV文件路径 reader = new CSVReader(new FileReader("/path/to/your/file.csv")); String[] row; // 逐行读取,自动处理引号包裹的含逗号字段 while ((row = reader.readNext()) != null) { // 这里的row已经是正确分割后的字段数组 if (row.length >= 2) { // 先做长度检查,避免意外 String targetField = row[1]; // 处理你的业务逻辑 } else { // 处理格式异常的行,比如字段数量不足 Log.w("CSVParse", "Invalid row with insufficient fields"); } } } catch (IOException e) { e.printStackTrace(); // 处理IO异常 } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } }
如果非要自己写解析逻辑
如果你不想引入第三方库,那得手动实现一个能识别引号状态的解析方法,核心思路是遍历每行的字符,判断当前是否处于引号包裹状态——只有不在引号里的逗号才会被当成分隔符:
private List<String> parseCsvLine(String line) { List<String> fields = new ArrayList<>(); StringBuilder currentField = new StringBuilder(); boolean insideQuotes = false; for (char c : line.toCharArray()) { if (c == '"') { // 切换引号状态 insideQuotes = !insideQuotes; } else if (c == ',' && !insideQuotes) { // 不在引号内的逗号才是分隔符,添加当前字段并重置 fields.add(currentField.toString().trim()); currentField.setLength(0); } else { // 普通字符,添加到当前字段 currentField.append(c); } } // 添加最后一个字段 fields.add(currentField.toString().trim()); return fields; }
然后在你的AsyncTask里替换掉split的逻辑:
// 假设line是读取到的CSV行 List<String> rowFields = parseCsvLine(line); if (rowFields.size() >= 2) { String field = rowFields.get(1); // 处理逻辑 } else { // 处理异常行 }
额外提醒
- 手动解析的方法还没处理转义引号(CSV规范里用两个连续引号
""表示字段内的一个引号),如果你的CSV有这种场景,得在遍历字符的时候加判断。 - 不管用哪种方式,都要先检查数组/集合的长度再调用
get(),避免因为某行CSV格式本身错误导致的越界。 - Android平台上要注意文件读取的动态权限(Android 6.0+),不然会出现IO异常。
内容的提问来源于stack exchange,提问作者Jo Momma
相关产品推荐
相关产品推荐

