Kotlin中如何通过扩展方法为DataInputStream添加小端序读取方法?
如何在DataInputStream的Kotlin扩展函数中获取底层InputStream?
你的场景我很熟悉:原来通过继承DataInputStream实现小端序读取时,能直接持有底层输入流,但改成扩展函数后,因为DataInputStream继承的FilterInputStream里的in字段是protected的——只有子类能直接访问,扩展函数不属于子类范畴,所以拿不到这个字段。
下面给你两个可行的解决方案,你可以根据需求选择:
方案一:用反射获取底层InputStream(复用POI的LittleEndian工具)
我们可以通过反射拿到FilterInputStream里的in字段,这样就能在扩展函数里继续用你原来的LittleEndian逻辑。为了性能,我们提前初始化反射字段,避免每次调用都重复反射操作:
import java.io.DataInputStream import java.io.EOFException import java.io.InputStream import org.apache.poi.util.LittleEndian // 提前通过反射获取FilterInputStream的protected字段"in",并设置可访问 private val underlyingInputStreamField = Class.forName("java.io.FilterInputStream") .getDeclaredField("in") .apply { isAccessible = true } // 给DataInputStream加一个扩展工具方法,获取底层输入流 private fun DataInputStream.getUnderlyingStream(): InputStream { return underlyingInputStreamField.get(this) as InputStream } // 实现小端序读取的扩展函数 fun DataInputStream.readShortLittle(): Short { val inp = getUnderlyingStream() return try { LittleEndian.readShort(inp) } catch (e: LittleEndian.BufferUnderrunException) { throw EOFException() } } fun DataInputStream.readIntLittle(): Int { val inp = getUnderlyingStream() return try { LittleEndian.readInt(inp) } catch (e: LittleEndian.BufferUnderrunException) { throw EOFException() } } fun DataInputStream.readLongLittle(): Long { val inp = getUnderlyingStream() return try { LittleEndian.readLong(inp) } catch (e: LittleEndian.BufferUnderrunException) { throw EOFException() } } // 测试代码 fun main(args: Array<String>) { val inp = DataInputStream(System.`in`) while (true) { val i = try { inp.readIntLittle() } catch (e: EOFException) { break } println(i) } }
注意点:
- 反射依赖JDK的内部实现,虽然
FilterInputStream的in字段几乎不会变,但如果未来JDK版本有极端变更,可能需要调整。 - 我们把反射逻辑封装成私有扩展方法,让业务代码更整洁。
方案二:手动实现小端序读取(不依赖反射和POI工具)
如果你不想用反射,也可以直接用DataInputStream的read()方法手动拼出小端序的数值,这样代码更独立,兼容性也更好:
import java.io.DataInputStream import java.io.EOFException fun DataInputStream.readShortLittle(): Short { val byte1 = read() val byte2 = read() if (byte1 == -1 || byte2 == -1) throw EOFException() // 小端序是低字节在前,所以byte1是低位,byte2是高位 return ((byte2 shl 8) or (byte1 and 0xFF)).toShort() } fun DataInputStream.readIntLittle(): Int { val byte1 = read() val byte2 = read() val byte3 = read() val byte4 = read() if (byte1 == -1 || byte2 == -1 || byte3 == -1 || byte4 == -1) throw EOFException() return (byte4 shl 24) or (byte3 shl 16) or (byte2 shl 8) or (byte1 and 0xFF) } fun DataInputStream.readLongLittle(): Long { val bytes = mutableListOf<Int>() repeat(8) { val b = read() if (b == -1) throw EOFException() bytes.add(b) } // 小端序:第一个字节是最低位,最后一个是最高位 return (bytes[7].toLong() shl 56) or (bytes[6].toLong() shl 48) or (bytes[5].toLong() shl 40) or (bytes[4].toLong() shl 32) or (bytes[3].toLong() shl 24) or (bytes[2].toLong() shl 16) or (bytes[1].toLong() shl 8) or (bytes[0].toLong() and 0xFF) } // 测试代码 fun main(args: Array<String>) { val inp = DataInputStream(System.`in`) while (true) { val i = try { inp.readIntLittle() } catch (e: EOFException) { break } println(i) } }
优点:
- 完全不依赖外部工具类或反射,代码更稳定。
- 直接使用
DataInputStream的读取方法,和原有读取逻辑共享缓冲(比如底层是BufferedInputStream时,不会出现读取错位的问题)。
内容的提问来源于stack exchange,提问作者francesc
相关产品推荐
相关产品推荐

