Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 32036b2

Browse files
Larry-NYuri Nesterenko
authored andcommitted
8227609: (fs) Files.newInputStream(...).skip(n) should allow skipping beyond file size
Backport-of: 3155cd8
1 parent afdd824 commit 32036b2

File tree

3 files changed

+142
-47
lines changed

3 files changed

+142
-47
lines changed

src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,21 @@ public int available() throws IOException {
119119

120120
public synchronized long skip(long n) throws IOException {
121121
// special case where the channel is to a file
122-
if (ch instanceof SeekableByteChannel && n > 0) {
122+
if (ch instanceof SeekableByteChannel) {
123123
SeekableByteChannel sbc = (SeekableByteChannel)ch;
124-
try {
125-
long pos = sbc.position();
124+
long pos = sbc.position();
125+
long newPos;
126+
if (n > 0) {
127+
newPos = pos + n;
126128
long size = sbc.size();
127-
if (pos >= size) {
128-
return 0L;
129+
if (newPos < 0 || newPos > size) {
130+
newPos = size;
129131
}
130-
n = Math.min(n, size - pos);
131-
sbc.position(pos + n);
132-
return sbc.position() - pos;
133-
} catch (ClosedChannelException cce) {
134-
throw new IOException(cce);
132+
} else {
133+
newPos = Long.max(pos + n, 0);
135134
}
135+
sbc.position(newPos);
136+
return newPos - pos;
136137
}
137138
return super.skip(n);
138139
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/* @test
25+
* @bug 8227609
26+
* @summary Test of InputStream and OutputStream created by java.nio.file.Files
27+
* @library ..
28+
*/
29+
30+
import java.io.InputStream;
31+
import java.io.OutputStream;
32+
import java.nio.channels.ClosedChannelException;
33+
import java.nio.file.*;
34+
import static java.nio.file.Files.*;
35+
import static java.nio.file.LinkOption.*;
36+
import java.nio.file.attribute.*;
37+
import java.io.IOException;
38+
import java.util.*;
39+
40+
public class InputStreamTest {
41+
42+
public static void main(String[] args) throws IOException {
43+
Path dir = TestUtil.createTemporaryDirectory();
44+
try {
45+
testSkip(dir);
46+
} finally {
47+
TestUtil.removeAll(dir);
48+
}
49+
}
50+
51+
/**
52+
* Tests Files.newInputStream(Path).skip().
53+
*/
54+
static void testSkip(Path tmpdir) throws IOException {
55+
Path file = createFile(tmpdir.resolve("foo"));
56+
try (OutputStream out = Files.newOutputStream(file)) {
57+
final int size = 512;
58+
byte[] blah = new byte[size];
59+
for (int i = 0; i < size; i++) {
60+
blah[i] = (byte)(i % 128);
61+
}
62+
out.write(blah);
63+
out.close();
64+
65+
try (InputStream in = Files.newInputStream(file)) {
66+
assertTrue(in.available() == size);
67+
assertTrue(in.skip(size/4) == size/4); // 0.25
68+
assertTrue(in.available() == 3*size/4);
69+
70+
int b = in.read();
71+
assertTrue(b == blah[size/4]);
72+
assertTrue(in.available() == 3*size/4 - 1);
73+
assertTrue(in.skip(-1) == -1); // 0.25
74+
assertTrue(in.available() == 3*size/4);
75+
76+
assertTrue(in.skip(-size/2) == -size/4); // 0
77+
assertTrue(in.available() == size);
78+
79+
assertTrue(in.skip(5*size/4) == size); // 1.0
80+
assertTrue(in.available() == 0);
81+
82+
assertTrue(in.skip(-3*size/4) == -3*size/4); // 0.25
83+
assertTrue(in.available() == 3*size/4);
84+
85+
byte[] buf = new byte[16];
86+
in.read(buf, 2, 12);
87+
assertTrue(Arrays.equals(buf, 2, 14,
88+
blah, size/4, size/4 + 12));
89+
assertTrue(in.skip(-12) == -12); // 0.25
90+
91+
assertTrue(in.skip(3*size/4) == 3*size/4); // 1.0
92+
assertTrue(in.available() == 0);
93+
94+
assertTrue(in.skip(-size/2) == -size/2); // 0.5
95+
assertTrue(in.available() == size/2);
96+
97+
assertTrue(in.skip(-size) == -size/2); // 0
98+
assertTrue(in.available() == size);
99+
100+
assertTrue(in.skip(size/2) == size/2); // 0.5
101+
assertTrue(in.available() == size/2);
102+
103+
assertTrue(in.skip(Long.MIN_VALUE) == -size/2); // 0
104+
assertTrue(in.available() == size);
105+
106+
assertTrue(in.skip(size/2) == size/2); // 0.5
107+
assertTrue(in.available() == size/2);
108+
109+
assertTrue(in.skip(Long.MAX_VALUE - size/4) == size/2);
110+
assertTrue(in.available() == 0);
111+
112+
in.close();
113+
try {
114+
in.skip(1);
115+
throw new RuntimeException("skip() did not fail");
116+
} catch (IOException ioe) {
117+
if (!(ioe instanceof ClosedChannelException)) {
118+
throw new RuntimeException
119+
("IOException is not a ClosedChannelException");
120+
}
121+
}
122+
}
123+
}
124+
}
125+
126+
static void assertTrue(boolean okay) {
127+
if (!okay)
128+
throw new RuntimeException("Assertion Failed");
129+
}
130+
}

test/jdk/java/nio/file/Files/Misc.java

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,11 @@
2222
*/
2323

2424
/* @test
25-
* @bug 4313887 6838333 8005566 8032220 8215467 8227080
25+
* @bug 4313887 6838333 8005566 8032220 8215467
2626
* @summary Unit test for miscellenous methods in java.nio.file.Files
2727
* @library ..
2828
*/
2929

30-
import java.io.InputStream;
31-
import java.io.OutputStream;
32-
import java.nio.channels.ClosedChannelException;
3330
import java.nio.file.*;
3431
import static java.nio.file.Files.*;
3532
import static java.nio.file.LinkOption.*;
@@ -47,7 +44,6 @@ public static void main(String[] args) throws IOException {
4744
testIsSameFile(dir);
4845
testFileTypeMethods(dir);
4946
testAccessMethods(dir);
50-
testSkip(dir);
5147
} finally {
5248
TestUtil.removeAll(dir);
5349
}
@@ -376,38 +372,6 @@ static void testAccessMethods(Path tmpdir) throws IOException {
376372
}
377373
}
378374

379-
/**
380-
* Tests Files.newInputStream(Path).skip().
381-
*/
382-
static void testSkip(Path tmpdir) throws IOException {
383-
Path file = createFile(tmpdir.resolve("foo"));
384-
try (OutputStream out = Files.newOutputStream(file)) {
385-
byte[] blah = new byte[8192];
386-
Arrays.fill(blah, (byte)42);
387-
out.write(blah);
388-
out.close();
389-
try (InputStream in = Files.newInputStream(file)) {
390-
assertTrue(in.skip(-1) == 0);
391-
assertTrue(in.skip(0) == 0);
392-
assertTrue(in.skip(blah.length/4) == blah.length/4);
393-
assertTrue(in.skip(blah.length/2) == blah.length/2);
394-
assertTrue(in.skip(Long.MAX_VALUE) == blah.length/4);
395-
in.close();
396-
try {
397-
long n = in.skip(1);
398-
throw new RuntimeException("skip() did not fail");
399-
} catch (IOException ioe) {
400-
if (!(ioe.getCause() instanceof ClosedChannelException)) {
401-
throw new RuntimeException
402-
("IOException not caused by ClosedChannelException");
403-
}
404-
}
405-
}
406-
} finally {
407-
delete(file);
408-
}
409-
}
410-
411375
static void assertTrue(boolean okay) {
412376
if (!okay)
413377
throw new RuntimeException("Assertion Failed");

0 commit comments

Comments
 (0)