文章

Scanner 和 BufferedReader 的一些研究和思考

Scanner 和 BufferedReader 的一些研究和思考

Scanner 和 BufferedReader 的性能差距不必多说(详见文末)。不过在大部分题目中,IO 效率并不会成为瓶颈,关键还是算法本身。

尽管如此,我仍在尝试用 BufferedReader 平替 Scanner,下面是一些封装方案。

完整版


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class FastIO {
    private final BufferedReader br;
    private StringTokenizer st;

    FastIO() throws FileNotFoundException {
        File f = new File("src/luogu/basic/input/input.txt");
        InputStream in = f.exists() ? new FileInputStream(f) : System.in;
        br = new BufferedReader(new InputStreamReader(in));
    }

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            String line = br.readLine();
            if (line == null) return null;
            st = new StringTokenizer(line);
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    String nextLine() throws IOException {
        return br.readLine();
    }

    long nextLong() throws IOException {
        return Long.parseLong(next());
    }

    double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }
}

精简版


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class FastIO {
    BufferedReader br;
    StringTokenizer st;

    FastIO() {
        File f = new File("");
        InputStream in = f.exists() ? new FileInputStream(f) : System.in;
        br = new BufferedReader(new InputStreamReader(in));
    }

    String next() {
        while (st == null || !st.hasMoreTokens()) {
            String line = br.readLine();
            if (line == null) return null;
            st = new StringTokenizer(line);
        }
        return st.nextToken();
    }

    int nextInt() {
        return Integer.parseInt(next());
    }
}

这个版本适合赛前快速编写,异常签名可以交给 IDE 自动补全。像 nextLinenextLong 这些 API 在比赛中大概率用不到,可以先不写。

Scanner 配文件输入流


1
2
3
File f = new File("");//输入文件相对路径
InputStream in = f.exists() ? new FileInputStream(f) : System.in;
Scanner sc = new Scanner(in);

设计思路


为了保持代码最简洁,所以没有使用 try-catch。

关于输出优化:System.out.println 当然也可以用 BufferedWriter 优化,但在大部分情况下,使用 StringBuilder 在最后输出不会成为瓶颈,而且还多了一步 bw.flush(),所以不使用 BufferedWriter

关于 hasNext 方法:实现起来代码较长,而且在题目中大概率会给出 N,或者可以按照下面的方式处理:

1
2
3
4
while (true) {
    String s = io.next();
    if (s == null) break;
}

File 构造函数填入输入文件的相对路径,这样可以直接读取文件作为输入,为调试节省时间。

该模板是为竞赛定制的,实际项目中还是需要多一些异常检查。

参考资料


本文由作者按照 CC BY 4.0 进行授权