OutputStreamWriter写入文件仅生成单一条目,读取时触发NoSuchElementException问题求助
问题诊断与修复方案
嘿,我来帮你排查这个问题!从你给出的代码和日志来看,主要有几个关键点导致了NoSuchElementException,咱们一个个拆解:
1. 读取循环的致命bug:未更新行数据
你看读取代码里,只在循环开始前调用了一次reader.readLine(),循环体内完全没有重新读取下一行!这会导致程序一直重复处理第一行数据,直到某次处理时(比如第一行本身格式有问题)触发异常。
修复这个超简单,在循环末尾加上读取下一行的代码就行,同时别忘了关闭流:
public void run() { if (fileTimeZones.exists()){ System.out.println("Timezone file exists. Loading.. File size is : " + fileTimeZones.length()); try{ savedTimeZoneList.clear(); BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("TimeZones.dat"))); String lineFromTZfile = reader.readLine(); while (lineFromTZfile != null ){ StringTokenizer token = new StringTokenizer(lineFromTZfile,","); // 先检查token数量,避免直接抛异常 if (token.countTokens() >= 2) { AL_TimeZone timeZone = new AL_TimeZone(token.nextToken(), token.nextToken()); savedTimeZoneList.add(timeZone); } else { // 打印异常行,方便排查 System.out.println("Skipping invalid line: " + lineFromTZfile); } // 关键:读取下一行! lineFromTZfile = reader.readLine(); } reader.close(); // 别忘了关闭流! } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e){ // 打印当前处理的行,快速定位问题 System.out.println("Error processing line: " + lineFromTZfile); e.printStackTrace(); } } }
2. StringTokenizer的坑:忽略空字段
StringTokenizer默认会把连续的分隔符当成一个,而且不会识别空字段。举个例子,如果某个AL_TimeZone的getRegion()返回空字符串,写入的行就是,+08:00\n,这时StringTokenizer只会解析出1个token(+08:00),你调用两次nextToken()自然就会抛异常。
如果你的数据可能存在空字段,建议改用String.split()来分割,它能保留空字段:
while (lineFromTZfile != null ){ // 用limit=2确保只分割一次,避免region字段本身带逗号 String[] parts = lineFromTZfile.split(",", 2); if (parts.length == 2) { AL_TimeZone timeZone = new AL_TimeZone(parts[0].trim(), parts[1].trim()); savedTimeZoneList.add(timeZone); } else { System.out.println("Invalid line format: " + lineFromTZfile); } lineFromTZfile = reader.readLine(); }
3. 写入时的潜在风险:字段包含特殊字符
如果某个时区的region或offset里包含了逗号或者换行符,写入后会破坏行结构,读取时就会出现格式错误。建议写入前对特殊字符做转义:
public static void copy_TimeZonestoFile(ArrayList<AL_TimeZone> timezones, Context context){ try { FileOutputStream fileOutputStream = context.openFileOutput("TimeZones.dat",Context.MODE_PRIVATE); OutputStreamWriter writerFile = new OutputStreamWriter(fileOutputStream); int TZsize = timezones.size(); for (int i = 0; i < TZsize; i++) { // 转义逗号和换行符,避免破坏格式 String safeRegion = timezones.get(i).getRegion().replace(",", "\\,").replace("\n", "\\n"); String safeOffset = timezones.get(i).getOffset().replace(",", "\\,").replace("\n", "\\n"); writerFile.write(safeRegion + "," + safeOffset + "\n" ); } writerFile.flush(); writerFile.close(); fileOutputStream.close(); // 别忘了关闭文件流 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
读取的时候再把转义字符还原就行:
String region = parts[0].replace("\\,", ",").replace("\\n", "\n").trim(); String offset = parts[1].replace("\\,", ",").replace("\\n", "\n").trim();
最后:加上调试日志
在catch块里打印当前处理的行,能帮你快速定位到底是哪一行出了问题,比如:
catch (Exception e){ System.out.println("Error processing line: " + lineFromTZfile); e.printStackTrace(); }
按照这些步骤修改后,应该就能解决你的问题啦!
内容的提问来源于stack exchange,提问作者xv.ch
相关产品推荐
相关产品推荐

