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

读取文件的Java代码输出多余字符及序号错误问题求助

Java逐字符读取文件的两个问题及修复方案

问题说明

这段代码用于逐字符读取文本文件并打印行号、字符序号和对应字符,但存在两个明显问题:

  1. 序号更新逻辑错误:比如从"1 : 5 o"跳转至下一行时,本该先输出"2 : 0 "再到"2 : 1 C",实际却先输出了错误的"1 : 6 "
  2. 文件末尾会读取到莫名的"?"字符

原代码

public class FileReaderDemo {
    // 补充原代码遗漏的类定义与全局变量
    private static int curr = 0;
    private static int line = 1;
    private static int ch = 0;
    private static BufferedReader br;
    private static char currChar;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        String fileName = "";
        System.out.print("Enter the file name: ");
        fileName = scanner.nextLine();
        if (fileName.equalsIgnoreCase("quit") || fileName.equalsIgnoreCase("exit")) {
            System.out.println("Exitting...");
            return;
        }

        while (!fileName.equalsIgnoreCase("quit") || !fileName.equalsIgnoreCase("exit")) {

            try {
                File file = new File(fileName);
                FileReader fr = new FileReader(file);
                br = new BufferedReader(fr);
                
                while (curr != -1) {
                    System.out.println(position() + currentChar());
                }

            } catch (FileNotFoundException e) {
                System.out.println("file not found, check file name");
                break;
            }

            System.out.print("Enter the file name: ");
            fileName = scanner.nextLine();
            if (fileName.equalsIgnoreCase("quit") || fileName.equalsIgnoreCase("exit")) {
                System.out.println("Exitting...");
                return;
            }
        }
        scanner.close();
    }

    public static String position() {
        String pos = line + " : " + ch + " ";
        return pos;
    }

    public static void nextChar(BufferedReader br) {
        try {
            curr = br.read();
            if (curr == 13) {
                line++;
                ch = 0;
                System.out.println(line + " : " + ch + "");
                nextChar(br);

            } else {
                ch++;
            }
        } catch (IOException e) {
            System.out.println("invalid file input");
        }
    }

    public static char currentChar() {
        nextChar(br);
        currChar = (char) curr;
        return currChar;
    }
}

测试输入文本

Hello
COSC 455!

错误输出结果

Enter the file name: input.txt
1 : 1 H
1 : 2 e
1 : 3 l
1 : 4 l
1 : 5 o
2 : 0
1 : 6

2 : 1 C
2 : 2 O
2 : 3 S
2 : 4 C
2 : 5
2 : 6 4
2 : 7 5
2 : 8 5
2 : 9 !
3 : 0
2 : 10

3 : 1 ?

问题分析与修复

问题1:序号输出错误的根源及解决

  1. 错误原因:

    • nextChar()处理回车符(ASCII 13)时直接打印新行序号,后续currentChar()会再次调用nextChar(),同时position()输出的是更新前的字符序号,导致重复输出和序号混乱。
    • 只处理了Windows系统的回车符(CR=13),未处理Unix系统的换行符(LF=10),导致换行后的空字符被错误计数。
    • 字符序号ch的递增时机错误,不管是否是换行符都直接递增,导致换行后的空行被计为上一行的最后一个序号。
  2. 修复方案:

    • 移除nextChar()中的打印逻辑,统一由main循环处理输出,避免重复打印。
    • 同时处理CR(13)和LF(10):遇到CR时先读取后续的LF,再更新行号并重置ch为0;遇到LF时直接更新行号重置ch。
    • 调整ch的递增逻辑:只有当读取的字符不是换行符且不是文件结束符(-1)时,才递增ch。

问题2:末尾出现"?"的根源及解决

  • 错误原因:文件读取到末尾时,br.read()返回-1,代码依然将其强制转换为char,而(char)-1对应的Unicode字符就是?。
  • 修复方案:在currentChar()中判断curr是否为-1,此时返回空字符,后续main循环跳过输出;同时在main循环中提前判断curr是否为-1,避免处理文件结束符。

修复后的完整代码

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class FileReaderFixed {
    private static int curr;
    private static int line = 1;
    private static int ch = 0;
    private static BufferedReader br;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        String fileName = "";
        System.out.print("Enter the file name: ");
        fileName = scanner.nextLine();
        if (fileName.equalsIgnoreCase("quit") || fileName.equalsIgnoreCase("exit")) {
            System.out.println("Exitting...");
            return;
        }

        while (!fileName.equalsIgnoreCase("quit") && !fileName.equalsIgnoreCase("exit")) {
            try {
                File file = new File(fileName);
                FileReader fr = new FileReader(file);
                br = new BufferedReader(fr);
                // 重置状态变量,确保每次读新文件都是初始状态
                line = 1;
                ch = 0;
                curr = br.read();

                while (curr != -1) {
                    String pos = position();
                    char c = currentChar();
                    // 避免输出文件结束符的转换字符
                    if (curr != -1) {
                        System.out.println(pos + c);
                    }
                }

            } catch (FileNotFoundException e) {
                System.out.println("file not found, check file name");
                break;
            } catch (IOException e) {
                System.out.println("invalid file input");
            }

            System.out.print("Enter the file name: ");
            fileName = scanner.nextLine();
            if (fileName.equalsIgnoreCase("quit") || fileName.equalsIgnoreCase("exit")) {
                System.out.println("Exitting...");
                return;
            }
        }
        scanner.close();
    }

    public static String position() {
        return line + " : " + ch + " ";
    }

    public static void nextChar() throws IOException {
        curr = br.read();
        if (curr == 13) {
            // 处理Windows的CRLF,跳过后续的LF
            curr = br.read();
            line++;
            ch = 0;
        } else if (curr == 10) {
            // 处理Unix的LF
            line++;
            ch = 0;
        } else if (curr != -1) {
            // 不是换行符也不是文件结束,递增字符序号
            ch++;
        }
    }

    public static char currentChar() throws IOException {
        nextChar();
        if (curr == -1) {
            // 文件结束时返回空字符,后续main循环跳过输出
            return '\0';
        }
        return (char) curr;
    }
}

修复后的预期输出

Enter the file name: input.txt
1 : 1 H
1 : 2 e
1 : 3 l
1 : 4 l
1 : 5 o
2 : 0 

2 : 1 C
2 : 2 O
2 : 3 S
2 : 4 C
2 : 5  
2 : 6 4
2 : 7 5
2 : 8 5
2 : 9 !
3 : 0 

内容的提问来源于stack exchange,提问作者beatmaister

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:15:08