簡體   English   中英

為什么我的 `InputStream` 實現不能與 `com.monitorjbl:xlsx-streamer:2.2.0` 中的 `StreamingReader` 一起工作

[英]Why my implementation of `InputStream` not working with `StreamingReader` from `com.monitorjbl:xlsx-streamer:2.2.0`

由於圖書館的 GitHub 網站沒有活動,我決定在這里放棄這個問題,希望得到任何支持。

我正在處理的問題是以流方式讀取 Excel 文件。 特別地,Excel 文件在使用一定的塊大小拆分為多行后,作為 blob 存儲在 SQLite 數據庫中。 例如,一個 3MB 的文件被分成三行,每行包含 1MB 的原始數據。 行按屬性排序,因此如果我 pipe 按順序將每行的 blob 列輸出到文件系統,我可以獲得 Excel 文件的副本。

由於StreamingReaderInputStream一起使用,我決定在 SQLite 數據庫中的這些行之上實現一個InputStream ,以便StreamingReader直接從數據庫中讀取數據。

我首先在查詢結果之上構造一個Sequence<Byte> ,對所有 blob 列中的字節進行排序:

    fun blocksByteSequence(id: String): Sequence<Byte> {
        return sequence {
            val conn = source.connection
            val stmt = conn.createStatement()
            val r = stmt.executeQuery(findFileQuery(id))
            while (r.next()) yieldAll(r.getBytes(raw_data_column).asIterable())
            stmt.close()
            conn.close()
        }
    }

然后將Sequence<Byte>轉換為InputStream相當簡單:

class ByteSequenceInputStreamFactory(
    private val seq: Sequence<Byte>,
) {
    fun inputStreamProvider(): InputStream = object : InputStream() {
        private val iter = seq.iterator()
        override fun read(): Int {
            return if (iter.hasNext()) iter.next().toInt() else -1
        }
    }
}

當我嘗試使用這樣的InputStream構造StreamingReader時出現錯誤:

val byteSeq = blocksByteSequence(id)
val ins = ByteSequenceInputStreamFactory(byteSeq).inputStreamProvider()
val reader = StreamingReader.builder().open(ins) // error

錯誤信息:

Could not open the specified zip entry source stream
org.apache.poi.openxml4j.exceptions.InvalidOperationException: Could not open the specified zip entry source stream
    at app//org.apache.poi.openxml4j.opc.ZipPackage.openZipEntrySourceStream(ZipPackage.java:212)
    at app//org.apache.poi.openxml4j.opc.ZipPackage.openZipEntrySourceStream(ZipPackage.java:194)
    ...
Caused by: java.util.zip.ZipException: invalid distances set
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.readFromInflater(ZipArchiveInputStream.java:586)
    at org.apache.commons.compress.archivers.zip.ZipArchiveInputStream.readDeflated(ZipArchiveInputStream.java:551)
   ...
Caused by: java.util.zip.DataFormatException: invalid distances set
    at java.base/java.util.zip.Inflater.inflateBytesBytes(Native Method)
    at java.base/java.util.zip.Inflater.inflate(Inflater.java:378)
   ...

但是,如果我將 SQLite 中的所有字節轉儲到某個路徑的 Excel 文件中:

val byteSeq = manager.blocksByteSequence(id)
val out = java.nio.file.Path.of("./private/test.xlsx")
out.outputStream().use { o -> byteSeq.forEach {  o.write(it.toInt()) } }

並使用該文件生成的InputStream ,錯誤消失了。

val reader = StreamingReader.builder().open(out.inputStream())

我想我解決了這個問題。

麻煩就在這里

class ByteSequenceInputStreamFactory(
    private val seq: Sequence<Byte>,
) {
    fun inputStreamProvider(): InputStream = object : InputStream() {
        private val iter = seq.iterator()
        override fun read(): Int {
            return if (iter.hasNext()) iter.next().toInt() /* this is not OK */  else -1
        }
    }
}

方法Byte.intoInt()的調用沒有InputStream預期的預期結果。

根據 Java Doc,方法InputStream.read()

從輸入 stream 讀取下一個數據字節。值字節作為0 到 255 范圍內的 int返回。 如果由於已到達 stream 的末尾而沒有可用字節,則返回值 -1。 此方法會阻塞,直到輸入數據可用、檢測到 stream 結束或拋出異常為止。

棘手的部分是,從Byte.toInt()返回的Int不是0 到 255 范圍內的 int

在 kotlin 中,一個Byte

表示一個 8 位簽名的 integer 在 JVM 上,此類型的不可空值表示為原始類型字節的值。

Byte.toInt()方法:

將此 Byte 值轉換為 Int。 生成的 Int 值表示與此 Byte 相同的數值。 結果 Int 值的最低有效 8 位與此 Byte 值的位相同,而最高有效 24 位填充此值的符號位

簡單地調用Byte.toInt()將返回此Byte下的簽名integer。 要獲得它的0-255表示,我需要通過執行以下操作來提取租賃的 8 位有效位:

val the_0_255_int = someByte.toInt().and(0xff) // extract the last 8 bits

所以我的問題的正確代碼如下所示:

class ByteSequenceInputStreamFactory(
    private val seq: Sequence<Byte>,
) {
    fun inputStreamProvider(): InputStream = object : InputStream() {
        private val iter = seq.iterator()
        override fun read(): Int {
            return if (iter.hasNext()) iter.next().toInt().and(0xff)  else -1
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM