001    package org.rakeshv.io;
002    
003    import java.io.BufferedOutputStream;
004    import java.io.File;
005    import java.io.FileNotFoundException;
006    import java.io.FileOutputStream;
007    import java.io.IOException;
008    import java.io.InputStream;
009    
010    import java.util.Date;
011    
012    /**
013     * A utility class that provides <code>static</code> methods for
014     * common IO operations.
015     *
016     * <p>&copy; Copyright 2005, Rakesh Vidyadharan</p>
017     * @author Rakesh Vidyadharan 17<sup><small>th</small></sup> September 2005
018     *
019     * @version $Id: FileUtilities.java,v 1.3 2005/10/18 01:36:24 rakesh Exp $
020     */
021    public final class FileUtilities extends Object 
022    {
023      /**
024       * Default constructor.  Cannot be instantiated.
025       */
026      private FileUtilities()
027      {
028        super();
029      }
030    
031      /**
032       * Delete all the files and directories under the specified directory.
033       * Invokes {@link #delete( File, boolean )} with a new <code>File
034       * </code> representing the specified <code>directory</code>.
035       *
036       * @param directory The directory whose children are to be deleted.
037       * @param deleteDirectory Specify <code>true</code> if you wish to
038       *   delete the specified directory as well.  Specify <code>false
039       *   </code> if you wish to preserve the specified directory.
040       * @return int - Returns the total number of files and directories
041       *   that were deleted.
042       * @throws SecurityException If the <code>SecurityManager</code>
043       *   prevented the directory or its children from being deleted.
044       */
045      public static int delete( String directory, boolean deleteDirectory ) 
046        throws SecurityException
047      {
048        return delete( new File( directory ), deleteDirectory );
049      }
050    
051      /**
052       * Delete all the files and directories under the specified directory.
053       *
054       * @see #delete( File )
055       * @param directory The directory whose children are to be deleted.
056       * @param deleteDirectory Specify <code>true</code> if you wish to
057       *   delete the specified directory as well.  Specify <code>false
058       *   </code> if you wish to preserve the specified directory.
059       * @return int - Returns the total number of files and directories
060       *   that were deleted.
061       * @throws SecurityException If the <code>SecurityManager</code>
062       *   prevented the directory or its children from being deleted.
063       */
064      public static int delete( File directory, boolean deleteDirectory ) 
065        throws SecurityException
066      {
067        int total = 0;
068    
069        if ( directory.isFile() )
070        {
071          if ( FileUtilities.delete( directory ) )
072          {
073            ++total;
074          }
075        }
076        else
077        {
078          File[] children = directory.listFiles();
079          if ( children != null )
080          {
081            for ( int i = 0; i < children.length; ++i )
082            {
083              if ( children[i].isDirectory() )
084              {
085                total += FileUtilities.delete( children[i], true );
086              }
087              else
088              {
089                if( FileUtilities.delete( children[i] ) )
090                {
091                  ++total;
092                }
093              }
094            }
095          }
096          else
097          {
098            System.err.println( new Date() + 
099                "  WARNING  org.rakeshv.io.FileUtilities.delete. " +
100                "Unable to list children for directory " + 
101                directory.getAbsolutePath() );
102          }
103        }
104    
105        if ( deleteDirectory )
106        {
107          boolean result = directory.delete();
108          if ( ! result )
109          {
110            System.err.println( new Date() + 
111                "  WARNING  org.rakeshv.io.FileUtilities.delete. " +
112                "Unable to delete directory " + 
113                directory.getAbsolutePath() );
114          }
115          else
116          {
117            ++total;
118          }
119        }
120        
121        return total;
122      }
123    
124      /**
125       * Create the parent directory tree for the specified file if
126       * required.  Check the <code>parent</code> for existence and create 
127       * if required.
128       *
129       * @throws SecurityException If errors are encountered while creating 
130       *   the directory tree.
131       */
132      public static final void mkdirs( File file )
133      {
134        File parent = file.getParentFile();
135        if ( parent != null && ! parent.exists() )
136        {
137          parent.mkdirs();
138        }
139      }
140    
141      /**
142       * Read all the data from the specified <code>InputStream</code> and
143       * write them to the specified files.
144       *
145       * <p>The following code shows sample usage of this method.</p>
146       * <pre>
147       * import org.rakeshv.io.FileUtilities;
148       * import java.io.BufferedInputStream;
149       * import java.io.FileInputStream;
150       * 
151       * public class test
152       * {
153       *   public static void main( String[] args )
154       *   {
155       *     try
156       *     {
157       *       String[] names = {"/tmp/one.m4a", "/tmp/two.m4a", "/tmp/three.m4a"};
158       *       BufferedInputStream inputStream = new BufferedInputStream(
159       *           new FileInputStream( 
160       *             "/Users/rakesh/Desktop/AaraadayaManu.m4a" ) );
161       *       FileUtilities.writeToFiles( inputStream, names );
162       *     }
163       *     catch ( Throwable t )
164       *     {
165       *       t.printStackTrace();
166       *     }
167       *   }
168       * }
169       * </pre>
170       *
171       * @see TeeOutputStream#TeeOutputStream( String[] )
172       * @see #writeToFiles( InputStream, TeeOutputStream )
173       * @param inputStream The stream from which the data is to be read.
174       * @param names The fully qualified names of the files to which the
175       *   data read is to be written.
176       * @throws FileNotFoundException If the file(s) specified could not
177       *   be created.
178       * @throws IOException If errors are encountered while reading the
179       *   data from the <code>inputStream</code> or while writing to the
180       *   file(s).
181       */
182      public static final void writeToFiles( InputStream inputStream,
183          String[] names ) throws FileNotFoundException, IOException
184      {
185        TeeOutputStream tee = new TeeOutputStream( names );
186        writeToFiles( inputStream, tee );
187      }
188    
189      /**
190       * Read all the data from the specified <code>InputStream</code> and
191       * write them to the specified files.
192       *
193       * @see TeeOutputStream#TeeOutputStream( File[] )
194       * @see #writeToFiles( InputStream, TeeOutputStream )
195       * @param inputStream The stream from which the data is to be read.
196       * @param files The files to which the data read is to be written.
197       * @throws FileNotFoundException If the file(s) specified could not
198       *   be accessed.
199       * @throws IOException If errors are encountered while reading the
200       *   data from the <code>inputStream</code> or while writing to the
201       *   file(s).
202       */
203      public static final void writeToFiles( InputStream inputStream,
204          File[] files ) throws FileNotFoundException, IOException
205      {
206        TeeOutputStream tee = new TeeOutputStream( files );
207        writeToFiles( inputStream, tee );
208      }
209    
210      /**
211       * Read all the data from the specified <code>InputStream</code> and
212       * write them to the specified {@link TeeOutputStream}.
213       *
214       * @param inputStream The stream from which the data is to be read.
215       * @param tee The <code>tee</code> to which the data read is to be 
216       *   written.
217       * @throws IOException If errors are encountered while reading the
218       *   data from the <code>inputStream</code> or while writing to the
219       *   file(s).
220       */
221      private static final void writeToFiles( InputStream inputStream,
222          TeeOutputStream tee ) throws FileNotFoundException, IOException
223      {
224        byte[] buffer = new byte[ 8192 ];
225        int length = 0;
226    
227        while ( ( length = 
228              inputStream.read( buffer, 0, buffer.length ) ) != -1 )
229        {
230          tee.write( buffer, 0, length );
231        }
232    
233        tee.flush();
234        tee.close();
235      }
236    
237      /**
238       * Delete the specified file.  Log a message to <code>System.err
239       * </code> if errors were encountered while deleting the file.
240       *
241       * @param file The file which is to be deleted.
242       * @return boolean - Returns <code>false</code> if the file could
243       *   not be deleted.
244       * @throws SecurityException If the <code>SecurityManager</code>
245       *   prevented the file from being deleted.
246       */
247      private static boolean delete( File file ) throws SecurityException
248      {
249        boolean result = true;
250    
251        if ( ! file.delete() )
252        {
253          System.err.println( new Date() + 
254              "  WARNING  org.rakeshv.io.FileUtilities.delete. " +
255              "Unable to delete file " + file.getAbsolutePath() );
256          result = false;
257        }
258    
259        return result;
260      }
261    }