mirror of https://github.com/apache/poi.git
Enhance javadoc and coverage for IOUtils
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1887801 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2ceb5ff553
commit
82bf04669f
|
@ -232,6 +232,13 @@ public final class IOUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method, just calls <tt>readFully(in, b, 0, b.length)</tt>
|
* Helper method, just calls <tt>readFully(in, b, 0, b.length)</tt>
|
||||||
|
*
|
||||||
|
* @param in the stream from which the data is read.
|
||||||
|
* @param b the buffer into which the data is read.
|
||||||
|
*
|
||||||
|
* @return the number of bytes read or -1 if no bytes were read
|
||||||
|
*
|
||||||
|
* @throws IOException if reading from the stream fails
|
||||||
*/
|
*/
|
||||||
public static int readFully(InputStream in, byte[] b) throws IOException {
|
public static int readFully(InputStream in, byte[] b) throws IOException {
|
||||||
return readFully(in, b, 0, b.length);
|
return readFully(in, b, 0, b.length);
|
||||||
|
@ -250,6 +257,10 @@ public final class IOUtils {
|
||||||
* @param b the buffer into which the data is read.
|
* @param b the buffer into which the data is read.
|
||||||
* @param off the start offset in array <tt>b</tt> at which the data is written.
|
* @param off the start offset in array <tt>b</tt> at which the data is written.
|
||||||
* @param len the maximum number of bytes to read.
|
* @param len the maximum number of bytes to read.
|
||||||
|
*
|
||||||
|
* @return the number of bytes read or -1 if no bytes were read
|
||||||
|
*
|
||||||
|
* @throws IOException if reading from the stream fails
|
||||||
*/
|
*/
|
||||||
public static int readFully(InputStream in, byte[] b, int off, int len) throws IOException {
|
public static int readFully(InputStream in, byte[] b, int off, int len) throws IOException {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
@ -275,6 +286,13 @@ public final class IOUtils {
|
||||||
* number of bytes read. If the end of the file isn't reached before the
|
* number of bytes read. If the end of the file isn't reached before the
|
||||||
* buffer has no more remaining capacity, will return the number of bytes
|
* buffer has no more remaining capacity, will return the number of bytes
|
||||||
* that were read.
|
* that were read.
|
||||||
|
*
|
||||||
|
* @param channel The byte-channel to read data from
|
||||||
|
* @param b the buffer into which the data is read.
|
||||||
|
*
|
||||||
|
* @return the number of bytes read or -1 if no bytes were read
|
||||||
|
*
|
||||||
|
* @throws IOException if reading from the stream fails
|
||||||
*/
|
*/
|
||||||
public static int readFully(ReadableByteChannel channel, ByteBuffer b) throws IOException {
|
public static int readFully(ReadableByteChannel channel, ByteBuffer b) throws IOException {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -34,6 +35,7 @@ import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PushbackInputStream;
|
import java.io.PushbackInputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
@ -42,29 +44,25 @@ import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to test IOUtils
|
|
||||||
*/
|
|
||||||
final class TestIOUtils {
|
final class TestIOUtils {
|
||||||
|
|
||||||
private static File TMP;
|
private static File TMP;
|
||||||
private static final long LENGTH = 300+new Random().nextInt(9000);
|
private static final long LENGTH = 300 + new Random().nextInt(9000);
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setUp() throws IOException {
|
public static void setUp() throws IOException {
|
||||||
TMP = File.createTempFile("poi-ioutils-", "");
|
TMP = File.createTempFile("poi-ioutils-", "");
|
||||||
OutputStream os = new FileOutputStream(TMP);
|
try (OutputStream os = new FileOutputStream(TMP)) {
|
||||||
for (int i = 0; i < LENGTH; i++) {
|
for (int i = 0; i < LENGTH; i++) {
|
||||||
os.write(0x01);
|
os.write(0x01);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
os.flush();
|
|
||||||
os.close();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
public static void tearDown() {
|
public static void tearDown() {
|
||||||
if (TMP != null) assertTrue(TMP.delete());
|
if (TMP != null) {
|
||||||
|
assertTrue(TMP.delete());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputStream data123() {
|
private static InputStream data123() {
|
||||||
|
@ -163,7 +161,7 @@ final class TestIOUtils {
|
||||||
void testSkipFullyByteArray() throws IOException {
|
void testSkipFullyByteArray() throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
try (InputStream is = new FileInputStream(TMP)) {
|
try (InputStream is = new FileInputStream(TMP)) {
|
||||||
IOUtils.copy(is, bos);
|
assertEquals(LENGTH, IOUtils.copy(is, bos));
|
||||||
long skipped = IOUtils.skipFully(new ByteArrayInputStream(bos.toByteArray()), 20000L);
|
long skipped = IOUtils.skipFully(new ByteArrayInputStream(bos.toByteArray()), 20000L);
|
||||||
assertEquals(LENGTH, skipped);
|
assertEquals(LENGTH, skipped);
|
||||||
}
|
}
|
||||||
|
@ -173,12 +171,41 @@ final class TestIOUtils {
|
||||||
void testSkipFullyByteArrayGtIntMax() throws IOException {
|
void testSkipFullyByteArrayGtIntMax() throws IOException {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
try (InputStream is = new FileInputStream(TMP)) {
|
try (InputStream is = new FileInputStream(TMP)) {
|
||||||
IOUtils.copy(is, bos);
|
assertEquals(LENGTH, IOUtils.copy(is, bos));
|
||||||
long skipped = IOUtils.skipFully(new ByteArrayInputStream(bos.toByteArray()), Integer.MAX_VALUE + 20000L);
|
long skipped = IOUtils.skipFully(new ByteArrayInputStream(bos.toByteArray()), Integer.MAX_VALUE + 20000L);
|
||||||
assertEquals(LENGTH, skipped);
|
assertEquals(LENGTH, skipped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCopyToFile() throws IOException {
|
||||||
|
File dest = File.createTempFile("poi-ioutils-", "");
|
||||||
|
try {
|
||||||
|
try (InputStream is = new FileInputStream(TMP)) {
|
||||||
|
assertEquals(LENGTH, IOUtils.copy(is, dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileInputStream strOrig = new FileInputStream(TMP);
|
||||||
|
FileInputStream strDest = new FileInputStream(dest)) {
|
||||||
|
byte[] bytesOrig = new byte[(int)LENGTH];
|
||||||
|
byte[] bytesDest = new byte[(int)LENGTH];
|
||||||
|
IOUtils.readFully(strOrig, bytesOrig);
|
||||||
|
IOUtils.readFully(strDest, bytesDest);
|
||||||
|
assertArrayEquals(bytesOrig, bytesDest);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
assertTrue(dest.delete());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCopyToInvalidFile() throws IOException {
|
||||||
|
try (InputStream is = new FileInputStream(TMP)) {
|
||||||
|
assertThrows(RuntimeException.class,
|
||||||
|
() -> IOUtils.copy(is, new File("/notexisting/directory/structure")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSkipFullyBug61294() throws IOException {
|
void testSkipFullyBug61294() throws IOException {
|
||||||
long skipped = IOUtils.skipFully(new ByteArrayInputStream(new byte[0]), 1);
|
long skipped = IOUtils.skipFully(new ByteArrayInputStream(new byte[0]), 1);
|
||||||
|
@ -292,7 +319,7 @@ final class TestIOUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testSetMaxOverrideOverLimitWithLength() throws IOException {
|
void testSetMaxOverrideOverLimitWithLength() {
|
||||||
IOUtils.setByteArrayMaxOverride(2);
|
IOUtils.setByteArrayMaxOverride(2);
|
||||||
try {
|
try {
|
||||||
ByteArrayInputStream stream = new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8));
|
ByteArrayInputStream stream = new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8));
|
||||||
|
@ -324,31 +351,92 @@ final class TestIOUtils {
|
||||||
@Test
|
@Test
|
||||||
void testReadFully() throws IOException {
|
void testReadFully() throws IOException {
|
||||||
byte[] bytes = new byte[2];
|
byte[] bytes = new byte[2];
|
||||||
IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 0, 2);
|
assertEquals(2, IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 0, 2));
|
||||||
assertArrayEquals(new byte[] {1,2}, bytes);
|
assertArrayEquals(new byte[] {1,2}, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyEOF() throws IOException {
|
||||||
|
byte[] bytes = new byte[2];
|
||||||
|
assertEquals(2, IOUtils.readFully(new NullInputStream(2), bytes, 0, 4));
|
||||||
|
assertArrayEquals(new byte[] {0,0}, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyEOFZero() throws IOException {
|
||||||
|
byte[] bytes = new byte[2];
|
||||||
|
assertEquals(-1, IOUtils.readFully(new NullInputStream(0), bytes, 0, 4));
|
||||||
|
assertArrayEquals(new byte[] {0,0}, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReadFullySimple() throws IOException {
|
void testReadFullySimple() throws IOException {
|
||||||
byte[] bytes = new byte[2];
|
byte[] bytes = new byte[2];
|
||||||
IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes);
|
assertEquals(2, IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes));
|
||||||
assertArrayEquals(new byte[] {1,2}, bytes);
|
assertArrayEquals(new byte[] {1,2}, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReadFullyOffset() throws IOException {
|
void testReadFullyOffset() throws IOException {
|
||||||
byte[] bytes = new byte[3];
|
byte[] bytes = new byte[3];
|
||||||
IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 1, 2);
|
assertEquals(2, IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 1, 2));
|
||||||
assertArrayEquals(new byte[] {0, 1,2}, bytes);
|
assertArrayEquals(new byte[] {0, 1,2}, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testReadFullyAtLength() throws IOException {
|
void testReadFullyAtLength() throws IOException {
|
||||||
byte[] bytes = new byte[3];
|
byte[] bytes = new byte[3];
|
||||||
IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 0, 3);
|
assertEquals(3, IOUtils.readFully(new ByteArrayInputStream(new byte[] {1, 2, 3}), bytes, 0, 3));
|
||||||
assertArrayEquals(new byte[] {1,2, 3}, bytes);
|
assertArrayEquals(new byte[] {1,2, 3}, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyChannel() throws IOException {
|
||||||
|
ByteBuffer bytes = ByteBuffer.allocate(2);
|
||||||
|
assertEquals(2, IOUtils.readFully(new SimpleByteChannel(new byte[]{1, 2, 3}), bytes));
|
||||||
|
assertArrayEquals(new byte[] {1,2}, bytes.array());
|
||||||
|
assertEquals(2, bytes.position());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyChannelEOF() throws IOException {
|
||||||
|
ByteBuffer bytes = ByteBuffer.allocate(2);
|
||||||
|
assertEquals(-1, IOUtils.readFully(new EOFByteChannel(false), bytes));
|
||||||
|
assertArrayEquals(new byte[] {0,0}, bytes.array());
|
||||||
|
assertEquals(0, bytes.position());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyChannelEOFException() {
|
||||||
|
ByteBuffer bytes = ByteBuffer.allocate(2);
|
||||||
|
assertThrows(IOException.class,
|
||||||
|
() -> IOUtils.readFully(new EOFByteChannel(true), bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testReadFullyChannelSimple() throws IOException {
|
||||||
|
ByteBuffer bytes = ByteBuffer.allocate(2);
|
||||||
|
assertEquals(2, IOUtils.readFully(new SimpleByteChannel(new byte[] {1, 2, 3}), bytes));
|
||||||
|
assertArrayEquals(new byte[] {1,2}, bytes.array());
|
||||||
|
assertEquals(2, bytes.position());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChecksum() {
|
||||||
|
assertEquals(0L, IOUtils.calculateChecksum(new byte[0]));
|
||||||
|
assertEquals(3057449933L, IOUtils.calculateChecksum(new byte[] { 1, 2, 3, 4}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChecksumStream() throws IOException {
|
||||||
|
assertEquals(0L, IOUtils.calculateChecksum(new NullInputStream(0)));
|
||||||
|
assertEquals(0L, IOUtils.calculateChecksum(new NullInputStream(1)));
|
||||||
|
assertEquals(3057449933L, IOUtils.calculateChecksum(new ByteArrayInputStream(new byte[] { 1, 2, 3, 4})));
|
||||||
|
assertThrows(EOFException.class,
|
||||||
|
() -> IOUtils.calculateChecksum(new NullInputStream(1, true)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This returns 0 for the first call to skip and then reads
|
* This returns 0 for the first call to skip and then reads
|
||||||
* as requested. This tests that the fallback to read() works.
|
* as requested. This tests that the fallback to read() works.
|
||||||
|
@ -386,4 +474,102 @@ final class TestIOUtils {
|
||||||
return 100000;
|
return 100000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class EOFByteChannel implements ReadableByteChannel {
|
||||||
|
private final boolean throwException;
|
||||||
|
|
||||||
|
public EOFByteChannel(boolean throwException) {
|
||||||
|
this.throwException = throwException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
|
if (throwException) {
|
||||||
|
throw new IOException("EOF");
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SimpleByteChannel extends InputStream implements ReadableByteChannel {
|
||||||
|
private final byte[] bytes;
|
||||||
|
|
||||||
|
public SimpleByteChannel(byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(ByteBuffer dst) throws IOException {
|
||||||
|
int toRead = Math.min(bytes.length, dst.capacity());
|
||||||
|
dst.put(bytes, 0, toRead);
|
||||||
|
return toRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NullInputStream extends InputStream {
|
||||||
|
private final int bytes;
|
||||||
|
private final boolean exception;
|
||||||
|
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
public NullInputStream(int bytes) {
|
||||||
|
this(bytes, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NullInputStream(int bytes, boolean exception) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
this.exception = exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
if (position >= bytes) {
|
||||||
|
return handleReturn();
|
||||||
|
}
|
||||||
|
|
||||||
|
position++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int handleReturn() throws EOFException {
|
||||||
|
if (exception) {
|
||||||
|
throw new EOFException();
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
int toRead = Math.min(b.length, len);
|
||||||
|
if (toRead > (bytes - position)) {
|
||||||
|
return handleReturn();
|
||||||
|
}
|
||||||
|
toRead = Math.min(toRead, (bytes - position));
|
||||||
|
|
||||||
|
position += toRead;
|
||||||
|
return toRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue