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

8227080: (fs) Files.newInputStream(...).skip(n) is slow #210

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 24 additions & 6 deletions src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -29,7 +29,7 @@
import java.nio.*;
import java.nio.channels.*;
import java.nio.channels.spi.*;

import java.util.Objects;

/**
* This class is defined here rather than in java.nio.channels.Channels
Expand Down Expand Up @@ -87,10 +87,8 @@ public synchronized int read() throws IOException {
public synchronized int read(byte[] bs, int off, int len)
throws IOException
{
if ((off < 0) || (off > bs.length) || (len < 0) ||
((off + len) > bs.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0)
Objects.checkFromIndexSize(off, len, bs.length);
if (len == 0)
return 0;

ByteBuffer bb = ((this.bs == bs)
Expand Down Expand Up @@ -119,6 +117,26 @@ public int available() throws IOException {
return 0;
}

public synchronized long skip(long n) throws IOException {
// special case where the channel is to a file
if (ch instanceof SeekableByteChannel && n > 0) {
SeekableByteChannel sbc = (SeekableByteChannel)ch;
try {
long pos = sbc.position();
long size = sbc.size();
if (pos >= size) {
return 0L;
}
n = Math.min(n, size - pos);
sbc.position(pos + n);
return sbc.position() - pos;
} catch (ClosedChannelException cce) {
throw new IOException(cce);
}
}
return super.skip(n);
}

public void close() throws IOException {
ch.close();
}
Expand Down
38 changes: 37 additions & 1 deletion test/jdk/java/nio/file/Files/Misc.java
Expand Up @@ -22,11 +22,14 @@
*/

/* @test
* @bug 4313887 6838333 8005566 8032220 8215467
* @bug 4313887 6838333 8005566 8032220 8215467 8227080
* @summary Unit test for miscellenous methods in java.nio.file.Files
* @library ..
*/

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.ClosedChannelException;
import java.nio.file.*;
import static java.nio.file.Files.*;
import static java.nio.file.LinkOption.*;
Expand All @@ -44,6 +47,7 @@ public static void main(String[] args) throws IOException {
testIsSameFile(dir);
testFileTypeMethods(dir);
testAccessMethods(dir);
testSkip(dir);
} finally {
TestUtil.removeAll(dir);
}
Expand Down Expand Up @@ -372,6 +376,38 @@ static void testAccessMethods(Path tmpdir) throws IOException {
}
}

/**
* Tests Files.newInputStream(Path).skip().
*/
static void testSkip(Path tmpdir) throws IOException {
Path file = createFile(tmpdir.resolve("foo"));
try (OutputStream out = Files.newOutputStream(file)) {
byte[] blah = new byte[8192];
Arrays.fill(blah, (byte)42);
out.write(blah);
out.close();
try (InputStream in = Files.newInputStream(file)) {
assertTrue(in.skip(-1) == 0);
assertTrue(in.skip(0) == 0);
assertTrue(in.skip(blah.length/4) == blah.length/4);
assertTrue(in.skip(blah.length/2) == blah.length/2);
assertTrue(in.skip(Long.MAX_VALUE) == blah.length/4);
in.close();
try {
long n = in.skip(1);
throw new RuntimeException("skip() did not fail");
} catch (IOException ioe) {
if (!(ioe.getCause() instanceof ClosedChannelException)) {
throw new RuntimeException
("IOException not caused by ClosedChannelException");
}
}
}
} finally {
delete(file);
}
}

static void assertTrue(boolean okay) {
if (!okay)
throw new RuntimeException("Assertion Failed");
Expand Down