【问题标题】:Reading a ByteArray from a FileSystem or a Jar in Kotlin在 Kotlin 中从文件系统或 Jar 中读取 ByteArray
【发布时间】:2019-02-17 17:39:21
【问题描述】:

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

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

无论是否抛出异常,都会正确关闭它。

这是返回 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
}

【问题讨论】:

  • 您好,我已经阅读了您的问题几次,但看不到您在问什么。你有什么问题?
  • @ErwinBolwidt 你是对的,我的问题不清楚。我想知道 Kotlin 正确关闭 InputStream 并处理文件不存在或抛出其他错误的可能性的方法。作为线索,似乎在 File.readBytes() 中使用 Kotlin 库函数 use() 解决了同样的问题。随后,我成功集成了这个use() 功能,并在下面发布了我的解决方案。可能还有其他关于从文件系统和我丢失的 Jar 中稳健读取的问题。所以我发布了我最好的想法并寻找任何改进。

标签: jar kotlin resources


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    我合并了 @gidds 的解决方案,以利用 Kotlin 库函数 Closeable.use() 作为通过 InputStream 从资源文件加载 ByteArray 操作的一部分.我是expecting use() 函数负责关闭InputStream 或处理是否抛出错误

    在更新的代码中,作为具体类型提供的调用 Class 给出了 resources 目录将包含文件的上下文。在多项目构建中,可能有多个 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")
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-12
      相关资源
      最近更新 更多