Skip to content

Commit 99a6100

Browse files
committed
IO-203 - Add skipFully() method for InputStreams
Implement our own skip() methods; rewrite skipFully() to use them git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@920483 13f79535-47bb-0310-9956-ffa450edef68
1 parent 79e7c9b commit 99a6100

2 files changed

Lines changed: 121 additions & 10 deletions

File tree

src/java/org/apache/commons/io/IOUtils.java

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,22 @@ public class IOUtils {
119119
}
120120

121121
/**
122-
* The default buffer size to use.
122+
* The default buffer size to use for
123+
* {@link #copyLarge(InputStream, OutputStream)}
124+
* and
125+
* {@link #copyLarge(Reader, Writer)}
123126
*/
124127
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
125128

129+
/**
130+
* The default buffer size to use for the skip() methods.
131+
*/
132+
private static final int SKIP_BUFFER_SIZE = 2048;
133+
134+
// Allocated in the skip method if necessary.
135+
private static char[] SKIP_CHAR_BUFFER;
136+
private static byte[] SKIP_BYTE_BUFFER;
137+
126138
/**
127139
* Instances should NOT be constructed in standard programming.
128140
*/
@@ -1399,6 +1411,86 @@ public static boolean contentEquals(Reader input1, Reader input2)
13991411
return (ch2 == -1);
14001412
}
14011413

