View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.Closeable;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.OutputStream;
30  import java.io.PrintWriter;
31  import java.io.Reader;
32  import java.io.StringWriter;
33  import java.io.Writer;
34  import java.nio.ByteBuffer;
35  import java.nio.channels.GatheringByteChannel;
36  import java.nio.charset.Charset;
37  
38  import org.eclipse.jetty.util.log.Log;
39  import org.eclipse.jetty.util.log.Logger;
40  
41  /* ======================================================================== */
42  /** IO Utilities.
43   * Provides stream handling utilities in
44   * singleton Threadpool implementation accessed by static members.
45   */
46  public class IO
47  {
48      private static final Logger LOG = Log.getLogger(IO.class);
49  
50      /* ------------------------------------------------------------------- */
51      public final static String
52          CRLF      = "\015\012";
53  
54      /* ------------------------------------------------------------------- */
55      public final static byte[]
56          CRLF_BYTES    = {(byte)'\015',(byte)'\012'};
57  
58      /* ------------------------------------------------------------------- */
59      public static final int bufferSize = 64*1024;
60  
61      /* ------------------------------------------------------------------- */
62      static class Job implements Runnable
63      {
64          InputStream in;
65          OutputStream out;
66          Reader read;
67          Writer write;
68  
69          Job(InputStream in,OutputStream out)
70          {
71              this.in=in;
72              this.out=out;
73              this.read=null;
74              this.write=null;
75          }
76          Job(Reader read,Writer write)
77          {
78              this.in=null;
79              this.out=null;
80              this.read=read;
81              this.write=write;
82          }
83  
84          /* ------------------------------------------------------------ */
85          /*
86           * @see java.lang.Runnable#run()
87           */
88          public void run()
89          {
90              try {
91                  if (in!=null)
92                      copy(in,out,-1);
93                  else
94                      copy(read,write,-1);
95              }
96              catch(IOException e)
97              {
98                  LOG.ignore(e);
99                  try{
100                     if (out!=null)
101                         out.close();
102                     if (write!=null)
103                         write.close();
104                 }
105                 catch(IOException e2)
106                 {
107                     LOG.ignore(e2);
108                 }
109             }
110         }
111     }
112 
113     /* ------------------------------------------------------------------- */
114     /** Copy Stream in to Stream out until EOF or exception.
115      * @param in the input stream to read from (until EOF)
116      * @param out the output stream to write to
117      * @throws IOException if unable to copy streams
118      */
119     public static void copy(InputStream in, OutputStream out)
120          throws IOException
121     {
122         copy(in,out,-1);
123     }
124 
125     /* ------------------------------------------------------------------- */
126     /** Copy Reader to Writer out until EOF or exception.
127      * @param in the read to read from (until EOF)
128      * @param out the writer to write to
129      * @throws IOException if unable to copy the streams
130      */
131     public static void copy(Reader in, Writer out)
132          throws IOException
133     {
134         copy(in,out,-1);
135     }
136 
137     /* ------------------------------------------------------------------- */
138     /** Copy Stream in to Stream for byteCount bytes or until EOF or exception.
139      * @param in the stream to read from
140      * @param out the stream to write to
141      * @param byteCount the number of bytes to copy
142      * @throws IOException if unable to copy the streams
143      */
144     public static void copy(InputStream in,
145                             OutputStream out,
146                             long byteCount)
147          throws IOException
148     {
149         byte buffer[] = new byte[bufferSize];
150         int len=bufferSize;
151 
152         if (byteCount>=0)
153         {
154             while (byteCount>0)
155             {
156                 int max = byteCount<bufferSize?(int)byteCount:bufferSize;
157                 len=in.read(buffer,0,max);
158 
159                 if (len==-1)
160                     break;
161 
162                 byteCount -= len;
163                 out.write(buffer,0,len);
164             }
165         }
166         else
167         {
168             while (true)
169             {
170                 len=in.read(buffer,0,bufferSize);
171                 if (len<0 )
172                     break;
173                 out.write(buffer,0,len);
174             }
175         }
176     }
177 
178     /* ------------------------------------------------------------------- */
179     /** Copy Reader to Writer for byteCount bytes or until EOF or exception.
180      * @param in the Reader to read from
181      * @param out the Writer to write to
182      * @param byteCount the number of bytes to copy
183      * @throws IOException if unable to copy streams
184      */
185     public static void copy(Reader in,
186                             Writer out,
187                             long byteCount)
188          throws IOException
189     {
190         char buffer[] = new char[bufferSize];
191         int len=bufferSize;
192 
193         if (byteCount>=0)
194         {
195             while (byteCount>0)
196             {
197                 if (byteCount<bufferSize)
198                     len=in.read(buffer,0,(int)byteCount);
199                 else
200                     len=in.read(buffer,0,bufferSize);
201 
202                 if (len==-1)
203                     break;
204 
205                 byteCount -= len;
206                 out.write(buffer,0,len);
207             }
208         }
209         else if (out instanceof PrintWriter)
210         {
211             PrintWriter pout=(PrintWriter)out;
212             while (!pout.checkError())
213             {
214                 len=in.read(buffer,0,bufferSize);
215                 if (len==-1)
216                     break;
217                 out.write(buffer,0,len);
218             }
219         }
220         else
221         {
222             while (true)
223             {
224                 len=in.read(buffer,0,bufferSize);
225                 if (len==-1)
226                     break;
227                 out.write(buffer,0,len);
228             }
229         }
230     }
231 
232     /* ------------------------------------------------------------ */
233     /** Copy files or directories
234      * @param from the file to copy
235      * @param to the destination to copy to
236      * @throws IOException if unable to copy
237      */
238     public static void copy(File from,File to) throws IOException
239     {
240         if (from.isDirectory())
241             copyDir(from,to);
242         else
243             copyFile(from,to);
244     }
245 
246     /* ------------------------------------------------------------ */
247     public static void copyDir(File from,File to) throws IOException
248     {
249         if (to.exists())
250         {
251             if (!to.isDirectory())
252                 throw new IllegalArgumentException(to.toString());
253         }
254         else
255             to.mkdirs();
256 
257         File[] files = from.listFiles();
258         if (files!=null)
259         {
260             for (int i=0;i<files.length;i++)
261             {
262                 String name = files[i].getName();
263                 if (".".equals(name) || "..".equals(name))
264                     continue;
265                 copy(files[i],new File(to,name));
266             }
267         }
268     }
269 
270     /* ------------------------------------------------------------ */
271     public static void copyFile(File from,File to) throws IOException
272     {
273         try (InputStream in=new FileInputStream(from);
274                 OutputStream out=new FileOutputStream(to))
275         {
276             copy(in,out);
277         }
278     }
279 
280     /* ------------------------------------------------------------ */
281     /** Read input stream to string.
282      * @param in the stream to read from (until EOF)
283      * @return the String parsed from stream (default Charset)
284      * @throws IOException if unable to read the stream (or handle the charset)
285      */
286     public static String toString(InputStream in)
287         throws IOException
288     {
289         return toString(in,(Charset)null);
290     }
291 
292     /* ------------------------------------------------------------ */
293     /** Read input stream to string.
294      * @param in the stream to read from (until EOF)
295      * @param encoding the encoding to use (can be null to use default Charset)
296      * @return the String parsed from the stream
297      * @throws IOException if unable to read the stream (or handle the charset)
298      */
299     public static String toString(InputStream in,String encoding)
300         throws IOException
301     {
302         return toString(in, encoding==null?null:Charset.forName(encoding));
303     }
304 
305     /** Read input stream to string.
306      * @param in the stream to read from (until EOF)
307      * @param encoding the Charset to use (can be null to use default Charset)
308      * @return the String parsed from the stream
309      * @throws IOException if unable to read the stream (or handle the charset)
310      */
311     public static String toString(InputStream in, Charset encoding)
312             throws IOException
313     {
314         StringWriter writer=new StringWriter();
315         InputStreamReader reader = encoding==null?new InputStreamReader(in):new InputStreamReader(in,encoding);
316 
317         copy(reader,writer);
318         return writer.toString();
319     }
320 
321     /* ------------------------------------------------------------ */
322     /** Read input stream to string.
323      * @param in the reader to read from (until EOF)
324      * @return the String parsed from the reader
325      * @throws IOException if unable to read the stream (or handle the charset)
326      */
327     public static String toString(Reader in)
328         throws IOException
329     {
330         StringWriter writer=new StringWriter();
331         copy(in,writer);
332         return writer.toString();
333     }
334 
335 
336     /* ------------------------------------------------------------ */
337     /** Delete File.
338      * This delete will recursively delete directories - BE CAREFULL
339      * @param file The file (or directory) to be deleted.
340      * @return true if anything was deleted. (note: this does not mean that all content in a directory was deleted)
341      */
342     public static boolean delete(File file)
343     {
344         if (!file.exists())
345             return false;
346         if (file.isDirectory())
347         {
348             File[] files = file.listFiles();
349             for (int i=0;files!=null && i<files.length;i++)
350                 delete(files[i]);
351         }
352         return file.delete();
353     }
354 
355     /**
356      * Closes an arbitrary closable, and logs exceptions at ignore level
357      *
358      * @param closeable the closeable to close
359      */
360     public static void close(Closeable closeable)
361     {
362         try
363         {
364             if (closeable != null)
365                 closeable.close();
366         }
367         catch (IOException ignore)
368         {
369             LOG.ignore(ignore);
370         }
371     }
372 
373     /**
374      * closes an input stream, and logs exceptions
375      *
376      * @param is the input stream to close
377      */
378     public static void close(InputStream is)
379     {
380         close((Closeable)is);
381     }
382 
383     /**
384      * closes an output stream, and logs exceptions
385      *
386      * @param os the output stream to close
387      */
388     public static void close(OutputStream os)
389     {
390         close((Closeable)os);
391     }
392 
393     /**
394      * closes a reader, and logs exceptions
395      *
396      * @param reader the reader to close
397      */
398     public static void close(Reader reader)
399     {
400         close((Closeable)reader);
401     }
402 
403     /**
404      * closes a writer, and logs exceptions
405      *
406      * @param writer the writer to close
407      */
408     public static void close(Writer writer)
409     {
410         close((Closeable)writer);
411     }
412 
413     /* ------------------------------------------------------------ */
414     public static byte[] readBytes(InputStream in)
415         throws IOException
416     {
417         ByteArrayOutputStream bout = new ByteArrayOutputStream();
418         copy(in,bout);
419         return bout.toByteArray();
420     }
421 
422     /* ------------------------------------------------------------ */
423     /**
424      * A gathering write utility wrapper.
425      * <p>
426      * This method wraps a gather write with a loop that handles the limitations of some operating systems that have a
427      * limit on the number of buffers written. The method loops on the write until either all the content is written or
428      * no progress is made.
429      *
430      * @param out
431      *            The GatheringByteChannel to write to
432      * @param buffers
433      *            The buffers to write
434      * @param offset
435      *            The offset into the buffers array
436      * @param length
437      *            The length in buffers to write
438      * @return The total bytes written
439      * @throws IOException
440      *             if unable write to the GatheringByteChannel
441      */
442     public static long write(GatheringByteChannel out, ByteBuffer[] buffers, int offset, int length) throws IOException
443     {
444         long total=0;
445         write: while (length>0)
446         {
447             // Write as much as we can
448             long wrote=out.write(buffers,offset,length);
449 
450             // If we can't write any more, give up
451             if (wrote==0)
452                 break;
453 
454             // count the total
455             total+=wrote;
456 
457             // Look for unwritten content
458             for (int i=offset;i<buffers.length;i++)
459             {
460                 if (buffers[i].hasRemaining())
461                 {
462                     // loop with new offset and length;
463                     length=length-(i-offset);
464                     offset=i;
465                     continue write;
466                 }
467             }
468             length=0;
469         }
470 
471         return total;
472     }
473 
474     /* ------------------------------------------------------------ */
475     /**
476      * @return An outputstream to nowhere
477      */
478     public static OutputStream getNullStream()
479     {
480         return __nullStream;
481     }
482 
483     /* ------------------------------------------------------------ */
484     /**
485      * @return An outputstream to nowhere
486      */
487     public static InputStream getClosedStream()
488     {
489         return __closedStream;
490     }
491 
492     /* ------------------------------------------------------------ */
493     /* ------------------------------------------------------------ */
494     private static class NullOS extends OutputStream
495     {
496         @Override
497         public void close(){}
498         @Override
499         public void flush(){}
500         @Override
501         public void write(byte[]b){}
502         @Override
503         public void write(byte[]b,int i,int l){}
504         @Override
505         public void write(int b){}
506     }
507     private static NullOS __nullStream = new NullOS();
508 
509 
510     /* ------------------------------------------------------------ */
511     /* ------------------------------------------------------------ */
512     private static class ClosedIS extends InputStream
513     {
514         @Override
515         public int read() throws IOException
516         {
517             return -1;
518         }
519     }
520     private static ClosedIS __closedStream = new ClosedIS();
521 
522     /* ------------------------------------------------------------ */
523     /**
524      * @return An writer to nowhere
525      */
526     public static Writer getNullWriter()
527     {
528         return __nullWriter;
529     }
530 
531     /* ------------------------------------------------------------ */
532     /**
533      * @return An writer to nowhere
534      */
535     public static PrintWriter getNullPrintWriter()
536     {
537         return __nullPrintWriter;
538     }
539 
540     /* ------------------------------------------------------------ */
541     /* ------------------------------------------------------------ */
542     private static class NullWrite extends Writer
543     {
544         @Override
545         public void close(){}
546         @Override
547         public void flush(){}
548         @Override
549         public void write(char[]b){}
550         @Override
551         public void write(char[]b,int o,int l){}
552         @Override
553         public void write(int b){}
554         @Override
555         public void write(String s){}
556         @Override
557         public void write(String s,int o,int l){}
558     }
559     private static NullWrite __nullWriter = new NullWrite();
560     private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter);
561 
562 }
563 
564 
565 
566 
567 
568 
569 
570 
571