Kotlin и Gradle — чтение из stdio

Я пытаюсь выполнить свой класс Kotlin с помощью команды:

./gradlew -q run < src/main/kotlin/samples/input.txt

Вот мой класс HelloWorld.kt:

package samples

fun main(args: Array<String>) {

    println("Hello, world!")

    val lineRead = readLine()
    println(lineRead)
}

Вот мой build.gradle.kts:

plugins {
    kotlin("jvm")
    application
}

application {
    mainClassName = "samples.HelloWorldKt"
}

dependencies {
    compile(kotlin("stdlib"))
}

repositories {
    jcenter()
}

Код выполняется, но данные, содержащиеся в файле input.txt, не отображаются. Вот что я получаю:

Hello, world!
null

Я хочу иметь возможность выполнить приведенную выше команду gradlew, а поток input.txt перенаправить на stdio. Я могу легко сделать это на C++. Как только я скомпилирую свой файл .cpp, я могу запустить:

./my_code < input.txt

и он выполняется, как ожидалось.

Как я могу добиться того же самого с Kotlin и Gradle?

Обновление: на основе этот ответ, я пытался добавить это в build.gradle.kts, но это недопустимый синтаксис:

введите описание изображения здесь


person Bitcoin Cash - ADA enthusiast    schedule 18.08.2017    source источник
comment
@CodeConfident Да, я уверен. Моя проблема похожа на этот вопрос: discuss.gradle.org/t/   -  person Bitcoin Cash - ADA enthusiast    schedule 18.08.2017
comment
Извините... Я уже удалил свой комментарий. Когда я перечитал это, это просто потеряло смысл.   -  person charles-allen    schedule 18.08.2017
comment
Эта ссылка выглядит как разумный ответ. Вы пытались добавить run { standardInput = System.in } в свой build.gradle.kts? То же предложение здесь: discuss.gradle.org/t/   -  person charles-allen    schedule 18.08.2017
comment
почему build.gradle.kts, а не только build.gradle?   -  person Thufir    schedule 05.11.2017


Ответы (2)


Предложение AjahnCharles о run { standardInput = System.in } верное, но для переноса его на kotlin-dsl вам нужен другой синтаксис. run в этом случае — это имя задачи, и вы настраиваете существующую задачу плагина application. Чтобы настроить существующую задачу в kotlin-dsl, вы должны использовать один из следующих способов:

val run by tasks.getting(JavaExec::class) {
    standardInput = System.`in`
}

or

val run: JavaExec by tasks
run.standardInput = System.`in`

Предстоящая версия Gradle 4.3 должна предоставлять API для авторов плагинов для чтения пользовательского ввода.

Причина разницы между Groovy и Kotlin в этом случае в том, что Groovy использует динамические типы, а в Kotlin вы должны указать тип задачи для автодополнения и просто для компиляции скрипта конфигурации

person gildor    schedule 10.10.2017
comment
Для справки: docs.gradle.org/current/userguide/ - person fahrradflucht; 22.12.2019

Почти, но это не работает :'(

Теоретически

Насколько я понимаю: < input.txt устанавливает стандартный ввод для процесса gradlew, но по умолчанию он не перенаправляется в вашу программу.

Вы хотите добавить это в свой build.gradle.kts:

run {
    standardInput = System.`in`
}

Источники:
https://discuss.gradle.org/t/why-doesnt-system-in-read-block-when-im-using-gradle/3308/2< br> https://discuss.gradle.org/t/how-can-i-execute-a-java-application-that-asks-for-user-input/3264


На практике

Для меня эти конфигурации сборки выглядят примерно одинаково, но Groovy работает, а Kotlin — нет. Я начинаю думать, что Gradle Kotlin DSL еще не поддерживает термин standardInput:/

Gradle в Kotlin и Gradle в Groovy

Вот моя рабочая версия Groovy, если это поможет:

apply plugin: 'kotlin'
apply plugin: 'application'

buildscript {
    ext.kotlin_version = '1.1.4'

    repositories {
        jcenter()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

repositories {
    jcenter()
}

dependencies {
    // api => exported to consumers (found on their compile classpath)
    // implementation => used internally (not exposed to consumers)
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

mainClassName = "samples.HelloWorldKt"

run {
    standardInput = System.in
}
person charles-allen    schedule 18.08.2017
comment
Я уже пробовал это. Но код не компилируется. Я прикрепил скриншот к вопросу. - person Bitcoin Cash - ADA enthusiast; 18.08.2017
comment
Я (наконец) воссоздал проблему. Я сделал как Kotlin build.gradle.kts, так и стандартный build.gradle. Последний работает при условии, что run { ... } установлен. Это заставляет меня думать, что проблема заключается в импорте соответствующего пакета Java в скрипт сборки Kotlin (думаю, Groovy делает это автоматически). Почти готово... ^^ - person charles-allen; 18.08.2017
comment
@Tiago - боюсь, несмотря на то, что он работает с Intellij, командной строкой kotlin и gradle-groovy, я не могу понять, как заставить его работать с gradle-kotlin , хотя, судя по снимку экрана выше, вы, вероятно, можете сказать, что у меня больше проблем, чем у вас! Я надеюсь, вы найдете ответ; это кажется довольно полезной вещью, которую можно сделать. - person charles-allen; 18.08.2017
comment
Да, я тоже потратил несколько часов на это. Но хорошо знать, что версия Groovy работает. Тогда я мог бы придерживаться этого решения. Большое спасибо, что помогли мне разобраться в этом! - person Bitcoin Cash - ADA enthusiast; 18.08.2017
comment
@Tiago - Честно говоря, для меня это была действительно хорошая практика. Хорошо, когда есть задача стимулировать обучение ^^. Я бы оставил вопрос открытым, чтобы посмотреть, получите ли вы лучший ответ позже. Буду следить обязательно! - person charles-allen; 18.08.2017
comment
run {} исходит из kotlin-stdlib и не ссылается на задачу run. tasks.getByName<JavaExec>() { standardInput = System.in } должен сделать - person eskatos; 24.09.2018
comment
Предложение @eskatos работает для меня с одной небольшой поправкой: tasks.withType<JavaExec>() { standardInput = System.`in` } - person Bruce Hamilton; 16.07.2021