在 Kotlin 中将大型 Inputstream 写入文件

47

我从REST Web服务收到了一大段文本流,想直接将其写入文件。有什么最简单的方法吗?

我已经编写了下面这个函数扩展,它是可以工作的。但我觉得肯定有更简洁的方法。

注意:我希望使用try-with-resources自动关闭流和文件。

fun File.copyInputStreamToFile(inputStream: InputStream) {
    val buffer = ByteArray(1024)

    inputStream.use { input ->
        this.outputStream().use { fileOut ->

            while (true) {
                val length = input.read(buffer)
                if (length <= 0)
                    break
                fileOut.write(buffer, 0, length)
            }
            fileOut.flush()
        }
    }
}
5个回答

105

您可以使用copyTo函数简化您的函数:

fun File.copyInputStreamToFile(inputStream: InputStream) {
    this.outputStream().use { fileOut ->
        inputStream.copyTo(fileOut)
    }
}

6
外部的 use 看起来像是一个错误。你正在不同于打开 inputStream 的作用域中关闭/释放资源。 - Andre Artus
2
而要执行相反的操作(从文件写入到某个输出流),我使用以下代码:FileInputStream(someFile).use { stream -> stream.copyTo(someOutputStream) },对吗? - android developer
2
安德烈的评论已不再相关,因为答案已被编辑。 - Hack5

17

我的建议是:

fun InputStream.toFile(path: String) {
    File(path).outputStream().use { this.copyTo(it) }
}

没有关闭当前流

InputStream.toFile("/path/filename")

同时,不要忘记处理异常情况,例如如果被拒绝写入权限 :)


10

我建议这样做:

fun InputStream.toFile(path: String) {
    use { input ->
        File(path).outputStream().use { input.copyTo(it) }
    }
}

然后像这样使用:

InputStream.toFile("/some_path_to_file")

你应该总是在打开的范围内关闭。这很可能是 copyTo 不会自动关闭资源的原因。 - Andre Artus

0
你需要这样做。
@Throws
fun copyDataBase() {

        var myInput = context.getAssets().open(DB_NAME)
        var outFileName = DB_PATH + DB_NAME
        var fileOut: OutputStream = FileOutputStream(outFileName)
        val buffer: ByteArray = ByteArray(1024)
        var length: Int? = 0

        while (true) {
            length = myInput.read(buffer)
            if (length <= 0)
                break
            fileOut.write(buffer, 0, length)
        }

        fileOut.flush()
        fileOut.close()
        myInput.close()

        throw IOException()
}

1
那个缓冲区大小可能有点太小了。通常使用8192到32768字节之间的某些值。例如,Kotlin自己的InputStream#copyTo使用8192 B作为默认值,而Go的copy使用32768(无法更改)。来源:https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-input-stream/copy-to.html 来源:https://golang.org/src/io/io.go?s=11569:11629#L389 - user7610
不必要调用.flush()然后调用close()。 - Jorgesys

-1

对我而言似乎有效的是这个:

fun fileCopyer(localFileA: File, localFileB: File) {
var output = localFileA.inputStream()
output.copyTo(localFileB.outputStream())
output.close()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接