1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Handle an Asynchronous OutputStream that allow to differ the writing process.
* This is an example purpose, and with this implementations IOException are uncaughted..
* Maybe we should use an UncaughtExceptionHandler to complete this design.
*
* All write() methods are ASynchronous but the close() method wait until all are "writted" to the destination outputstream
*
* Exemple to use:
*
* BufferedOutputStream bos = new BufferedOutputStream( new ASyncOutputStream( new FileOutputStream( "c:\\Test.txt" ) ) );
* bos.write( "A first line".getBytes() );
* bos.write( "A second one".getBytes() );
* bos.write( "the last one".getBytes() );
* bose.close();
*
* @author André Sébastien
*/
public class ASyncOutputStream extends OutputStream
{
private OutputStream out = null;
private ExecutorService es = null;
/** Creates a new instance of AsyncOutputStream */
public ASyncOutputStream(OutputStream o)
{
this.out = o;
this.es = Executors.newSingleThreadExecutor();
}
/**
* Writes the specified byte to this output stream. The general
* contract for <code>write</code> is that one byte is written
* to the output stream. The byte to be written is the eight
* low-order bits of the argument <code>b</code>. The 24
* high-order bits of <code>b</code> are ignored.
* <p>
* Subclasses of <code>OutputStream</code> must provide an
* implementation for this method.
*
*
* @param b the <code>byte</code>.
* @exception IOException if an I/O error occurs. In particular,
* an <code>IOException</code> may be thrown if the
* output stream has been closed.
*/
public void write(final int b) throws IOException {
Runnable doRun = new Runnable()
{
public void run()
{
try
{
ASyncOutputStream.this.out.write(b);
}
catch(Exception e)
{ /* Maybe you should handle theses exceptions by a UncaughtExceptionHandler */
e.printStackTrace();
}
}
};
this.es.execute(doRun);
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this output stream.
* The general contract for <code>write(b, off, len)</code> is that
* some of the bytes in the array <code>b</code> are written to the
* output stream in order; element <code>b[off]</code> is the first
* byte written and <code>b[off+len-1]</code> is the last byte written
* by this operation.
* <p>
* The <code>write</code> method of <code>OutputStream</code> calls
* the write method of one argument on each of the bytes to be
* written out. Subclasses are encouraged to override this method and
* provide a more efficient implementation.
* <p>
* If <code>b</code> is <code>null</code>, a
* <code>NullPointerException</code> is thrown.
* <p>
* If <code>off</code> is negative, or <code>len</code> is negative, or
* <code>off+len</code> is greater than the length of the array
* <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
*
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs. In particular,
* an <code>IOException</code> is thrown if the output
* stream is closed.
*/
public void write(final byte[] b, final int off, final int len) throws IOException {
Runnable doRun = new Runnable()
{
public void run()
{
try
{
ASyncOutputStream.this.out.write(b,off,len);
}
catch(Exception e)
{ /* Maybe you should handle theses exceptions by a UncaughtExceptionHandler */
e.printStackTrace();
}
}
};
this.es.execute(doRun);
}
/**
* Closes this output stream and releases any system resources
* associated with this stream. The general contract of <code>close</code>
* is that it closes the output stream. A closed stream cannot perform
* output operations and cannot be reopened.
* <p>
* The <code>close</code> method of <code>OutputStream</code> does nothing.
*
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
super.close();
Runnable doRun = new Runnable()
{
public void run()
{
try
{
ASyncOutputStream.this.out.close();
ASyncOutputStream.this.es.shutdown();
}
catch(Exception e)
{ /* Maybe you should handle theses exceptions by a UncaughtExceptionHandler */
e.printStackTrace();
}
}
};
// Execute and wait the sucess
Future future = this.es.submit(doRun);
try
{
future.get();
}
catch(Exception e){ e.printStackTrace(); }
}
/**
* Flushes this output stream and forces any buffered output bytes
* to be written out. The general contract of <code>flush</code> is
* that calling it is an indication that, if any bytes previously
* written have been buffered by the implementation of the output
* stream, such bytes should immediately be written to their
* intended destination.
* <p>
* If the intended destination of this stream is an abstraction provided by
* the underlying operating system, for example a file, then flushing the
* stream guarantees only that bytes previously written to the stream are
* passed to the operating system for writing; it does not guarantee that
* they are actually written to a physical device such as a disk drive.
* <p>
* The <code>flush</code> method of <code>OutputStream</code> does nothing.
*
*
* @exception IOException if an I/O error occurs.
*/
public void flush() throws IOException {
super.flush();
Runnable doRun = new Runnable()
{
public void run()
{
try
{
ASyncOutputStream.this.out.flush();
}
catch(Exception e)
{ /* Maybe you should handle theses exceptions by a UncaughtExceptionHandler */
e.printStackTrace();
}
}
};
this.es.execute(doRun);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try
{
BufferedOutputStream bos = new BufferedOutputStream( new ASyncOutputStream( new FileOutputStream( "c:\\Test.txt" ) ) );
bos.write( "A first line".getBytes() );
bos.write( "A second one".getBytes() );
bos.write( "the last one".getBytes() );
bos.close();
}
catch(Exception e){ e.printStackTrace(); }
}
} |
Partager