java inputstream转outputstream_如何将OutputStream转换为InputStream?

从我的角度来看,java.io.PipedInputStream / java.io.PipedOutputStream是考虑的最佳选择。 在某些情况下,您可能希望使用ByteArrayInputStream / ByteArrayOutputStream。 问题是您需要复制缓冲区以将ByteArrayOutputStream转换为ByteArrayInputStream。 ByteArrayOutpuStream / ByteArrayInputStream也限制为2GB。 这是我编写的OutpuStream / InputStream实现,它绕过了ByteArrayOutputStream / ByteArrayInputStream限制(Scala代码,但对java开发人员来说很容易理解):

import java.io.{IOException, InputStream, OutputStream}

import scala.annotation.tailrec

/** Acts as a replacement for ByteArrayOutputStream

*

*/

class HugeMemoryOutputStream(capacity: Long) extends OutputStream {

private val PAGE_SIZE: Int = 1024000

private val ALLOC_STEP: Int = 1024

/** Pages array

*

*/

private var streamBuffers: Array[Array[Byte]] = Array.empty[Array[Byte]]

/** Allocated pages count

*

*/

private var pageCount: Int = 0

/** Allocated bytes count

*

*/

private var allocatedBytes: Long = 0

/** Current position in stream

*

*/

private var position: Long = 0

/** Stream length

*

*/

private var length: Long = 0

allocSpaceIfNeeded(capacity)

/** Gets page count based on given length

*

* @param length Buffer length

* @return Page count to hold the specified amount of data

*/

private def getPageCount(length: Long) = {

var pageCount = (length / PAGE_SIZE).toInt + 1

if ((length % PAGE_SIZE) == 0) {

pageCount -= 1

}

pageCount

}

/** Extends pages array

*

*/

private def extendPages(): Unit = {

if (streamBuffers.isEmpty) {

streamBuffers = new Array[Array[Byte]](ALLOC_STEP)

}

else {

val newStreamBuffers = new Array[Array[Byte]](streamBuffers.length + ALLOC_STEP)

Array.copy(streamBuffers, 0, newStreamBuffers, 0, streamBuffers.length)

streamBuffers = newStreamBuffers

}

pageCount = streamBuffers.length

}

/** Ensures buffers are bug enough to hold specified amount of data

*

* @param value Amount of data

*/

private def allocSpaceIfNeeded(value: Long): Unit = {

@tailrec

def allocSpaceIfNeededIter(value: Long): Unit = {

val currentPageCount = getPageCount(allocatedBytes)

val neededPageCount = getPageCount(value)

if (currentPageCount < neededPageCount) {

if (currentPageCount == pageCount) extendPages()

streamBuffers(currentPageCount) = new Array[Byte](PAGE_SIZE)

allocatedBytes = (currentPageCount + 1).toLong * PAGE_SIZE

allocSpaceIfNeededIter(value)

}

}

if (value < 0) throw new Error("AllocSpaceIfNeeded < 0")

if (value > 0) {

allocSpaceIfNeededIter(value)

length = Math.max(value, length)

if (position > length) position = length

}

}

/**

* Writes the specified byte to this output stream. The general

* contract for write is that one byte is written

* to the output stream. The byte to be written is the eight

* low-order bits of the argument b. The 24

* high-order bits of b are ignored.

*

* Subclasses of OutputStream must provide an

* implementation for this method.

*

* @param b the byte.

*/

@throws[IOException]

override def write(b: Int): Unit = {

val buffer: Array[Byte] = new Array[Byte](1)

buffer(0) = b.toByte

write(buffer)

}

/**

* Writes len bytes from the specified byte array

* starting at offset off to this output stream.

* The general contract for write(b, off, len) is that

* some of the bytes in the array b are written to the

* output stream in order; element b[off] is the first

* byte written and b[off+len-1] is the last byte written

* by this operation.

*

* The write method of OutputStream calls

* the write method of one argument on each of the bytes to be

* written out. Subclasses are encouraged to override this method and

* provide a more efficient implementation.

*

* If b is null, a

* NullPointerException is thrown.

*

* If off is negative, or len is negative, or

* off+len is greater than the length of the array

* b, then an IndexOutOfBoundsException is thrown.

*

* @param b the data.

* @param off the start offset in the data.

* @param len the number of bytes to write.

*/

@throws[IOException]

override def write(b: Array[Byte], off: Int, len: Int): Unit = {

@tailrec

def writeIter(b: Array[Byte], off: Int, len: Int): Unit = {

val currentPage: Int = (position / PAGE_SIZE).toInt

val currentOffset: Int = (position % PAGE_SIZE).toInt

if (len != 0) {

val currentLength: Int = Math.min(PAGE_SIZE - currentOffset, len)

Array.copy(b, off, streamBuffers(currentPage), currentOffset, currentLength)

position += currentLength

writeIter(b, off + currentLength, len - currentLength)

}

}

allocSpaceIfNeeded(position + len)

writeIter(b, off, len)

}

/** Gets an InputStream that points to HugeMemoryOutputStream buffer

*

* @return InputStream

*/

def asInputStream(): InputStream = {

new HugeMemoryInputStream(streamBuffers, length)

}

private class HugeMemoryInputStream(streamBuffers: Array[Array[Byte]], val length: Long) extends InputStream {

/** Current position in stream

*

*/

private var position: Long = 0

/**

* Reads the next byte of data from the input stream. The value byte is

* returned as an int in the range 0 to

* 255. If no byte is available because the end of the stream

* has been reached, the value -1 is returned. This method

* blocks until input data is available, the end of the stream is detected,

* or an exception is thrown.

*

*

A subclass must provide an implementation of this method.

*

* @return the next byte of data, or -1 if the end of the

* stream is reached.

*/

@throws[IOException]

def read: Int = {

val buffer: Array[Byte] = new Array[Byte](1)

if (read(buffer) == 0) throw new Error("End of stream")

else buffer(0)

}

/**

* Reads up to len bytes of data from the input stream into

* an array of bytes. An attempt is made to read as many as

* len bytes, but a smaller number may be read.

* The number of bytes actually read is returned as an integer.

*

*

This method blocks until input data is available, end of file is

* detected, or an exception is thrown.

*

*

If len is zero, then no bytes are read and

* 0 is returned; otherwise, there is an attempt to read at

* least one byte. If no byte is available because the stream is at end of

* file, the value -1 is returned; otherwise, at least one

* byte is read and stored into b.

*

*

The first byte read is stored into element b[off], the

* next one into b[off+1], and so on. The number of bytes read

* is, at most, equal to len. Let k be the number of

* bytes actually read; these bytes will be stored in elements

* b[off] through b[off+k-1],

* leaving elements b[off+k] through

* b[off+len-1] unaffected.

*

*

In every case, elements b[0] through

* b[off] and elements b[off+len] through

* b[b.length-1] are unaffected.

*

*

The read(b, off, len) method

* for class InputStream simply calls the method

* read() repeatedly. If the first such call results in an

* IOException, that exception is returned from the call to

* the read(b, off, len) method. If

* any subsequent call to read() results in a

* IOException, the exception is caught and treated as if it

* were end of file; the bytes read up to that point are stored into

* b and the number of bytes read before the exception

* occurred is returned. The default implementation of this method blocks

* until the requested amount of input data len has been read,

* end of file is detected, or an exception is thrown. Subclasses are encouraged

* to provide a more efficient implementation of this method.

*

* @param b the buffer into which the data is read.

* @param off the start offset in array b

* at which the data is written.

* @param len the maximum number of bytes to read.

* @return the total number of bytes read into the buffer, or

* -1 if there is no more data because the end of

* the stream has been reached.

* @see java.io.InputStream#read()

*/

@throws[IOException]

override def read(b: Array[Byte], off: Int, len: Int): Int = {

@tailrec

def readIter(acc: Int, b: Array[Byte], off: Int, len: Int): Int = {

val currentPage: Int = (position / PAGE_SIZE).toInt

val currentOffset: Int = (position % PAGE_SIZE).toInt

val count: Int = Math.min(len, length - position).toInt

if (count == 0 || position >= length) acc

else {

val currentLength = Math.min(PAGE_SIZE - currentOffset, count)

Array.copy(streamBuffers(currentPage), currentOffset, b, off, currentLength)

position += currentLength

readIter(acc + currentLength, b, off + currentLength, len - currentLength)

}

}

readIter(0, b, off, len)

}

/**

* Skips over and discards n bytes of data from this input

* stream. The skip method may, for a variety of reasons, end

* up skipping over some smaller number of bytes, possibly 0.

* This may result from any of a number of conditions; reaching end of file

* before n bytes have been skipped is only one possibility.

* The actual number of bytes skipped is returned. If n is

* negative, the skip method for class InputStream always

* returns 0, and no bytes are skipped. Subclasses may handle the negative

* value differently.

*

* The skip method of this class creates a

* byte array and then repeatedly reads into it until n bytes

* have been read or the end of the stream has been reached. Subclasses are

* encouraged to provide a more efficient implementation of this method.

* For instance, the implementation may depend on the ability to seek.

*

* @param n the number of bytes to be skipped.

* @return the actual number of bytes skipped.

*/

@throws[IOException]

override def skip(n: Long): Long = {

if (n < 0) 0

else {

position = Math.min(position + n, length)

length - position

}

}

}

}

