在 Kotlin 中从文件系统或 Jar 中读取 ByteArray

Reading a ByteArray from a FileSystem or a Jar in Kotlin

我经常在 IDE 中开发应用程序,然后使用可执行 JAR 分发它们。所以我在库函数方面寻求互操作性。我有一个部分解决方案,使用 InputStream 从位于 FileSystem 或 Jar 文件中的文件稳健地读取数据,但我想利用强大的 Kotlin 函数 Closable.use() 来适应是否抛出错误。

经过一番努力,我发现这个 post 解释了 Jar 文件内部的压缩如何使其访问不同于文件系统的访问。特别是漂亮的 Kotlin 扩展函数 File.readBytes() 不适用于 Jar 中的文件。这是一种耻辱,因为查看 readBytes() 的源代码可以巧妙地使用 use() 函数来处理流突发事件。它说...

closes it down correctly whether an exception is thrown or not.

这里是 returns 一个 ByteArray 的部分解决方案。无论 运行 来自 IDE 内的应用程序还是来自可执行 Jar.

的应用程序,这些功能都相同
inline fun <reified T> getResourceAsStream(filename:String):InputStream {
  //it is calling function's responsibility to close the stream
  //force the first character to be a backslash that indicates root
  val fnameWithPath= if (filename[0] != '/') "/$filename" else filename
  //extract the stream if it exists
  return T::class.java.getResourceAsStream(fnameWithPath)
}
inline fun <reified T> getResourceByteArray(filename:String):ByteArray {
  //will open a stream, read bytes and then close stream
  val stream= getResourceAsStream<T>(filename)
  val byteArray = stream.readBytes()
  stream.close()
  return byteArray
}

我合并了@gidds 的解决方案以利用 Kotlin 库函数 Closeable.use() as part of the operation to load the ByteArray from a resource file through an InputStream. I'm expecting use() 函数来处理关闭 InputStream 或其他处理 是否抛出错误

在更新的代码中,作为具体化类型提供的调用 Classresources 目录提供了上下文包含文件。在多项目构建中,可能有多个 resources 目录。我正在处理需要不同输入数据的不同项目。

inline fun <reified T> getResourceAsStream(filename:String):InputStream {
  //it is calling function's responsibility to close the stream
  //force the first character to be a backslash that indicates root
  val fnameWithPath= if (filename[0] != '/') "/$filename" else filename
  //extract the stream if it exists
  return T::class.java.getResourceAsStream(fnameWithPath)
}

inline fun <reified T> getResourceByteArray(filename: String)
= getResourceAsStream<T>(filename).use{ it.readBytes() }

class ReadByteData() {
  init{
    val byteArray= getResourceByteArray<ReadByteData>("fileName")
  }
}

你快到了。您可能错过的是,Kotlin 已经在 InputStream 实现的 Closable 接口上定义了一个扩展方法 use()。所以你的第二种方法可以改写为一行:

inline fun <reified T> getResourceByteArray(filename: String)
    = getResourceAsStream<T>(filename).use{ it.readBytes() }