Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/nio/channels/Channels.java
38918 views
/*1* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.nio.channels;2627import java.io.FileInputStream;28import java.io.FileOutputStream;29import java.io.InputStream;30import java.io.OutputStream;31import java.io.Reader;32import java.io.Writer;33import java.io.IOException;34import java.nio.ByteBuffer;35import java.nio.charset.Charset;36import java.nio.charset.CharsetDecoder;37import java.nio.charset.CharsetEncoder;38import java.nio.charset.UnsupportedCharsetException;39import java.nio.channels.spi.AbstractInterruptibleChannel;40import java.util.concurrent.ExecutionException;41import sun.nio.ch.ChannelInputStream;42import sun.nio.cs.StreamDecoder;43import sun.nio.cs.StreamEncoder;444546/**47* Utility methods for channels and streams.48*49* <p> This class defines static methods that support the interoperation of the50* stream classes of the <tt>{@link java.io}</tt> package with the channel51* classes of this package. </p>52*53*54* @author Mark Reinhold55* @author Mike McCloskey56* @author JSR-51 Expert Group57* @since 1.458*/5960public final class Channels {6162private Channels() { } // No instantiation6364private static void checkNotNull(Object o, String name) {65if (o == null)66throw new NullPointerException("\"" + name + "\" is null!");67}6869/**70* Write all remaining bytes in buffer to the given channel.71* If the channel is selectable then it must be configured blocking.72*/73private static void writeFullyImpl(WritableByteChannel ch, ByteBuffer bb)74throws IOException75{76while (bb.remaining() > 0) {77int n = ch.write(bb);78if (n <= 0)79throw new RuntimeException("no bytes written");80}81}8283/**84* Write all remaining bytes in buffer to the given channel.85*86* @throws IllegalBlockingModeException87* If the channel is selectable and configured non-blocking.88*/89private static void writeFully(WritableByteChannel ch, ByteBuffer bb)90throws IOException91{92if (ch instanceof SelectableChannel) {93SelectableChannel sc = (SelectableChannel)ch;94synchronized (sc.blockingLock()) {95if (!sc.isBlocking())96throw new IllegalBlockingModeException();97writeFullyImpl(ch, bb);98}99} else {100writeFullyImpl(ch, bb);101}102}103104// -- Byte streams from channels --105106/**107* Constructs a stream that reads bytes from the given channel.108*109* <p> The <tt>read</tt> methods of the resulting stream will throw an110* {@link IllegalBlockingModeException} if invoked while the underlying111* channel is in non-blocking mode. The stream will not be buffered, and112* it will not support the {@link InputStream#mark mark} or {@link113* InputStream#reset reset} methods. The stream will be safe for access by114* multiple concurrent threads. Closing the stream will in turn cause the115* channel to be closed. </p>116*117* @param ch118* The channel from which bytes will be read119*120* @return A new input stream121*/122public static InputStream newInputStream(ReadableByteChannel ch) {123checkNotNull(ch, "ch");124return new sun.nio.ch.ChannelInputStream(ch);125}126127/**128* Constructs a stream that writes bytes to the given channel.129*130* <p> The <tt>write</tt> methods of the resulting stream will throw an131* {@link IllegalBlockingModeException} if invoked while the underlying132* channel is in non-blocking mode. The stream will not be buffered. The133* stream will be safe for access by multiple concurrent threads. Closing134* the stream will in turn cause the channel to be closed. </p>135*136* @param ch137* The channel to which bytes will be written138*139* @return A new output stream140*/141public static OutputStream newOutputStream(final WritableByteChannel ch) {142checkNotNull(ch, "ch");143144return new OutputStream() {145146private ByteBuffer bb = null;147private byte[] bs = null; // Invoker's previous array148private byte[] b1 = null;149150public synchronized void write(int b) throws IOException {151if (b1 == null)152b1 = new byte[1];153b1[0] = (byte)b;154this.write(b1);155}156157public synchronized void write(byte[] bs, int off, int len)158throws IOException159{160if ((off < 0) || (off > bs.length) || (len < 0) ||161((off + len) > bs.length) || ((off + len) < 0)) {162throw new IndexOutOfBoundsException();163} else if (len == 0) {164return;165}166ByteBuffer bb = ((this.bs == bs)167? this.bb168: ByteBuffer.wrap(bs));169bb.limit(Math.min(off + len, bb.capacity()));170bb.position(off);171this.bb = bb;172this.bs = bs;173Channels.writeFully(ch, bb);174}175176public void close() throws IOException {177ch.close();178}179180};181}182183/**184* Constructs a stream that reads bytes from the given channel.185*186* <p> The stream will not be buffered, and it will not support the {@link187* InputStream#mark mark} or {@link InputStream#reset reset} methods. The188* stream will be safe for access by multiple concurrent threads. Closing189* the stream will in turn cause the channel to be closed. </p>190*191* @param ch192* The channel from which bytes will be read193*194* @return A new input stream195*196* @since 1.7197*/198public static InputStream newInputStream(final AsynchronousByteChannel ch) {199checkNotNull(ch, "ch");200return new InputStream() {201202private ByteBuffer bb = null;203private byte[] bs = null; // Invoker's previous array204private byte[] b1 = null;205206@Override207public synchronized int read() throws IOException {208if (b1 == null)209b1 = new byte[1];210int n = this.read(b1);211if (n == 1)212return b1[0] & 0xff;213return -1;214}215216@Override217public synchronized int read(byte[] bs, int off, int len)218throws IOException219{220if ((off < 0) || (off > bs.length) || (len < 0) ||221((off + len) > bs.length) || ((off + len) < 0)) {222throw new IndexOutOfBoundsException();223} else if (len == 0)224return 0;225226ByteBuffer bb = ((this.bs == bs)227? this.bb228: ByteBuffer.wrap(bs));229bb.position(off);230bb.limit(Math.min(off + len, bb.capacity()));231this.bb = bb;232this.bs = bs;233234boolean interrupted = false;235try {236for (;;) {237try {238return ch.read(bb).get();239} catch (ExecutionException ee) {240throw new IOException(ee.getCause());241} catch (InterruptedException ie) {242interrupted = true;243}244}245} finally {246if (interrupted)247Thread.currentThread().interrupt();248}249}250251@Override252public void close() throws IOException {253ch.close();254}255};256}257258/**259* Constructs a stream that writes bytes to the given channel.260*261* <p> The stream will not be buffered. The stream will be safe for access262* by multiple concurrent threads. Closing the stream will in turn cause263* the channel to be closed. </p>264*265* @param ch266* The channel to which bytes will be written267*268* @return A new output stream269*270* @since 1.7271*/272public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {273checkNotNull(ch, "ch");274return new OutputStream() {275276private ByteBuffer bb = null;277private byte[] bs = null; // Invoker's previous array278private byte[] b1 = null;279280@Override281public synchronized void write(int b) throws IOException {282if (b1 == null)283b1 = new byte[1];284b1[0] = (byte)b;285this.write(b1);286}287288@Override289public synchronized void write(byte[] bs, int off, int len)290throws IOException291{292if ((off < 0) || (off > bs.length) || (len < 0) ||293((off + len) > bs.length) || ((off + len) < 0)) {294throw new IndexOutOfBoundsException();295} else if (len == 0) {296return;297}298ByteBuffer bb = ((this.bs == bs)299? this.bb300: ByteBuffer.wrap(bs));301bb.limit(Math.min(off + len, bb.capacity()));302bb.position(off);303this.bb = bb;304this.bs = bs;305306boolean interrupted = false;307try {308while (bb.remaining() > 0) {309try {310ch.write(bb).get();311} catch (ExecutionException ee) {312throw new IOException(ee.getCause());313} catch (InterruptedException ie) {314interrupted = true;315}316}317} finally {318if (interrupted)319Thread.currentThread().interrupt();320}321}322323@Override324public void close() throws IOException {325ch.close();326}327};328}329330331// -- Channels from streams --332333/**334* Constructs a channel that reads bytes from the given stream.335*336* <p> The resulting channel will not be buffered; it will simply redirect337* its I/O operations to the given stream. Closing the channel will in338* turn cause the stream to be closed. </p>339*340* @param in341* The stream from which bytes are to be read342*343* @return A new readable byte channel344*/345public static ReadableByteChannel newChannel(final InputStream in) {346checkNotNull(in, "in");347348if (in instanceof FileInputStream &&349FileInputStream.class.equals(in.getClass())) {350return ((FileInputStream)in).getChannel();351}352353return new ReadableByteChannelImpl(in);354}355356private static class ReadableByteChannelImpl357extends AbstractInterruptibleChannel // Not really interruptible358implements ReadableByteChannel359{360InputStream in;361private static final int TRANSFER_SIZE = 8192;362private byte buf[] = new byte[0];363private boolean open = true;364private Object readLock = new Object();365366ReadableByteChannelImpl(InputStream in) {367this.in = in;368}369370public int read(ByteBuffer dst) throws IOException {371int len = dst.remaining();372int totalRead = 0;373int bytesRead = 0;374synchronized (readLock) {375while (totalRead < len) {376int bytesToRead = Math.min((len - totalRead),377TRANSFER_SIZE);378if (buf.length < bytesToRead)379buf = new byte[bytesToRead];380if ((totalRead > 0) && !(in.available() > 0))381break; // block at most once382try {383begin();384bytesRead = in.read(buf, 0, bytesToRead);385} finally {386end(bytesRead > 0);387}388if (bytesRead < 0)389break;390else391totalRead += bytesRead;392dst.put(buf, 0, bytesRead);393}394if ((bytesRead < 0) && (totalRead == 0))395return -1;396397return totalRead;398}399}400401protected void implCloseChannel() throws IOException {402in.close();403open = false;404}405}406407408/**409* Constructs a channel that writes bytes to the given stream.410*411* <p> The resulting channel will not be buffered; it will simply redirect412* its I/O operations to the given stream. Closing the channel will in413* turn cause the stream to be closed. </p>414*415* @param out416* The stream to which bytes are to be written417*418* @return A new writable byte channel419*/420public static WritableByteChannel newChannel(final OutputStream out) {421checkNotNull(out, "out");422423if (out instanceof FileOutputStream &&424FileOutputStream.class.equals(out.getClass())) {425return ((FileOutputStream)out).getChannel();426}427428return new WritableByteChannelImpl(out);429}430431private static class WritableByteChannelImpl432extends AbstractInterruptibleChannel // Not really interruptible433implements WritableByteChannel434{435OutputStream out;436private static final int TRANSFER_SIZE = 8192;437private byte buf[] = new byte[0];438private boolean open = true;439private Object writeLock = new Object();440441WritableByteChannelImpl(OutputStream out) {442this.out = out;443}444445public int write(ByteBuffer src) throws IOException {446int len = src.remaining();447int totalWritten = 0;448synchronized (writeLock) {449while (totalWritten < len) {450int bytesToWrite = Math.min((len - totalWritten),451TRANSFER_SIZE);452if (buf.length < bytesToWrite)453buf = new byte[bytesToWrite];454src.get(buf, 0, bytesToWrite);455try {456begin();457out.write(buf, 0, bytesToWrite);458} finally {459end(bytesToWrite > 0);460}461totalWritten += bytesToWrite;462}463return totalWritten;464}465}466467protected void implCloseChannel() throws IOException {468out.close();469open = false;470}471}472473474// -- Character streams from channels --475476/**477* Constructs a reader that decodes bytes from the given channel using the478* given decoder.479*480* <p> The resulting stream will contain an internal input buffer of at481* least <tt>minBufferCap</tt> bytes. The stream's <tt>read</tt> methods482* will, as needed, fill the buffer by reading bytes from the underlying483* channel; if the channel is in non-blocking mode when bytes are to be484* read then an {@link IllegalBlockingModeException} will be thrown. The485* resulting stream will not otherwise be buffered, and it will not support486* the {@link Reader#mark mark} or {@link Reader#reset reset} methods.487* Closing the stream will in turn cause the channel to be closed. </p>488*489* @param ch490* The channel from which bytes will be read491*492* @param dec493* The charset decoder to be used494*495* @param minBufferCap496* The minimum capacity of the internal byte buffer,497* or <tt>-1</tt> if an implementation-dependent498* default capacity is to be used499*500* @return A new reader501*/502public static Reader newReader(ReadableByteChannel ch,503CharsetDecoder dec,504int minBufferCap)505{506checkNotNull(ch, "ch");507return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);508}509510/**511* Constructs a reader that decodes bytes from the given channel according512* to the named charset.513*514* <p> An invocation of this method of the form515*516* <blockquote><pre>517* Channels.newReader(ch, csname)</pre></blockquote>518*519* behaves in exactly the same way as the expression520*521* <blockquote><pre>522* Channels.newReader(ch,523* Charset.forName(csName)524* .newDecoder(),525* -1);</pre></blockquote>526*527* @param ch528* The channel from which bytes will be read529*530* @param csName531* The name of the charset to be used532*533* @return A new reader534*535* @throws UnsupportedCharsetException536* If no support for the named charset is available537* in this instance of the Java virtual machine538*/539public static Reader newReader(ReadableByteChannel ch,540String csName)541{542checkNotNull(csName, "csName");543return newReader(ch, Charset.forName(csName).newDecoder(), -1);544}545546/**547* Constructs a writer that encodes characters using the given encoder and548* writes the resulting bytes to the given channel.549*550* <p> The resulting stream will contain an internal output buffer of at551* least <tt>minBufferCap</tt> bytes. The stream's <tt>write</tt> methods552* will, as needed, flush the buffer by writing bytes to the underlying553* channel; if the channel is in non-blocking mode when bytes are to be554* written then an {@link IllegalBlockingModeException} will be thrown.555* The resulting stream will not otherwise be buffered. Closing the stream556* will in turn cause the channel to be closed. </p>557*558* @param ch559* The channel to which bytes will be written560*561* @param enc562* The charset encoder to be used563*564* @param minBufferCap565* The minimum capacity of the internal byte buffer,566* or <tt>-1</tt> if an implementation-dependent567* default capacity is to be used568*569* @return A new writer570*/571public static Writer newWriter(final WritableByteChannel ch,572final CharsetEncoder enc,573final int minBufferCap)574{575checkNotNull(ch, "ch");576return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);577}578579/**580* Constructs a writer that encodes characters according to the named581* charset and writes the resulting bytes to the given channel.582*583* <p> An invocation of this method of the form584*585* <blockquote><pre>586* Channels.newWriter(ch, csname)</pre></blockquote>587*588* behaves in exactly the same way as the expression589*590* <blockquote><pre>591* Channels.newWriter(ch,592* Charset.forName(csName)593* .newEncoder(),594* -1);</pre></blockquote>595*596* @param ch597* The channel to which bytes will be written598*599* @param csName600* The name of the charset to be used601*602* @return A new writer603*604* @throws UnsupportedCharsetException605* If no support for the named charset is available606* in this instance of the Java virtual machine607*/608public static Writer newWriter(WritableByteChannel ch,609String csName)610{611checkNotNull(csName, "csName");612return newWriter(ch, Charset.forName(csName).newEncoder(), -1);613}614}615616617