Kotlin에서 InputStream의 전체 콘텐츠를 문자열로 읽으려면 어떻게해야하나요?


105

최근 InputStream에 Kotlin에서 의 전체 내용을 문자열로 읽는 코드를 보았습니다 .

// input is of type InputStream
val baos = ByteArrayOutputStream()
input.use { it.copyTo(baos) }
val inputAsString = baos.toString()

그리고 또한:

val reader = BufferedReader(InputStreamReader(input))
try {
    val results = StringBuilder()
    while (true) { 
        val line = reader.readLine()
        if (line == null) break
        results.append(line) 
    }
    val inputAsString = results.toString()
} finally {
    reader.close()
}

그리고 이것은 자동으로 닫히기 때문에 더 부드럽게 보입니다 InputStream.

val inputString = BufferedReader(InputStreamReader(input)).useLines { lines ->
    val results = StringBuilder()
    lines.forEach { results.append(it) }
    results.toString()
}

또는 약간의 변형 :

val results = StringBuilder()
BufferedReader(InputStreamReader(input)).forEachLine { results.append(it) }
val resultsAsString = results.toString()   

그런 다음이 기능적 폴드 물건 :

val inputString = input.bufferedReader().useLines { lines ->
    lines.fold(StringBuilder()) { buff, line -> buff.append(line) }.toString()
}

또는 다음을 닫지 않는 잘못된 변형 InputStream:

val inputString = BufferedReader(InputStreamReader(input))
        .lineSequence()
        .fold(StringBuilder()) { buff, line -> buff.append(line) }
        .toString()

그러나 그들은 모두 투박하고 나는 동일한 버전의 새롭고 다른 버전을 계속 찾고 있습니다 ... 그리고 그들 중 일부는 InputStream. 을 읽는 비 투잡 한 (관용적) 방법은 InputStream무엇입니까?

참고 : 이 질문은 작성자 ( Self-Answered Questions ) 가 의도적으로 작성하고 답변 하므로 일반적으로 묻는 Kotlin 주제에 대한 관용적 답변이 SO에 있습니다.

답변:


217

Kotlin에는 이러한 목적을위한 특정 확장 기능이 있습니다.

가장 간단한 방법 :

val inputAsString = input.bufferedReader().use { it.readText() }  // defaults to UTF-8

그리고이 예제에서 당신은 사이에 결정할 수 bufferedReader()하거나 reader(). 함수 호출 Closeable.use()은 람다 실행이 끝날 때 입력을 자동으로 닫습니다.

추가 읽기 :

이런 종류의 일을 많이하면 확장 함수로 작성할 수 있습니다.

fun InputStream.readTextAndClose(charset: Charset = Charsets.UTF_8): String {
    return this.bufferedReader(charset).use { it.readText() }
}

그러면 다음과 같이 쉽게 호출 할 수 있습니다.

val inputAsString = input.readTextAndClose()  // defaults to UTF-8

참고로 charset이미를 알아야하는 모든 Kotlin 확장 기능은 기본값이 UTF-8이므로 다른 인코딩이 필요한 경우 호출에서 reader(charset)또는에 대한 인코딩을 포함하도록 위 코드를 조정해야합니다 bufferedReader(charset).

경고 : 더 짧은 예가 표시 될 수 있습니다.

val inputAsString = input.reader().readText() 

그러나 이것은 스트림을 닫지 않습니다 . 사용하는 모든 IO 함수에 대한 API 문서를 확인하여 닫히는 것과 닫히지 않는 것을 확인하십시오. 일반적으로 단어 use(예 : useLines()또는 use()) 를 포함하면 이후 스트림을 닫습니다. 예외는 전자는 아무것도 열어 두지 않고 후자는 실제로 명시적인 닫기를 요구 한다는 File.readText()점에서 다릅니다 Reader.readText().

참조 : Kotlin IO 관련 확장 함수


1
나는 "readText"가 당신이 제안하는 확장 기능에 대해 "useText"보다 더 나은 이름이라고 생각한다. "useText"를 읽을 때 "사용되는"항목에 대해 블록 함수를 실행 use하거나 같은 함수를 기대합니다 useLines. 예를 들어 inputStream.useText { text -> ... }"readText"를 읽을 때 텍스트를 반환하는 함수를 기대합니다 val inputAsString = inputStream.readText()..
mfulton26

사실이지만 readText는 이미 잘못된 의미를 가지고 있으므로 use그 점 에서 함수 와 비슷하다는 것을 의미하고 싶었습니다 . 적어도이 Q & A의 맥락에서. 어쩌면 새로운 동사는 ... 찾을 수 있습니다
제이슨 Minard

3
@ mfulton26 나는 닫지 않는 패턴과 람다를 원하는 패턴 과의 readTextAndClose()충돌을 피하기 위해이 예제를 사용했습니다. 미래 노동을 절약하기위한 확장. readText()use
Jayson Minard

@JaysonMinard 왜 이것을 대답으로 표시하지 않습니까? 그것은 :-) 좋은 생각을의
piotrek1543

2

InputStream의 내용을 String으로 읽는 예제

import java.io.File
import java.io.InputStream
import java.nio.charset.Charset

fun main(args: Array<String>) {
    val file = File("input"+File.separator+"contents.txt")
    var ins:InputStream = file.inputStream()
    var content = ins.readBytes().toString(Charset.defaultCharset())
    println(content)
}

참고 용 -Kotlin 읽기 파일


1
귀하의 예제에는 결함이 있습니다. 1) 크로스 플랫폼 경로의 경우 Paths.get()method 를 사용해야합니다 . 2) 스트림 용 - 시도 - 자원 기능 (에 코 틀린 : .use {})
에브 게니 레베 데프
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.