易于使用,没有缓冲区重复,没有2GB内存限制

val out: HugeMemoryOutputStream = new HugeMemoryOutputStream(initialCapacity /*may be 0*/)

out.write(...)

...

val in1: InputStream = out.asInputStream()

in1.read(...)

...

val in2: InputStream = out.asInputStream()

in2.read(...)

...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将 JavaInputStream 转换OutputStream,您可以使用以下方法之一: 1. 使用 `java.io.BufferedInputStream` 和 `java.io.BufferedOutputStream` 缓冲流。这两个类都实现了 `InputStream` 和 `OutputStream` 接口,因此可以很容易地将它们相互转换。例如: ``` InputStream inputStream = ...; OutputStream outputStream = ...; try (BufferedInputStream bis = new BufferedInputStream(inputStream); BufferedOutputStream bos = new BufferedOutputStream(outputStream)) { int data; while ((data = bis.read()) != -1) { bos.write(data); } } ``` 2. 使用 `java.io.InputStreamReader` 和 `java.io.OutputStreamWriter` 字符流。这两个类都实现了 `Reader` 和 `Writer` 接口,并可以将字节流转换为字符流。例如: ``` InputStream inputStream = ...; OutputStream outputStream = ...; try (InputStreamReader isr = new InputStreamReader(inputStream, StandardCharsets.UTF_8); OutputStreamWriter osw = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { int data; while ((data = isr.read()) != -1) { osw.write(data); } } ``` 3. 使用 `java.nio.channels.Channels` 类的 `newChannel` 方法。这个方法可以将字节流包装在 `ReadableByteChannel` 或 `WritableByteChannel` 中,这些类均实现了 `Channel` 接口。例如: ``` InputStream inputStream = ...; OutputStream outputStream = ...; ReadableByteChannel inputChannel = Channels.newChannel(inputStream); WritableByteChannel outputChannel = Channels.newChannel(outputStream); ByteBuffer buffer = ByteBuffer.allocate(1024); while (inputChannel.read(buffer) != -1) { buffer.flip(); outputChannel.write(buffer); buffer.clear(); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值