1414+
/**
1415+
* Skip bytes from an input byte stream.
1416+
* This implementation guarantees that it will read as many bytes
1417+
* as possible before giving up; this may not always be the case for
1418+
* subclasses of {@link Reader}.
1419+
*
1420+
* @param input byte stream to skip
1421+
* @param toSkip number of bytes to skip.
1422+
* @return number of bytes actually skipped.
1423+
*
1424+
* @see InputStream#skip(long)
1425+
*
1426+
* @throws IOException if there is a problem reading the file
1427+
* @throws IllegalArgumentException if toSkip is negative
1428+
*/
1429+
public static long skip(InputStream input, long toSkip) throws IOException {
1430+
if (toSkip < 0) {
1431+
throw new IllegalArgumentException("Skip count must be non-negative, actual: "+toSkip);
1432+
}
1433+
/*
1434+
* N.B. no need to synchronize this because:
1435+
* - we don't care if the buffer is created multiple times (the data is ignored)
1436+
* - we always use the same size buffer, so if it it is recreated it will still be OK
1437+
* (if the buffer size were variable, we would need to synch. to ensure some other thread
1438+
* did not create a smaller one)
1439+
*/
1440+
if (SKIP_BYTE_BUFFER == null){
1441+
SKIP_BYTE_BUFFER = new byte[SKIP_BUFFER_SIZE];
1442+
}
1443+
long remain=toSkip;
1444+
while(remain > 0) {
1445+
long n = input.read(SKIP_BYTE_BUFFER, 0, (int) Math.min(remain, SKIP_BUFFER_SIZE));
1446+
if (n < 0) { // EOF
1447+
break;
1448+
}
1449+
remain -= n;
1450+
}
1451+
return toSkip - remain;
1452+
}
1453+
1454+
/**
1455+
* Skip characters from an input character stream.
1456+
* This implementation guarantees that it will read as many characters
1457+
* as possible before giving up; this may not always be the case for
1458+
* subclasses of {@link Reader}.
1459+
*
1460+
* @param input character stream to skip
1461+
* @param toSkip number of characters to skip.
1462+
* @return number of characters actually skipped.
1463+
*
1464+
* @see Reader#skip(long)
1465+
*
1466+
* @throws IOException if there is a problem reading the file
1467+
* @throws IllegalArgumentException if toSkip is negative
1468+
*/
1469+
public static long skip(Reader input, long toSkip) throws IOException {
1470+
if (toSkip < 0) {
1471+
throw new IllegalArgumentException("Skip count must be non-negative, actual: "+toSkip);
1472+
}
1473+
/*
1474+
* N.B. no need to synchronize this because:
1475+
* - we don't care if the buffer is created multiple times (the data is ignored)
1476+
* - we always use the same size buffer, so if it it is recreated it will still be OK
1477+
* (if the buffer size were variable, we would need to synch. to ensure some other thread
1478+
* did not create a smaller one)
1479+
*/
1480+
if (SKIP_CHAR_BUFFER == null){
1481+
SKIP_CHAR_BUFFER = new char[SKIP_BUFFER_SIZE];
1482+
}
1483+
long remain=toSkip;
1484+
while(remain > 0) {
1485+
long n = input.read(SKIP_CHAR_BUFFER, 0, (int) Math.min(remain, SKIP_BUFFER_SIZE));
1486+
if (n < 0) { // EOF
1487+
break;
1488+
}
1489+
remain -= n;
1490+
}
1491+
return toSkip - remain;
1492+
}
1493+
14021494
/**
14031495
* Skip the requested number of bytes or fail if there are not enough left.
14041496
* <p>
@@ -1417,31 +1509,28 @@ public static void skipFully(InputStream input, long toSkip) throws IOException
14171509
if (toSkip < 0){
14181510
throw new IllegalArgumentException("Bytes to skip must not be negative: "+toSkip);
14191511
}
1420-
long skipped = input.skip(toSkip);
1512+
long skipped = skip(input, toSkip);
14211513
if (skipped != toSkip) {
14221514
throw new EOFException("Bytes to skip: "+toSkip+" actual: "+skipped);
14231515
}
14241516
}
14251517

14261518
/**
1427-
* Skip the requested number of bytes or fail if there are not enough left.
1519+
* Skip the requested number of characters or fail if there are not enough left.
14281520
* <p>
14291521
* This allows for the possibility that {@link Reader#skip(long)} may
1430-
* not skip as many bytes as requested (most likely because of reaching EOF).
1522+
* not skip as many characters as requested (most likely because of reaching EOF).
14311523
*
14321524
* @param input stream to skip
1433-
* @param toSkip the number of bytes to skip
1525+
* @param toSkip the number of characters to skip
14341526
* @see Reader#skip(long)
14351527
*
14361528
* @throws IOException if there is a problem reading the file
14371529
* @throws IllegalArgumentException if toSkip is negative
1438-
* @throws EOFException if the number of bytes skipped was incorrect
1530+
* @throws EOFException if the number of characters skipped was incorrect
14391531
*/
14401532
public static void skipFully(Reader input, long toSkip) throws IOException {
1441-
if (toSkip < 0){
1442-
throw new IllegalArgumentException("Bytes to skip must not be negative: "+toSkip);
1443-
}
1444-
long skipped = input.skip(toSkip);
1533+
long skipped = skip(input, toSkip);
14451534
if (skipped != toSkip) {
14461535
throw new EOFException("Bytes to skip: "+toSkip+" actual: "+skipped);
14471536
}

src/test/org/apache/commons/io/IOUtilsTestCase.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,4 +510,26 @@ public void testSkipReader() throws Exception{
510510
}
511511
IOUtils.closeQuietly(input);
512512
}
513+
514+
public void testSkipFileReader() throws Exception{
515+
FileReader in = new FileReader(m_testFile);
516+
try {
517+
assertEquals(FILE_SIZE-10, IOUtils.skip(in, FILE_SIZE-10));
518+
assertEquals(10, IOUtils.skip(in, 20));
519+
assertEquals(0, IOUtils.skip(in, 10));
520+
} finally {
521+
in.close();
522+
}
523+
}
524+
525+
public void testSkipFileInput() throws Exception{
526+
InputStream in = new FileInputStream(m_testFile);
527+
try {
528+
assertEquals(FILE_SIZE-10, IOUtils.skip(in, FILE_SIZE-10));
529+
assertEquals(10, IOUtils.skip(in, 20));
530+
assertEquals(0, IOUtils.skip(in, 10));
531+
} finally {
532+
in.close();
533+
}
534+
}
513535
}

0 commit comments

Comments
 (0)