// ===========================================================================
// CONTENT : CLASS FileUtil
// AUTHOR : Manfred Duchrow
// VERSION : 1.1 - 14/03/2003
// HISTORY :
// 17/05/2002 duma CREATED
// 14/03/2003 duma added -> standardize(), javaFilename()
//
// Copyright (c) 2002-2003, by Manfred Duchrow. All rights reserved.
// ===========================================================================
package org.pf.file ;
// ===========================================================================
// IMPORTS
// ===========================================================================
import java.io.* ;
import org.pf.text.StringUtil;
/**
* This class provides helper methods for file and stream handling.
* It's an add-on to the java.io package.
* The service is implemented as a singleton, so use the
* <b>FileUtil.current()</b> method to get the sole instance.
*
* @author Manfred Duchrow
* @version 1.1
*/
public class FileUtil
{
// =========================================================================
// CONSTANTS
// =========================================================================
/** The lines.separator from the system properties as a constant */
public static final String LINE_SEPARATOR = System.getProperty( "line.separator" ) ;
protected static final int DEFAULT_BUFFER_SIZE = 1024 ;
// =========================================================================
// CLASS VARIABLES
// =========================================================================
private static FileUtil current = new FileUtil() ;
// =========================================================================
// CLASS METHODS
// =========================================================================
// =========================================================================
// CONSTRUCTORS
// =========================================================================
/**
* Initialize the new instance with default values.
*/
private FileUtil()
{
super() ;
} // FileUtil()
// =========================================================================
// PUBLIC CLASS METHODS
// =========================================================================
public static FileUtil current()
{
return current ;
} // current()
// =========================================================================
// PUBLIC INSTANCE METHODS
// =========================================================================
/**
* Copies all data from the iniput stream to the output stream using
* a buffer with the default size (1024 bytes).
* After all data is copied both streams will be closed !
*/
public void copyStream( InputStream inStream, OutputStream outStream )
throws IOException
{
this.copyStream( inStream, outStream, DEFAULT_BUFFER_SIZE ) ;
} // copyStream()
// -------------------------------------------------------------------------
/**
* Copies all data from the iniput stream to the output stream using
* a buffer of the given size in bytes.
* After all data is copied both streams will be closed !
*/
public void copyStream( InputStream inStream, OutputStream outStream,
int bufSize )
throws IOException
{
byte[] buffer = new byte[bufSize] ;
int count ;
try
{
count = inStream.read(buffer) ;
while ( count > -1 )
{
outStream.write( buffer, 0, count ) ;
count = inStream.read(buffer) ;
}
}
finally
{
this.close(inStream) ;
this.close(outStream) ;
}
} // copyStream()
// -------------------------------------------------------------------------
/**
* Reads the whole content of the given input stream and returns
* it as a string.
* The stream will be closed after calling this method. Even if an exception
* occured!
*
* @param inStream The input stream to read
* @return The text content of the given stream
*/
public String readTextFrom( InputStream inStream )
throws IOException
{
StringWriter writer ;
writer = new StringWriter( 1024 ) ;
this.copyText( inStream, writer ) ;
return writer.toString() ;
} // readTextFrom()
// -------------------------------------------------------------------------
/**
* Reads the whole content of the file with the given name and returns
* it as a string.
*
* @param filename The name of the text containing file
*/
public String readTextFrom( String filename )
throws IOException
{
FileInputStream inStream ;
inStream = new FileInputStream( filename ) ;
return this.readTextFrom( inStream ) ;
} // readTextFrom()
// -------------------------------------------------------------------------
/**
* Reads the whole content of the specified file and returns
* it as a string.
*/
public String readTextFrom( File file )
throws IOException
{
FileInputStream inStream ;
inStream = new FileInputStream( file ) ;
return this.readTextFrom( inStream ) ;
} // readTextFrom()
// -------------------------------------------------------------------------
/**
* Copies all text lines from the specified reader to the given writer.
* After that the reader will be closed. Even if an exception occurs.
*
* @param reader The reader which provides the text to copy
* @param writer The writer to which the text will be copied
*/
public void copyText( Reader reader, final StringWriter writer )
throws IOException
{
BufferedReader bufReader ;
String line ;
LineProcessor processor ;
bufReader = new BufferedReader( reader ) ;
try
{
processor = new LineProcessor()
{
public boolean processLine( String line, int lineNo )
{
if ( lineNo > 1 )
writer.write( LINE_SEPARATOR ) ;
writer.write( line ) ;
return true ;
}
} ;
this.processTextLines( bufReader, processor ) ;
}
finally
{
bufReader.close() ;
}
} // copyText()
// ------------------------------------------------------------------------
/**
* Reads all text lines from the file with the specified name and passes them
* one by one to the given line processor.
* The processing will be terminated, if the end of the text is reached or
* if the processor returns <b>false</b>.<br>
*
* @param filename The name of the text file to read
* @param processor The processor that receives the lines from the text
*/
public void processTextLines( String filename, LineProcessor processor )
throws IOException
{
FileInputStream inStream ;
if ( filename == null )
throw new IllegalArgumentException( "filename must not be null" ) ;
inStream = new FileInputStream( filename ) ;
try{
this.processTextLines( inStream, processor ) ;
}finally{
inStream.close();
}
} // processTextLines()
// -------------------------------------------------------------------------
/**
* Reads all text lines from the specified input stream and passes them
* one by one to the given line processor.
* The processing will be terminated, if the end of the text is reached or
* if the processor returns <b>false</b>.<br>
* The given input stream will be closed after the execution of this method.
* Even if an exception occured.
*
* @param inStream The input stream that contains the text
* @param processor The processor that receives the lines from the text
*/
public void processTextLines( InputStream inStream, LineProcessor processor )
throws IOException
{
InputStreamReader reader ;
if ( inStream == null )
throw new IllegalArgumentException( "inStream must not be null" ) ;
reader = new InputStreamReader( inStream ) ;
this.processTextLines( reader, processor ) ;
} // processTextLines()
// -------------------------------------------------------------------------
/**
* Reads all text lines from the specified reader and passes them one by one
* to the given line processor.
* The processing will be terminated, if the end of the text is reached or
* if the processor returns <b>false</b>.
*
* @param reader The reader that contains a text stream
* @param processor The processor that receives the lines from the text
*/
public void processTextLines( Reader reader, LineProcessor processor )
throws IOException
{
BufferedReader bufReader ;
String line ;
int counter = 0 ;
boolean continue_reading = true ;
if ( reader == null )
throw new IllegalArgumentException( "reader must not be null" ) ;
if ( processor == null )
throw new IllegalArgumentException( "processor must not be null" ) ;
bufReader = new BufferedReader( reader ) ;
while ( continue_reading && bufReader.ready() )
{
line = bufReader.readLine() ;
if ( line == null )
break ;
counter++ ;
continue_reading = processor.processLine( line, counter ) ;
}
} // processTextLines()
// ------------------------------------------------------------------------
/**
* Close the given stream ignoring any exception.
* Returns true, if the stream was closed successfully, false otherwise
*/
public boolean close( InputStream stream )
{
if ( stream == null )
{
return false ;
}
try
{
stream.close() ;
return true ;
}
catch (IOException e)
{
return false ;
}
} // close()
// -------------------------------------------------------------------------
/**
* Close the given stream ignoring any exception.
* Returns true, if the stream was closed successfully, false otherwise
*/
public boolean close( OutputStream stream )
{
if ( stream == null )
{
return false ;
}
try
{
stream.close() ;
return true ;
}
catch (IOException e)
{
return false ;
}
} // close()
// -------------------------------------------------------------------------
/**
* Convert the filename to a canonical (see java.io.File.getCanonicalPath())
* format and replace any backslashes '\' by slashes ('/').
* If possible all "." and ".." elements in the path are eliminated.
*
* @param filename The filename which has to be standardized
* @return An absolute filename that uses slashes to separate its elements
*/
public String standardize( String filename )
{
if ( filename == null )
return null ;
return this.standardizeFilename( filename ) ;
} // standardize()
// -------------------------------------------------------------------------
/**
* Returns the given filename in the platform independent way that Java
* understands. That is all elements are separated by a forward slash rather
* than back slashes as on Windows systems.
*
* @param filename The name to be modified
*/
public String javaFilename( String filename )
{
if ( filename == null )
return null ;
return filename.replace( '\\', '/' ) ;
} // javaFilename()
// -------------------------------------------------------------------------
// =========================================================================
// PROTECTED INSTANCE METHODS
// =========================================================================
protected void copyText( InputStream inStream, StringWriter writer )
throws IOException
{
this.copyText( new InputStreamReader( inStream ), writer ) ;
} // copyText()
// ------------------------------------------------------------------------
protected String standardizeFilename( String filename )
{
String[] nameElements ;
boolean hasDriveLetter ;
boolean startedFromRoot ;
boolean isAbsolute ;
int index ;
filename = this.javaFilename(filename) ;
startedFromRoot = filename.startsWith( "/" ) ;
nameElements = this.str().parts( filename, "/" ) ;
if ( nameElements.length > 0 )
{
hasDriveLetter = nameElements[0].endsWith( ":" ) ;
if ( hasDriveLetter )
{
nameElements[0] = nameElements[0].toUpperCase() ;
}
else
{
if ( startedFromRoot )
{
nameElements = this.str().append( new String[] { "" }, nameElements );
}
}
isAbsolute = hasDriveLetter || startedFromRoot ;
for (int i = 0; i < nameElements.length; i++)
{
if ( ".".equals( nameElements[i] ) )
{
nameElements[i] = null ;
}
else
{
if ( "..".equals( nameElements[i] ) )
{
index = this.indexOfPreceedingNotNullElement( nameElements, i-1 ) ;
if ( index >= 0 )
{
if ( ( index > 0 ) || ( ! isAbsolute ) )
{
nameElements[i] = null ;
nameElements[index] = null ;
}
}
}
}
}
nameElements = this.str().removeNull( nameElements ) ;
return this.str().asString( nameElements, "/" ) ;
}
else
{
return "" ;
}
} // standardizeFilename()
// -------------------------------------------------------------------------
protected int indexOfPreceedingNotNullElement( String[] elements, int start )
{
for (int i = start; i >= 0 ; i--)
{
if ( elements[i] != null )
{
if ( "..".equals( elements[i] ) ) // This is not a valid not null element
{
return -1 ;
}
else
{
return i ;
}
}
}
return -1 ;
} // indexOfPreceedingNotNullElement()
// -------------------------------------------------------------------------
protected StringUtil str()
{
return StringUtil.current() ;
} // str()
// -------------------------------------------------------------------------
} // class FileUtil