1 /* |
1 /* |
2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
36 import java.nio.charset.Charset; |
36 import java.nio.charset.Charset; |
37 import java.nio.charset.CharsetDecoder; |
37 import java.nio.charset.CharsetDecoder; |
38 import java.nio.charset.CharsetEncoder; |
38 import java.nio.charset.CharsetEncoder; |
39 import java.nio.charset.UnsupportedCharsetException; |
39 import java.nio.charset.UnsupportedCharsetException; |
40 import java.nio.channels.spi.AbstractInterruptibleChannel; |
40 import java.nio.channels.spi.AbstractInterruptibleChannel; |
|
41 import java.util.Objects; |
41 import java.util.concurrent.ExecutionException; |
42 import java.util.concurrent.ExecutionException; |
42 import sun.nio.ch.ChannelInputStream; |
43 import sun.nio.ch.ChannelInputStream; |
43 import sun.nio.cs.StreamDecoder; |
44 import sun.nio.cs.StreamDecoder; |
44 import sun.nio.cs.StreamEncoder; |
45 import sun.nio.cs.StreamEncoder; |
45 |
46 |
46 |
47 |
47 /** |
48 /** |
48 * Utility methods for channels and streams. |
49 * Utility methods for channels and streams. |
49 * |
50 * |
50 * <p> This class defines static methods that support the interoperation of the |
51 * <p> This class defines static methods that support the interoperation of the |
51 * stream classes of the <tt>{@link java.io}</tt> package with the channel |
52 * stream classes of the {@link java.io} package with the channel classes |
52 * classes of this package. </p> |
53 * of this package. </p> |
53 * |
54 * |
54 * |
55 * |
55 * @author Mark Reinhold |
56 * @author Mark Reinhold |
56 * @author Mike McCloskey |
57 * @author Mike McCloskey |
57 * @author JSR-51 Expert Group |
58 * @author JSR-51 Expert Group |
58 * @since 1.4 |
59 * @since 1.4 |
59 */ |
60 */ |
60 |
61 |
61 public final class Channels { |
62 public final class Channels { |
62 |
63 |
63 private Channels() { } // No instantiation |
64 private Channels() { throw new Error("no instances"); } |
64 |
|
65 private static void checkNotNull(Object o, String name) { |
|
66 if (o == null) |
|
67 throw new NullPointerException("\"" + name + "\" is null!"); |
|
68 } |
|
69 |
65 |
70 /** |
66 /** |
71 * Write all remaining bytes in buffer to the given channel. |
67 * Write all remaining bytes in buffer to the given channel. |
72 * If the channel is selectable then it must be configured blocking. |
68 * If the channel is selectable then it must be configured blocking. |
73 */ |
69 */ |
89 */ |
85 */ |
90 private static void writeFully(WritableByteChannel ch, ByteBuffer bb) |
86 private static void writeFully(WritableByteChannel ch, ByteBuffer bb) |
91 throws IOException |
87 throws IOException |
92 { |
88 { |
93 if (ch instanceof SelectableChannel) { |
89 if (ch instanceof SelectableChannel) { |
94 SelectableChannel sc = (SelectableChannel)ch; |
90 SelectableChannel sc = (SelectableChannel) ch; |
95 synchronized (sc.blockingLock()) { |
91 synchronized (sc.blockingLock()) { |
96 if (!sc.isBlocking()) |
92 if (!sc.isBlocking()) |
97 throw new IllegalBlockingModeException(); |
93 throw new IllegalBlockingModeException(); |
98 writeFullyImpl(ch, bb); |
94 writeFullyImpl(ch, bb); |
99 } |
95 } |
105 // -- Byte streams from channels -- |
101 // -- Byte streams from channels -- |
106 |
102 |
107 /** |
103 /** |
108 * Constructs a stream that reads bytes from the given channel. |
104 * Constructs a stream that reads bytes from the given channel. |
109 * |
105 * |
110 * <p> The <tt>read</tt> methods of the resulting stream will throw an |
106 * <p> The {@code read} methods of the resulting stream will throw an |
111 * {@link IllegalBlockingModeException} if invoked while the underlying |
107 * {@link IllegalBlockingModeException} if invoked while the underlying |
112 * channel is in non-blocking mode. The stream will not be buffered, and |
108 * channel is in non-blocking mode. The stream will not be buffered, and |
113 * it will not support the {@link InputStream#mark mark} or {@link |
109 * it will not support the {@link InputStream#mark mark} or {@link |
114 * InputStream#reset reset} methods. The stream will be safe for access by |
110 * InputStream#reset reset} methods. The stream will be safe for access by |
115 * multiple concurrent threads. Closing the stream will in turn cause the |
111 * multiple concurrent threads. Closing the stream will in turn cause the |
119 * The channel from which bytes will be read |
115 * The channel from which bytes will be read |
120 * |
116 * |
121 * @return A new input stream |
117 * @return A new input stream |
122 */ |
118 */ |
123 public static InputStream newInputStream(ReadableByteChannel ch) { |
119 public static InputStream newInputStream(ReadableByteChannel ch) { |
124 checkNotNull(ch, "ch"); |
120 Objects.requireNonNull(ch, "ch"); |
125 return new sun.nio.ch.ChannelInputStream(ch); |
121 return new ChannelInputStream(ch); |
126 } |
122 } |
127 |
123 |
128 /** |
124 /** |
129 * Constructs a stream that writes bytes to the given channel. |
125 * Constructs a stream that writes bytes to the given channel. |
130 * |
126 * |
131 * <p> The <tt>write</tt> methods of the resulting stream will throw an |
127 * <p> The {@code write} methods of the resulting stream will throw an |
132 * {@link IllegalBlockingModeException} if invoked while the underlying |
128 * {@link IllegalBlockingModeException} if invoked while the underlying |
133 * channel is in non-blocking mode. The stream will not be buffered. The |
129 * channel is in non-blocking mode. The stream will not be buffered. The |
134 * stream will be safe for access by multiple concurrent threads. Closing |
130 * stream will be safe for access by multiple concurrent threads. Closing |
135 * the stream will in turn cause the channel to be closed. </p> |
131 * the stream will in turn cause the channel to be closed. </p> |
136 * |
132 * |
137 * @param ch |
133 * @param ch |
138 * The channel to which bytes will be written |
134 * The channel to which bytes will be written |
139 * |
135 * |
140 * @return A new output stream |
136 * @return A new output stream |
141 */ |
137 */ |
142 public static OutputStream newOutputStream(final WritableByteChannel ch) { |
138 public static OutputStream newOutputStream(WritableByteChannel ch) { |
143 checkNotNull(ch, "ch"); |
139 Objects.requireNonNull(ch, "ch"); |
144 |
140 |
145 return new OutputStream() { |
141 return new OutputStream() { |
146 |
142 |
147 private ByteBuffer bb = null; |
143 private ByteBuffer bb; |
148 private byte[] bs = null; // Invoker's previous array |
144 private byte[] bs; // Invoker's previous array |
149 private byte[] b1 = null; |
145 private byte[] b1; |
150 |
146 |
151 public synchronized void write(int b) throws IOException { |
147 @Override |
152 if (b1 == null) |
148 public synchronized void write(int b) throws IOException { |
153 b1 = new byte[1]; |
149 if (b1 == null) |
154 b1[0] = (byte)b; |
150 b1 = new byte[1]; |
155 this.write(b1); |
151 b1[0] = (byte) b; |
|
152 this.write(b1); |
|
153 } |
|
154 |
|
155 @Override |
|
156 public synchronized void write(byte[] bs, int off, int len) |
|
157 throws IOException |
|
158 { |
|
159 if ((off < 0) || (off > bs.length) || (len < 0) || |
|
160 ((off + len) > bs.length) || ((off + len) < 0)) { |
|
161 throw new IndexOutOfBoundsException(); |
|
162 } else if (len == 0) { |
|
163 return; |
156 } |
164 } |
157 |
165 ByteBuffer bb = ((this.bs == bs) |
158 public synchronized void write(byte[] bs, int off, int len) |
166 ? this.bb |
159 throws IOException |
167 : ByteBuffer.wrap(bs)); |
160 { |
168 bb.limit(Math.min(off + len, bb.capacity())); |
161 if ((off < 0) || (off > bs.length) || (len < 0) || |
169 bb.position(off); |
162 ((off + len) > bs.length) || ((off + len) < 0)) { |
170 this.bb = bb; |
163 throw new IndexOutOfBoundsException(); |
171 this.bs = bs; |
164 } else if (len == 0) { |
172 Channels.writeFully(ch, bb); |
165 return; |
173 } |
166 } |
174 |
167 ByteBuffer bb = ((this.bs == bs) |
175 @Override |
168 ? this.bb |
176 public void close() throws IOException { |
169 : ByteBuffer.wrap(bs)); |
177 ch.close(); |
170 bb.limit(Math.min(off + len, bb.capacity())); |
178 } |
171 bb.position(off); |
179 |
172 this.bb = bb; |
180 }; |
173 this.bs = bs; |
|
174 Channels.writeFully(ch, bb); |
|
175 } |
|
176 |
|
177 public void close() throws IOException { |
|
178 ch.close(); |
|
179 } |
|
180 |
|
181 }; |
|
182 } |
181 } |
183 |
182 |
184 /** |
183 /** |
185 * Constructs a stream that reads bytes from the given channel. |
184 * Constructs a stream that reads bytes from the given channel. |
186 * |
185 * |
194 * |
193 * |
195 * @return A new input stream |
194 * @return A new input stream |
196 * |
195 * |
197 * @since 1.7 |
196 * @since 1.7 |
198 */ |
197 */ |
199 public static InputStream newInputStream(final AsynchronousByteChannel ch) { |
198 public static InputStream newInputStream(AsynchronousByteChannel ch) { |
200 checkNotNull(ch, "ch"); |
199 Objects.requireNonNull(ch, "ch"); |
201 return new InputStream() { |
200 return new InputStream() { |
202 |
201 |
203 private ByteBuffer bb = null; |
202 private ByteBuffer bb; |
204 private byte[] bs = null; // Invoker's previous array |
203 private byte[] bs; // Invoker's previous array |
205 private byte[] b1 = null; |
204 private byte[] b1; |
206 |
205 |
207 @Override |
206 @Override |
208 public synchronized int read() throws IOException { |
207 public synchronized int read() throws IOException { |
209 if (b1 == null) |
208 if (b1 == null) |
210 b1 = new byte[1]; |
209 b1 = new byte[1]; |
214 return -1; |
213 return -1; |
215 } |
214 } |
216 |
215 |
217 @Override |
216 @Override |
218 public synchronized int read(byte[] bs, int off, int len) |
217 public synchronized int read(byte[] bs, int off, int len) |
219 throws IOException |
218 throws IOException |
220 { |
219 { |
221 if ((off < 0) || (off > bs.length) || (len < 0) || |
220 if ((off < 0) || (off > bs.length) || (len < 0) || |
222 ((off + len) > bs.length) || ((off + len) < 0)) { |
221 ((off + len) > bs.length) || ((off + len) < 0)) { |
223 throw new IndexOutOfBoundsException(); |
222 throw new IndexOutOfBoundsException(); |
224 } else if (len == 0) |
223 } else if (len == 0) { |
225 return 0; |
224 return 0; |
|
225 } |
226 |
226 |
227 ByteBuffer bb = ((this.bs == bs) |
227 ByteBuffer bb = ((this.bs == bs) |
228 ? this.bb |
228 ? this.bb |
229 : ByteBuffer.wrap(bs)); |
229 : ByteBuffer.wrap(bs)); |
230 bb.position(off); |
230 bb.position(off); |
268 * |
268 * |
269 * @return A new output stream |
269 * @return A new output stream |
270 * |
270 * |
271 * @since 1.7 |
271 * @since 1.7 |
272 */ |
272 */ |
273 public static OutputStream newOutputStream(final AsynchronousByteChannel ch) { |
273 public static OutputStream newOutputStream(AsynchronousByteChannel ch) { |
274 checkNotNull(ch, "ch"); |
274 Objects.requireNonNull(ch, "ch"); |
275 return new OutputStream() { |
275 return new OutputStream() { |
276 |
276 |
277 private ByteBuffer bb = null; |
277 private ByteBuffer bb; |
278 private byte[] bs = null; // Invoker's previous array |
278 private byte[] bs; // Invoker's previous array |
279 private byte[] b1 = null; |
279 private byte[] b1; |
280 |
280 |
281 @Override |
281 @Override |
282 public synchronized void write(int b) throws IOException { |
282 public synchronized void write(int b) throws IOException { |
283 if (b1 == null) |
283 if (b1 == null) |
284 b1 = new byte[1]; |
284 b1 = new byte[1]; |
285 b1[0] = (byte)b; |
285 b1[0] = (byte) b; |
286 this.write(b1); |
286 this.write(b1); |
287 } |
287 } |
288 |
288 |
289 @Override |
289 @Override |
290 public synchronized void write(byte[] bs, int off, int len) |
290 public synchronized void write(byte[] bs, int off, int len) |
291 throws IOException |
291 throws IOException |
292 { |
292 { |
293 if ((off < 0) || (off > bs.length) || (len < 0) || |
293 if ((off < 0) || (off > bs.length) || (len < 0) || |
294 ((off + len) > bs.length) || ((off + len) < 0)) { |
294 ((off + len) > bs.length) || ((off + len) < 0)) { |
295 throw new IndexOutOfBoundsException(); |
295 throw new IndexOutOfBoundsException(); |
296 } else if (len == 0) { |
296 } else if (len == 0) { |
341 * @param in |
341 * @param in |
342 * The stream from which bytes are to be read |
342 * The stream from which bytes are to be read |
343 * |
343 * |
344 * @return A new readable byte channel |
344 * @return A new readable byte channel |
345 */ |
345 */ |
346 public static ReadableByteChannel newChannel(final InputStream in) { |
346 public static ReadableByteChannel newChannel(InputStream in) { |
347 checkNotNull(in, "in"); |
347 Objects.requireNonNull(in, "in"); |
348 |
348 |
349 if (in instanceof FileInputStream && |
349 if (in.getClass() == FileInputStream.class) { |
350 FileInputStream.class.equals(in.getClass())) { |
350 return ((FileInputStream) in).getChannel(); |
351 return ((FileInputStream)in).getChannel(); |
|
352 } |
351 } |
353 |
352 |
354 return new ReadableByteChannelImpl(in); |
353 return new ReadableByteChannelImpl(in); |
355 } |
354 } |
356 |
355 |
357 private static class ReadableByteChannelImpl |
356 private static class ReadableByteChannelImpl |
358 extends AbstractInterruptibleChannel // Not really interruptible |
357 extends AbstractInterruptibleChannel // Not really interruptible |
359 implements ReadableByteChannel |
358 implements ReadableByteChannel |
360 { |
359 { |
361 InputStream in; |
360 private final InputStream in; |
362 private static final int TRANSFER_SIZE = 8192; |
361 private static final int TRANSFER_SIZE = 8192; |
363 private byte buf[] = new byte[0]; |
362 private byte[] buf = new byte[0]; |
364 private boolean open = true; |
363 private final Object readLock = new Object(); |
365 private Object readLock = new Object(); |
|
366 |
364 |
367 ReadableByteChannelImpl(InputStream in) { |
365 ReadableByteChannelImpl(InputStream in) { |
368 this.in = in; |
366 this.in = in; |
369 } |
367 } |
370 |
368 |
|
369 @Override |
371 public int read(ByteBuffer dst) throws IOException { |
370 public int read(ByteBuffer dst) throws IOException { |
372 int len = dst.remaining(); |
371 int len = dst.remaining(); |
373 int totalRead = 0; |
372 int totalRead = 0; |
374 int bytesRead = 0; |
373 int bytesRead = 0; |
375 synchronized (readLock) { |
374 synchronized (readLock) { |
416 * @param out |
415 * @param out |
417 * The stream to which bytes are to be written |
416 * The stream to which bytes are to be written |
418 * |
417 * |
419 * @return A new writable byte channel |
418 * @return A new writable byte channel |
420 */ |
419 */ |
421 public static WritableByteChannel newChannel(final OutputStream out) { |
420 public static WritableByteChannel newChannel(OutputStream out) { |
422 checkNotNull(out, "out"); |
421 Objects.requireNonNull(out, "out"); |
423 |
422 |
424 if (out instanceof FileOutputStream && |
423 if (out.getClass() == FileOutputStream.class) { |
425 FileOutputStream.class.equals(out.getClass())) { |
424 return ((FileOutputStream) out).getChannel(); |
426 return ((FileOutputStream)out).getChannel(); |
|
427 } |
425 } |
428 |
426 |
429 return new WritableByteChannelImpl(out); |
427 return new WritableByteChannelImpl(out); |
430 } |
428 } |
431 |
429 |
432 private static class WritableByteChannelImpl |
430 private static class WritableByteChannelImpl |
433 extends AbstractInterruptibleChannel // Not really interruptible |
431 extends AbstractInterruptibleChannel // Not really interruptible |
434 implements WritableByteChannel |
432 implements WritableByteChannel |
435 { |
433 { |
436 OutputStream out; |
434 private final OutputStream out; |
437 private static final int TRANSFER_SIZE = 8192; |
435 private static final int TRANSFER_SIZE = 8192; |
438 private byte buf[] = new byte[0]; |
436 private byte[] buf = new byte[0]; |
439 private boolean open = true; |
437 private final Object writeLock = new Object(); |
440 private Object writeLock = new Object(); |
|
441 |
438 |
442 WritableByteChannelImpl(OutputStream out) { |
439 WritableByteChannelImpl(OutputStream out) { |
443 this.out = out; |
440 this.out = out; |
444 } |
441 } |
445 |
442 |
|
443 @Override |
446 public int write(ByteBuffer src) throws IOException { |
444 public int write(ByteBuffer src) throws IOException { |
447 int len = src.remaining(); |
445 int len = src.remaining(); |
448 int totalWritten = 0; |
446 int totalWritten = 0; |
449 synchronized (writeLock) { |
447 synchronized (writeLock) { |
450 while (totalWritten < len) { |
448 while (totalWritten < len) { |
477 /** |
475 /** |
478 * Constructs a reader that decodes bytes from the given channel using the |
476 * Constructs a reader that decodes bytes from the given channel using the |
479 * given decoder. |
477 * given decoder. |
480 * |
478 * |
481 * <p> The resulting stream will contain an internal input buffer of at |
479 * <p> The resulting stream will contain an internal input buffer of at |
482 * least <tt>minBufferCap</tt> bytes. The stream's <tt>read</tt> methods |
480 * least {@code minBufferCap} bytes. The stream's {@code read} methods |
483 * will, as needed, fill the buffer by reading bytes from the underlying |
481 * will, as needed, fill the buffer by reading bytes from the underlying |
484 * channel; if the channel is in non-blocking mode when bytes are to be |
482 * channel; if the channel is in non-blocking mode when bytes are to be |
485 * read then an {@link IllegalBlockingModeException} will be thrown. The |
483 * read then an {@link IllegalBlockingModeException} will be thrown. The |
486 * resulting stream will not otherwise be buffered, and it will not support |
484 * resulting stream will not otherwise be buffered, and it will not support |
487 * the {@link Reader#mark mark} or {@link Reader#reset reset} methods. |
485 * the {@link Reader#mark mark} or {@link Reader#reset reset} methods. |
493 * @param dec |
491 * @param dec |
494 * The charset decoder to be used |
492 * The charset decoder to be used |
495 * |
493 * |
496 * @param minBufferCap |
494 * @param minBufferCap |
497 * The minimum capacity of the internal byte buffer, |
495 * The minimum capacity of the internal byte buffer, |
498 * or <tt>-1</tt> if an implementation-dependent |
496 * or {@code -1} if an implementation-dependent |
499 * default capacity is to be used |
497 * default capacity is to be used |
500 * |
498 * |
501 * @return A new reader |
499 * @return A new reader |
502 */ |
500 */ |
503 public static Reader newReader(ReadableByteChannel ch, |
501 public static Reader newReader(ReadableByteChannel ch, |
504 CharsetDecoder dec, |
502 CharsetDecoder dec, |
505 int minBufferCap) |
503 int minBufferCap) |
506 { |
504 { |
507 checkNotNull(ch, "ch"); |
505 Objects.requireNonNull(ch, "ch"); |
508 return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap); |
506 return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap); |
509 } |
507 } |
510 |
508 |
511 /** |
509 /** |
512 * Constructs a reader that decodes bytes from the given channel according |
510 * Constructs a reader that decodes bytes from the given channel according |
513 * to the named charset. |
511 * to the named charset. |
514 * |
512 * |
515 * <p> An invocation of this method of the form |
513 * <p> An invocation of this method of the form |
516 * |
514 * |
517 * <blockquote><pre> |
515 * <pre> {@code |
518 * Channels.newReader(ch, csname)</pre></blockquote> |
516 * Channels.newReader(ch, csname) |
|
517 * } </pre> |
519 * |
518 * |
520 * behaves in exactly the same way as the expression |
519 * behaves in exactly the same way as the expression |
521 * |
520 * |
522 * <blockquote><pre> |
521 * <pre> {@code |
523 * Channels.newReader(ch, |
522 * Channels.newReader(ch, Charset.forName(csName).newDecoder(), -1) |
524 * Charset.forName(csName) |
523 * } </pre> |
525 * .newDecoder(), |
|
526 * -1);</pre></blockquote> |
|
527 * |
524 * |
528 * @param ch |
525 * @param ch |
529 * The channel from which bytes will be read |
526 * The channel from which bytes will be read |
530 * |
527 * |
531 * @param csName |
528 * @param csName |
538 * in this instance of the Java virtual machine |
535 * in this instance of the Java virtual machine |
539 */ |
536 */ |
540 public static Reader newReader(ReadableByteChannel ch, |
537 public static Reader newReader(ReadableByteChannel ch, |
541 String csName) |
538 String csName) |
542 { |
539 { |
543 checkNotNull(csName, "csName"); |
540 Objects.requireNonNull(csName, "csName"); |
544 return newReader(ch, Charset.forName(csName).newDecoder(), -1); |
541 return newReader(ch, Charset.forName(csName).newDecoder(), -1); |
545 } |
542 } |
546 |
543 |
547 /** |
544 /** |
548 * Constructs a writer that encodes characters using the given encoder and |
545 * Constructs a writer that encodes characters using the given encoder and |
549 * writes the resulting bytes to the given channel. |
546 * writes the resulting bytes to the given channel. |
550 * |
547 * |
551 * <p> The resulting stream will contain an internal output buffer of at |
548 * <p> The resulting stream will contain an internal output buffer of at |
552 * least <tt>minBufferCap</tt> bytes. The stream's <tt>write</tt> methods |
549 * least {@code minBufferCap} bytes. The stream's {@code write} methods |
553 * will, as needed, flush the buffer by writing bytes to the underlying |
550 * will, as needed, flush the buffer by writing bytes to the underlying |
554 * channel; if the channel is in non-blocking mode when bytes are to be |
551 * channel; if the channel is in non-blocking mode when bytes are to be |
555 * written then an {@link IllegalBlockingModeException} will be thrown. |
552 * written then an {@link IllegalBlockingModeException} will be thrown. |
556 * The resulting stream will not otherwise be buffered. Closing the stream |
553 * The resulting stream will not otherwise be buffered. Closing the stream |
557 * will in turn cause the channel to be closed. </p> |
554 * will in turn cause the channel to be closed. </p> |
562 * @param enc |
559 * @param enc |
563 * The charset encoder to be used |
560 * The charset encoder to be used |
564 * |
561 * |
565 * @param minBufferCap |
562 * @param minBufferCap |
566 * The minimum capacity of the internal byte buffer, |
563 * The minimum capacity of the internal byte buffer, |
567 * or <tt>-1</tt> if an implementation-dependent |
564 * or {@code -1} if an implementation-dependent |
568 * default capacity is to be used |
565 * default capacity is to be used |
569 * |
566 * |
570 * @return A new writer |
567 * @return A new writer |
571 */ |
568 */ |
572 public static Writer newWriter(final WritableByteChannel ch, |
569 public static Writer newWriter(WritableByteChannel ch, |
573 final CharsetEncoder enc, |
570 CharsetEncoder enc, |
574 final int minBufferCap) |
571 int minBufferCap) |
575 { |
572 { |
576 checkNotNull(ch, "ch"); |
573 Objects.requireNonNull(ch, "ch"); |
577 return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap); |
574 return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap); |
578 } |
575 } |
579 |
576 |
580 /** |
577 /** |
581 * Constructs a writer that encodes characters according to the named |
578 * Constructs a writer that encodes characters according to the named |
582 * charset and writes the resulting bytes to the given channel. |
579 * charset and writes the resulting bytes to the given channel. |
583 * |
580 * |
584 * <p> An invocation of this method of the form |
581 * <p> An invocation of this method of the form |
585 * |
582 * <p> |
586 * <blockquote><pre> |
583 * <pre> {@code |
587 * Channels.newWriter(ch, csname)</pre></blockquote> |
584 * Channels.newWriter(ch, csname) |
588 * |
585 * } </pre> |
589 * behaves in exactly the same way as the expression |
586 * behaves in exactly the same way as the expression |
590 * |
587 * <p> |
591 * <blockquote><pre> |
588 * <pre> {@code |
592 * Channels.newWriter(ch, |
589 * Channels.newWriter(ch, Charset.forName(csName).newEncoder(), -1) |
593 * Charset.forName(csName) |
590 * } </pre> |
594 * .newEncoder(), |
|
595 * -1);</pre></blockquote> |
|
596 * |
591 * |
597 * @param ch |
592 * @param ch |
598 * The channel to which bytes will be written |
593 * The channel to which bytes will be written |
599 * |
594 * |
600 * @param csName |
595 * @param csName |