You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 20:42:31