Skip to content

Commit 1c80d32

Browse files
committed
Add optimized DataBufferInputStream overrides
Add optimized DataBufferInputStream overrides for readNBytes, skip, and transferTo; all of them allocate byte buffers which we can either avoid (in the case of skip) or size more precisely since the number of remaining bytes is known. Signed-off-by: Patrick Strawderman <[email protected]>
1 parent ffb32f4 commit 1c80d32

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferInputStream.java

+40-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818

1919
import java.io.IOException;
2020
import java.io.InputStream;
21+
import java.io.OutputStream;
22+
import java.nio.ByteBuffer;
23+
import java.nio.channels.Channels;
24+
import java.nio.channels.WritableByteChannel;
25+
import java.util.Objects;
2126

2227
import org.springframework.util.Assert;
2328

@@ -103,10 +108,44 @@ public void close() {
103108
this.closed = true;
104109
}
105110

111+
@Override
112+
public byte[] readNBytes(int len) throws IOException {
113+
if (len < 0) {
114+
throw new IllegalArgumentException("len < 0");
115+
}
116+
checkClosed();
117+
int size = Math.min(available(), len);
118+
byte[] out = new byte[size];
119+
this.dataBuffer.read(out);
120+
return out;
121+
}
122+
123+
@Override
124+
public long skip(long n) throws IOException {
125+
checkClosed();
126+
if (n <= 0) {
127+
return 0L;
128+
}
129+
int skipped = Math.min(available(), n > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) n);
130+
this.dataBuffer.readPosition(Math.min(this.end, this.dataBuffer.readPosition() + skipped));
131+
return skipped;
132+
}
133+
134+
@Override
135+
public long transferTo(OutputStream out) throws IOException {
136+
Objects.requireNonNull(out, "out");
137+
checkClosed();
138+
if (available() == 0) {
139+
return 0L;
140+
}
141+
byte[] buf = readAllBytes();
142+
out.write(buf);
143+
return buf.length;
144+
}
145+
106146
private void checkClosed() throws IOException {
107147
if (this.closed) {
108148
throw new IOException("DataBufferInputStream is closed");
109149
}
110150
}
111-
112151
}

spring-core/src/test/java/org/springframework/core/io/buffer/DataBufferTests.java

+43
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.core.io.buffer;
1818

19+
import java.io.ByteArrayOutputStream;
1920
import java.io.InputStream;
2021
import java.io.OutputStream;
2122
import java.nio.ByteBuffer;
@@ -341,6 +342,48 @@ void inputStream(DataBufferFactory bufferFactory) throws Exception {
341342
assertThat(len).isEqualTo(3);
342343
assertThat(bytes).containsExactly('c', 'd', 'e');
343344

345+
buffer.readPosition(0);
346+
inputStream = buffer.asInputStream();
347+
assertThat(inputStream.readAllBytes()).asString().isEqualTo("abcde");
348+
assertThat(inputStream.available()).isEqualTo(0);
349+
assertThat(inputStream.readAllBytes()).isEmpty();
350+
351+
buffer.readPosition(0);
352+
inputStream = buffer.asInputStream();
353+
inputStream.mark(5);
354+
assertThat(inputStream.readNBytes(0)).isEmpty();
355+
assertThat(inputStream.readNBytes(1000)).asString().isEqualTo("abcde");
356+
inputStream.reset();
357+
assertThat(inputStream.readNBytes(3)).asString().isEqualTo("abc");
358+
assertThat(inputStream.readNBytes(2)).asString().isEqualTo("de");
359+
assertThat(inputStream.readNBytes(10)).isEmpty();
360+
361+
buffer.readPosition(0);
362+
inputStream = buffer.asInputStream();
363+
inputStream.mark(5);
364+
assertThat(inputStream.skip(1)).isEqualTo(1);
365+
assertThat(inputStream.readAllBytes()).asString().isEqualTo("bcde");
366+
assertThat(inputStream.skip(10)).isEqualTo(0);
367+
assertThat(inputStream.available()).isEqualTo(0);
368+
inputStream.reset();
369+
assertThat(inputStream.skip(100)).isEqualTo(5);
370+
assertThat(inputStream.available()).isEqualTo(0);
371+
372+
buffer.readPosition(0);
373+
inputStream = buffer.asInputStream();
374+
inputStream.mark(5);
375+
ByteArrayOutputStream out = new ByteArrayOutputStream();
376+
assertThat(inputStream.transferTo(out)).isEqualTo(5);
377+
assertThat(out.toByteArray()).asString().isEqualTo("abcde");
378+
assertThat(inputStream.available()).isEqualTo(0);
379+
out.reset();
380+
inputStream.reset();
381+
assertThat(inputStream.read()).isEqualTo('a');
382+
assertThat(inputStream.transferTo(out)).isEqualTo(4);
383+
assertThat(out.toByteArray()).asString().isEqualTo("bcde");
384+
assertThat(inputStream.available()).isEqualTo(0);
385+
assertThat(inputStream.transferTo(OutputStream.nullOutputStream())).isEqualTo(0);
386+
344387
release(buffer);
345388
}
346389

0 commit comments

Comments
 (0)