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

Kotlin竞技编程中如何让readln()从文件读取以复用代码?

Kotlin竞技编程:复用readln()实现控制台/文件输入切换

你需要在竞技编程中切换控制台输入和文件输入,同时避免重复编写业务代码,之前尝试的嵌套useWith方案无法正常运行,核心问题是嵌套的with会覆盖上下文——内层PrintWriter的上下文会替换外层的BufferedReader/Scanner,导致你调用的readLine()/nextInt()找不到对应方法。

下面提供两种实用解决方案:

方案1:重定向标准输入输出

直接修改System.in和System.out,让readln()和println()默认读写文件,业务代码无需任何改动:

import java.io.File
import java.io.PrintStream
import java.nio.file.Files

fun main() {
    // 保存原始控制台输入输出
    val originalIn = System.`in`
    val originalOut = System.out

    try {
        // 重定向输入到a.in,输出到a.out
        System.setIn(Files.newInputStream(File("a.in").toPath()))
        System.setOut(PrintStream(File("a.out")))

        // 业务代码和控制台版本完全一致
        val (a, b) = readln()!!.split(' ').map(String::toInt)
        println(a + b)
    } finally {
        // 恢复控制台输入输出
        System.setIn(originalIn)
        System.setOut(originalOut)
    }
}

这种方式的优势是完全复用原有控制台代码,不需要额外封装,适合快速切换场景。

方案2:封装IO上下文高阶函数

通过高阶函数封装输入输出流,在函数块内提供统一的读取/打印接口,业务代码保持一致:

针对BufferedReader的版本

import java.io.BufferedReader
import java.io.File
import java.io.PrintWriter
import java.io.Reader
import java.io.Writer

fun runWithIO(
    input: Reader = BufferedReader(System.`in`.reader()),
    output: Writer = PrintWriter(System.out)
) {
    input.use { reader ->
        output.use { writer ->
            // 定义块内专属的readln和println
            fun readln(): String? = (reader as BufferedReader).readLine()
            fun println(s: Any?) = writer.apply { write("$s\n"); flush() }

            // 业务代码
            val (a, b) = readln()!!.split(' ').map(String::toInt)
            println(a + b)
        }
    }
}

fun main() {
    // 从文件读写
    runWithIO(
        input = File("a.in").bufferedReader(),
        output = File("a.out").printWriter()
    )

    // 默认使用控制台读写
    runWithIO()
}

针对Scanner的版本

如果习惯用Scanner处理输入,可以封装对应版本:

import java.io.File
import java.io.PrintWriter
import java.util.Scanner

fun runWithScanner(
    input: Scanner = Scanner(System.`in`),
    output: PrintWriter = PrintWriter(System.out)
) {
    input.use { scanner ->
        output.use { writer ->
            // 定义块内专属的读取和打印方法
            fun nextInt(): Int = scanner.nextInt()
            fun println(s: Any?) = writer.apply { write("$s\n"); flush() }

            // 业务代码
            val a = nextInt()
            val b = nextInt()
            println(a + b)
        }
    }
}

fun main() {
    // 从文件读写
    runWithScanner(
        input = Scanner(File("b.in")),
        output = PrintWriter(File("b.out"))
    )
}

这种方式的优势是隔离了IO实现,业务代码完全与输入输出源无关,适合需要频繁切换场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:40:21