Avoid creating FileInputStream and FileOutputStream for obtaining Fil… (#8110)

Motivation:

If all we need is the FileChannel we should better use RandomAccessFile as FileInputStream and FileOutputStream use a finalizer.

Modifications:

Replace FileInputStream and FileOutputStream with RandomAccessFile when possible.

Result:

Fixes https://github.com/netty/netty/issues/8078.
This commit is contained in:
Norman Maurer 2019-08-17 09:43:01 +02:00 committed by GitHub
parent 97361fa2c8
commit d8e59ca638
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 46 deletions

View File

@ -21,9 +21,8 @@ import org.junit.Test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException; import java.nio.ReadOnlyBufferException;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
@ -307,12 +306,12 @@ public class ReadOnlyDirectByteBufferBufTest {
ByteBuf b2 = null; ByteBuf b2 = null;
try { try {
output = new FileOutputStream(file).getChannel(); output = new RandomAccessFile(file, "rw").getChannel();
byte[] bytes = new byte[1024]; byte[] bytes = new byte[1024];
PlatformDependent.threadLocalRandom().nextBytes(bytes); PlatformDependent.threadLocalRandom().nextBytes(bytes);
output.write(ByteBuffer.wrap(bytes)); output.write(ByteBuffer.wrap(bytes));
input = new FileInputStream(file).getChannel(); input = new RandomAccessFile(file, "r").getChannel();
ByteBuffer m = input.map(FileChannel.MapMode.READ_ONLY, 0, input.size()); ByteBuffer m = input.map(FileChannel.MapMode.READ_ONLY, 0, input.size());
b1 = buffer(m); b1 = buffer(m);

View File

@ -22,10 +22,9 @@ import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -125,9 +124,10 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
} }
return; return;
} }
FileOutputStream outputStream = new FileOutputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
accessFile.setLength(0);
try { try {
FileChannel localfileChannel = outputStream.getChannel(); FileChannel localfileChannel = accessFile.getChannel();
ByteBuffer byteBuffer = buffer.nioBuffer(); ByteBuffer byteBuffer = buffer.nioBuffer();
int written = 0; int written = 0;
while (written < size) { while (written < size) {
@ -136,7 +136,7 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
buffer.readerIndex(buffer.readerIndex() + written); buffer.readerIndex(buffer.readerIndex() + written);
localfileChannel.force(false); localfileChannel.force(false);
} finally { } finally {
outputStream.close(); accessFile.close();
} }
setCompleted(); setCompleted();
} finally { } finally {
@ -163,8 +163,8 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
file = tempFile(); file = tempFile();
} }
if (fileChannel == null) { if (fileChannel == null) {
FileOutputStream outputStream = new FileOutputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
fileChannel = outputStream.getChannel(); fileChannel = accessFile.getChannel();
} }
while (written < localsize) { while (written < localsize) {
written += fileChannel.write(byteBuffer); written += fileChannel.write(byteBuffer);
@ -182,8 +182,8 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
file = tempFile(); file = tempFile();
} }
if (fileChannel == null) { if (fileChannel == null) {
FileOutputStream outputStream = new FileOutputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
fileChannel = outputStream.getChannel(); fileChannel = accessFile.getChannel();
} }
fileChannel.force(false); fileChannel.force(false);
fileChannel.close(); fileChannel.close();
@ -217,10 +217,11 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
delete(); delete();
} }
file = tempFile(); file = tempFile();
FileOutputStream outputStream = new FileOutputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
accessFile.setLength(0);
int written = 0; int written = 0;
try { try {
FileChannel localfileChannel = outputStream.getChannel(); FileChannel localfileChannel = accessFile.getChannel();
byte[] bytes = new byte[4096 * 4]; byte[] bytes = new byte[4096 * 4];
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
int read = inputStream.read(bytes); int read = inputStream.read(bytes);
@ -232,7 +233,7 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
} }
localfileChannel.force(false); localfileChannel.force(false);
} finally { } finally {
outputStream.close(); accessFile.close();
} }
size = written; size = written;
if (definedSize > 0 && definedSize < size) { if (definedSize > 0 && definedSize < size) {
@ -290,8 +291,8 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
return EMPTY_BUFFER; return EMPTY_BUFFER;
} }
if (fileChannel == null) { if (fileChannel == null) {
FileInputStream inputStream = new FileInputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "r");
fileChannel = inputStream.getChannel(); fileChannel = accessFile.getChannel();
} }
int read = 0; int read = 0;
ByteBuffer byteBuffer = ByteBuffer.allocate(length); ByteBuffer byteBuffer = ByteBuffer.allocate(length);
@ -349,15 +350,15 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
if (!file.renameTo(dest)) { if (!file.renameTo(dest)) {
// must copy // must copy
IOException exception = null; IOException exception = null;
FileInputStream inputStream = null; RandomAccessFile inputAccessFile = null;
FileOutputStream outputStream = null; RandomAccessFile outputAccessFile = null;
long chunkSize = 8196; long chunkSize = 8196;
long position = 0; long position = 0;
try { try {
inputStream = new FileInputStream(file); inputAccessFile = new RandomAccessFile(file, "r");
outputStream = new FileOutputStream(dest); outputAccessFile = new RandomAccessFile(dest, "rw");
FileChannel in = inputStream.getChannel(); FileChannel in = inputAccessFile.getChannel();
FileChannel out = outputStream.getChannel(); FileChannel out = outputAccessFile.getChannel();
while (position < size) { while (position < size) {
if (chunkSize < size - position) { if (chunkSize < size - position) {
chunkSize = size - position; chunkSize = size - position;
@ -367,9 +368,9 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
} catch (IOException e) { } catch (IOException e) {
exception = e; exception = e;
} finally { } finally {
if (inputStream != null) { if (inputAccessFile != null) {
try { try {
inputStream.close(); inputAccessFile.close();
} catch (IOException e) { } catch (IOException e) {
if (exception == null) { // Choose to report the first exception if (exception == null) { // Choose to report the first exception
exception = e; exception = e;
@ -378,9 +379,9 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
} }
} }
} }
if (outputStream != null) { if (outputAccessFile != null) {
try { try {
outputStream.close(); outputAccessFile.close();
} catch (IOException e) { } catch (IOException e) {
if (exception == null) { // Choose to report the first exception if (exception == null) { // Choose to report the first exception
exception = e; exception = e;
@ -422,17 +423,17 @@ public abstract class AbstractDiskHttpData extends AbstractHttpData {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"File too big to be loaded in memory"); "File too big to be loaded in memory");
} }
FileInputStream inputStream = new FileInputStream(src); RandomAccessFile accessFile = new RandomAccessFile(src, "r");
byte[] array = new byte[(int) srcsize]; byte[] array = new byte[(int) srcsize];
try { try {
FileChannel fileChannel = inputStream.getChannel(); FileChannel fileChannel = accessFile.getChannel();
ByteBuffer byteBuffer = ByteBuffer.wrap(array); ByteBuffer byteBuffer = ByteBuffer.wrap(array);
int read = 0; int read = 0;
while (read < srcsize) { while (read < srcsize) {
read += fileChannel.read(byteBuffer); read += fileChannel.read(byteBuffer);
} }
} finally { } finally {
inputStream.close(); accessFile.close();
} }
return array; return array;
} }

View File

@ -20,10 +20,9 @@ import io.netty.buffer.CompositeByteBuf;
import io.netty.handler.codec.http.HttpConstants; import io.netty.handler.codec.http.HttpConstants;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -131,8 +130,8 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
throw new IllegalArgumentException("File too big to be loaded in memory"); throw new IllegalArgumentException("File too big to be loaded in memory");
} }
checkSize(newsize); checkSize(newsize);
FileInputStream inputStream = new FileInputStream(file); RandomAccessFile accessFile = new RandomAccessFile(file, "r");
FileChannel fileChannel = inputStream.getChannel(); FileChannel fileChannel = accessFile.getChannel();
byte[] array = new byte[(int) newsize]; byte[] array = new byte[(int) newsize];
ByteBuffer byteBuffer = ByteBuffer.wrap(array); ByteBuffer byteBuffer = ByteBuffer.wrap(array);
int read = 0; int read = 0;
@ -140,7 +139,7 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
read += fileChannel.read(byteBuffer); read += fileChannel.read(byteBuffer);
} }
fileChannel.close(); fileChannel.close();
inputStream.close(); accessFile.close();
byteBuffer.flip(); byteBuffer.flip();
if (byteBuf != null) { if (byteBuf != null) {
byteBuf.release(); byteBuf.release();
@ -232,8 +231,8 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
return true; return true;
} }
int length = byteBuf.readableBytes(); int length = byteBuf.readableBytes();
FileOutputStream outputStream = new FileOutputStream(dest); RandomAccessFile accessFile = new RandomAccessFile(dest, "rw");
FileChannel fileChannel = outputStream.getChannel(); FileChannel fileChannel = accessFile.getChannel();
int written = 0; int written = 0;
if (byteBuf.nioBufferCount() == 1) { if (byteBuf.nioBufferCount() == 1) {
ByteBuffer byteBuffer = byteBuf.nioBuffer(); ByteBuffer byteBuffer = byteBuf.nioBuffer();
@ -249,7 +248,7 @@ public abstract class AbstractMemoryHttpData extends AbstractHttpData {
fileChannel.force(false); fileChannel.force(false);
fileChannel.close(); fileChannel.close();
outputStream.close(); accessFile.close();
return written == length; return written == length;
} }

View File

@ -21,8 +21,8 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.FileRegion; import io.netty.channel.FileRegion;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
/** /**
@ -45,7 +45,7 @@ public class ChunkedNioFile implements ChunkedInput<ByteBuf> {
* Creates a new instance that fetches data from the specified file. * Creates a new instance that fetches data from the specified file.
*/ */
public ChunkedNioFile(File in) throws IOException { public ChunkedNioFile(File in) throws IOException {
this(new FileInputStream(in).getChannel()); this(new RandomAccessFile(in, "r").getChannel());
} }
/** /**
@ -55,7 +55,7 @@ public class ChunkedNioFile implements ChunkedInput<ByteBuf> {
* {@link #readChunk(ChannelHandlerContext)} call * {@link #readChunk(ChannelHandlerContext)} call
*/ */
public ChunkedNioFile(File in, int chunkSize) throws IOException { public ChunkedNioFile(File in, int chunkSize) throws IOException {
this(new FileInputStream(in).getChannel(), chunkSize); this(new RandomAccessFile(in, "r").getChannel(), chunkSize);
} }
/** /**

View File

@ -32,9 +32,9 @@ import org.hamcrest.CoreMatchers;
import org.junit.Test; import org.junit.Test;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
import java.util.Random; import java.util.Random;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@ -121,7 +121,7 @@ public class SocketFileRegionTest extends AbstractSocketTest {
// Request file region which is bigger then the underlying file. // Request file region which is bigger then the underlying file.
FileRegion region = new DefaultFileRegion( FileRegion region = new DefaultFileRegion(
new FileInputStream(file).getChannel(), 0, data.length + 1024); new RandomAccessFile(file, "r").getChannel(), 0, data.length + 1024);
assertThat(cc.writeAndFlush(region).await().cause(), CoreMatchers.<Throwable>instanceOf(IOException.class)); assertThat(cc.writeAndFlush(region).await().cause(), CoreMatchers.<Throwable>instanceOf(IOException.class));
cc.close().sync(); cc.close().sync();
@ -183,8 +183,8 @@ public class SocketFileRegionTest extends AbstractSocketTest {
Channel cc = cb.connect(sc.localAddress()).sync().channel(); Channel cc = cb.connect(sc.localAddress()).sync().channel();
FileRegion region = new DefaultFileRegion( FileRegion region = new DefaultFileRegion(
new FileInputStream(file).getChannel(), startOffset, data.length - bufferSize); new RandomAccessFile(file, "r").getChannel(), startOffset, data.length - bufferSize);
FileRegion emptyRegion = new DefaultFileRegion(new FileInputStream(file).getChannel(), 0, 0); FileRegion emptyRegion = new DefaultFileRegion(new RandomAccessFile(file, "r").getChannel(), 0, 0);
if (!defaultFileRegion) { if (!defaultFileRegion) {
region = new FileRegionWrapper(region); region = new FileRegionWrapper(region);