root/trunk/src/java/org/jcoderz/commons/util/IoUtil.java

Revision 1638, 12.1 kB (checked in by mgriffel, 17 months ago)

Added new method IoUtil#skip(). Wraps strange InputStream#skip?() that violates the POLA.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.commons.util;
34
35import java.io.ByteArrayOutputStream;
36import java.io.EOFException;
37import java.io.File;
38import java.io.FileInputStream;
39import java.io.FileOutputStream;
40import java.io.IOException;
41import java.io.InputStream;
42import java.io.OutputStream;
43import java.io.RandomAccessFile;
44import java.io.Reader;
45import java.io.StringWriter;
46import java.io.Writer;
47import java.net.Socket;
48import java.nio.channels.Channel;
49import java.util.logging.Level;
50import java.util.logging.Logger;
51
52/**
53 * Collects some I/O utility functions.
54 *
55 * @author Michael Griffel
56 * @author Andreas Mandel
57 */
58public final class IoUtil
59{
60   /** class name for use in logger */
61   private static final String CLASSNAME = IoUtil.class.getName();
62
63   /** logging facility */
64   private static final Logger logger = Logger.getLogger(CLASSNAME);
65
66   private static final int BUFFER_SIZE = 4096;
67
68   /**
69    * Constructor.
70    */
71   private IoUtil ()
72   {
73      // Utility class -- only static methods
74   }
75
76   /**
77    * Closes the input stream (safe).
78    *
79    * This method tries to close the given input stream and
80    * if an IOException occurs a message with the level
81    * {@link Level#FINE} is logged. It's safe to pass a
82    * <code>null</code> reference for the argument.
83    *
84    * @param in the input stream that should be closed.
85    */
86   public static void close (InputStream in)
87   {
88      if (in != null)
89      {
90         try
91         {
92            in.close();
93         }
94         catch (IOException x)
95         {
96            logCloseFailedWarningMessage(
97                  InputStream.class, in.getClass(), x);
98         }
99      }
100   }
101
102   /**
103    * Closes the output stream (safe).
104    *
105    * This method tries to close the given output stream and
106    * if an IOException occurs a message with the level
107    * {@link Level#FINE} is logged. It's safe to pass a
108    * <code>null</code> reference for the argument.
109    *
110    * @param out the output stream that should be closed.
111    */
112   public static void close (OutputStream out)
113   {
114      if (out != null)
115      {
116         try
117         {
118            out.close();
119         }
120         catch (IOException x)
121         {
122            logCloseFailedWarningMessage(
123                  OutputStream.class, out.getClass(), x);
124         }
125      }
126   }
127
128   /**
129    * Closes the reader (safe).
130    *
131    * This method tries to close the given reader and if an IOException occurs
132    * a message with the level {@link Level#FINE} is logged. It's safe
133    * to pass a <code>null</code> reference for the argument.
134    *
135    * @param reader the reader that should be closed.
136    */
137   public static void close (Reader reader)
138   {
139      if (reader != null)
140      {
141         try
142         {
143            reader.close();
144         }
145         catch (IOException x)
146         {
147            logCloseFailedWarningMessage(
148                  Reader.class, reader.getClass(), x);
149         }
150      }
151   }
152
153   /**
154    * Closes the RandomAccessFile (safe).
155    *
156    * This method tries to close the given RandomAccessFile and if an
157    * IOException occurs a message with the level {@link Level#FINE}
158    * is logged. It's safe to pass a <code>null</code> reference
159    * for the argument.
160    *
161    * @param randomAccessFile the randomAccessFile that should be closed.
162    */
163   public static void close (RandomAccessFile randomAccessFile)
164   {
165      if (randomAccessFile != null)
166      {
167         try
168         {
169            randomAccessFile.close();
170         }
171         catch (IOException x)
172         {
173            logCloseFailedWarningMessage(
174                  Reader.class, randomAccessFile.getClass(), x);
175         }
176      }
177   }
178
179   /**
180    * Closes the writer (safe).
181    *
182    * This method tries to close the given writer and if an IOException occurs
183    * a message with the level {@link Level#FINE} is logged. It's safe
184    * to pass a <code>null</code> reference for the argument.
185    *
186    * @param writer the writer that should be closed.
187    */
188   public static void close (Writer writer)
189   {
190      if (writer != null)
191      {
192         try
193         {
194            writer.close();
195         }
196         catch (IOException x)
197         {
198            logCloseFailedWarningMessage(
199                  Writer.class, writer.getClass(), x);
200         }
201      }
202   }
203
204   /**
205    * Closes the channel (safe).
206    *
207    * This method tries to close the given channel and if an IOException occurs
208    * a message with the level {@link Level#FINE} is logged. It's safe
209    * to pass a <code>null</code> reference for the argument.
210    *
211    * @param channel the channel that should be closed.
212    */
213   public static void close (Channel channel)
214   {
215      if (channel != null)
216      {
217         try
218         {
219            channel.close();
220         }
221         catch (IOException x)
222         {
223            logCloseFailedWarningMessage(Channel.class, channel.getClass(), x);
224         }
225      }
226   }
227
228   /**
229    * Closes the socket (safe).
230    *
231    * This method tries to close the given socket and if an IOException occurs
232    * a message with the level {@link Level#FINE} is logged. It's safe
233    * to pass a <code>null</code> reference for the argument.
234    *
235    * @param socket the socket that should be closed.
236    */
237   public static void close (Socket socket)
238   {
239      if (socket != null)
240      {
241         try
242         {
243             socket.close();
244         }
245         catch (IOException x)
246         {
247            logCloseFailedWarningMessage(Channel.class, socket.getClass(), x);
248         }
249      }
250   }
251
252   /**
253    * Reads <code>expectedLength</code> bytes from the input
254    * stream <code>in</code>.
255    *
256    * @param in the input stream to read from.
257    * @param expectedLength the expected size.
258    * @return an byte array with <code>expectedLength</code> bytes.
259    * @throws IOException in an I/O error occurs or if the read size is not the
260    *       expected size.
261    */
262   public static byte[] readFully (InputStream in, int expectedLength)
263         throws IOException
264   {
265      final byte[] buffer = new byte[expectedLength];
266      int pos = 0;
267      int read = 0;
268
269      while ((read = in.read(buffer, pos, expectedLength - pos)) >= 0)
270      {
271         pos += read;
272         if (expectedLength == pos)
273         {
274            break;
275         }
276      }
277
278      if (expectedLength != pos)
279      {
280         throw new IOException(
281               "Buffer underread. Could not read " + expectedLength
282               + " bytes from stream. Expected was " + expectedLength
283               + " bytes, but got only " + pos + " bytes");
284      }
285
286      return buffer;
287   }
288
289   /**
290    * Reads all bytes from the input stream <code>in</code>.
291    *
292    * @param in the input stream to read from.
293    * @return an byte array with read bytes.
294    * @throws IOException in an I/O error occurs.
295    */
296   public static byte[] readFully (InputStream in)
297         throws IOException
298   {
299      final byte[] buffer = new byte[BUFFER_SIZE];
300      int read = 0;
301      final ByteArrayOutputStream out = new ByteArrayOutputStream();
302
303      while ((read = in.read(buffer)) >= 0)
304      {
305         out.write(buffer, 0, read);
306      }
307
308      return out.toByteArray();
309   }
310
311   /**
312    * Reads all characters from the reader <code>in</code>.
313    *
314    * @param in the Reader to read from.
315    * @return an String containing the read data
316    * @throws IOException in an I/O error occurs.
317    */
318   public static String readFully (Reader in)
319         throws IOException
320   {
321      final char[] buffer = new char[BUFFER_SIZE];
322      int read = 0;
323      final StringWriter out = new StringWriter();
324
325      while ((read = in.read(buffer)) >= 0)
326      {
327         out.write(buffer, 0, read);
328      }
329
330      return out.toString();
331   }
332
333
334   /**
335    * Reads all characters from the reader <code>in</code> and
336    * normalizes newlines to single '\n'.
337    *
338    * @param in the Reader to read from.
339    * @return an String containing the read data
340    * @throws IOException in an I/O error occurs.
341    */
342   public static String readFullyNormalizeNewLine (Reader in)
343         throws IOException
344   {
345      final StringWriter out = new StringWriter();
346
347      int c;
348      int last = 0;
349      while ((c = in.read()) != -1)
350      {
351         if (c == '\n')
352         {
353             if (last != '\r')
354             {
355                 out.write(c);
356             }
357         }
358         else if (c == '\r' || c == '\u0085' 
359             || c == '\u2028' || c == '\u2029')
360         {
361             if (last != '\n')
362             {
363                 out.write('\n');
364             }
365         }
366         else
367         {
368             out.write(c);
369         }
370         last = c;
371      }
372
373      return out.toString();
374   }
375
376   /**
377    * Reads all data from in and copies it to the out stream.
378    * @param in the stream to read.
379    * @param out the stream to write.
380    * @throws IOException if an I/O issue occurs.
381    */
382   public static void copy (InputStream in, OutputStream out)
383         throws IOException
384   {
385      final byte[] buffer = new byte[BUFFER_SIZE];
386      int read;
387
388      while ((read = in.read(buffer)) >= 0)
389      {
390         out.write(buffer, 0, read);
391      }
392   }
393
394   /**
395    * Copies file <tt>src</tt> to file <tt>dest</tt>.
396    * @param src the source file.
397    * @param dest the destination file.
398    * @throws IOException if an I/O issue occurs.
399    */
400   public static void copy (File src, File dest)
401         throws IOException
402   {
403      final InputStream in = new FileInputStream(src);
404      try
405      {
406          final OutputStream out = new FileOutputStream(dest);
407          try
408          {
409             copy(in, out);
410          }
411          finally
412          {
413             close(out);
414          }
415      }
416      finally
417      {
418         close(in);
419      }
420   }
421   
422   /**
423    * Ensures that the given number of bytes are skipped from the given
424    * input stream.
425    * @param in the input stream.
426    * @param bytes the number of bytes to skip.
427    * @throws IOException if the stream does not support seek,
428    *              or if some other I/O error occurs.
429    * @see InputStream#skip             
430    */
431    public static void skip (InputStream in, int bytes)
432        throws IOException
433    {
434        long remaining = bytes;
435        while (remaining != 0)
436        {
437            final long skipped = in.skip(remaining);
438            if (skipped == 0)
439            {
440                throw new EOFException();
441            }
442            remaining -= skipped;
443        }
444    }
445
446
447   private static void logCloseFailedWarningMessage (
448         Class resource, Class clazz, IOException x)
449   {
450      logger.log(Level.FINE, "Error while closing " + resource.getName() + ": "
451            + clazz.getName() + ".close()", x);
452   }
453
454}
Note: See TracBrowser for help on using the browser.