/* * Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved. * * This program and the accompanying materials are made available * under the terms of the Eclipse Public License, Version 1.0, * which accompanies this distribution and is available at * * http://www.eclipse.org/legal/epl-v10.html * */ package net.rim.ejde.internal.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import net.rim.ejde.internal.core.IConstants; import org.apache.log4j.Logger; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; /** * A utility class to manipulate files. * * @author dmeng */ public class FileUtils { private static final Logger log = Logger.getLogger( FileUtils.class ); /** * Copy the source file to the destination file. An <code>IllegalArgumentException</code> will be thrown if the destination * file exists. * * @param src * The source file * @param dest * The destination file * @throws IOException * Any error during file copy */ public static void copy( File src, File dest ) throws IOException { if( ( src == null ) || ( dest == null ) ) { log.error( "Source and Destination files cannot be null" ); //$NON-NLS-1$ throw new IllegalArgumentException( "Source and Destination files cannot be null" ); //$NON-NLS-1$ } if( !src.exists() || !src.canRead() || !src.isFile() ) { log.error( "Could not access or read file " + src ); //$NON-NLS-1$ throw new IllegalArgumentException( "Could not access or read file " + src ); //$NON-NLS-1$ } if( dest.exists() ) { log.error( "Destination file already exists: " + dest ); //$NON-NLS-1$ throw new IllegalArgumentException( "Destination file already exists: " + dest ); //$NON-NLS-1$ } FileInputStream inputStream = null; FileOutputStream outputStream = null; FileChannel inputChannel = null, outputChannel = null; try { inputStream = new FileInputStream( src ); outputStream = new FileOutputStream( dest ); inputChannel = inputStream.getChannel(); outputChannel = outputStream.getChannel(); long count = 0, size = inputChannel.size(); while( ( count += outputChannel.transferFrom( inputChannel, count, size - count ) ) < size ) ; } catch( Throwable e ) { log.error( e.getMessage(), e ); } finally {// just in case the Eclipse API doesn't close it for whatever // reason. try { if( null != inputStream ) inputStream.close(); if( outputStream != null ) { outputStream.close(); } } catch( Throwable e ) { ; log.error( e.getMessage(), e ); } } } /** * Copy the source file to the destination file. An <code>IllegalArgumentException</code> will be thrown if the destination * file exists. * * @param inputStream * the input stream that acts as a source * @param dest * The destination file * * @throws IOException * Any error during file copy */ public static void copy( InputStream inputStream, File dest ) throws IOException { if( ( inputStream == null ) || ( dest == null ) ) { log.error( "Source and Destination cannot be null" ); //$NON-NLS-1$ throw new IllegalArgumentException( "Source and Destination cannot be null" ); //$NON-NLS-1$ } if( dest.exists() ) { log.error( "Destination file already exists: " + dest ); //$NON-NLS-1$ throw new IllegalArgumentException( "Destination file already exists: " + dest ); //$NON-NLS-1$ } FileOutputStream outputStream = null; ReadableByteChannel inputChannel = null; FileChannel outputChannel = null; try { outputStream = new FileOutputStream( dest ); inputChannel = Channels.newChannel( inputStream ); outputChannel = outputStream.getChannel(); long count = 0, size = Long.MAX_VALUE; outputChannel.transferFrom( inputChannel, count, size ); } catch( Throwable e ) { log.error( e.getMessage(), e ); } finally {// just in case the Eclipse API doesn't close it for whatever // reason. try { inputStream.close(); if( outputStream != null ) { outputStream.close(); } } catch( Throwable e ) { log.error( e.getMessage(), e ); } } } /** * Copy the source file to the destination file. Overwrite it if the destination file exists. * * @param src * The source file * @param dest * The destination file * @throws IOException * Any error during file copy */ public static void copyOverwrite( File src, File dest ) throws IOException { if( ( src == null ) || ( dest == null ) ) { log.error( "Source and Destination files cannot be null" ); //$NON-NLS-1$ throw new IllegalArgumentException( "Source and Destination files cannot be null" ); //$NON-NLS-1$ } if( !src.exists() || !src.canRead() || !src.isFile() ) { log.error( "Could not access or read file " + src ); //$NON-NLS-1$ throw new IllegalArgumentException( "Could not access or read file " + src ); //$NON-NLS-1$ } // delete the destination file if it exists. if( dest.exists() ) { if( !dest.delete() ) { log.warn( "Could not replace file " + dest ); //$NON-NLS-1$ return; } } copy( src, dest ); } public static IStatus canChange( final java.io.File osFile ) { return canChange( osFile, "Change Resource Problem", "Resource is read-only and cannot be changed: ", true, "\n\nDo you want to make the resource writable?" ); } public static IStatus canChange( final java.io.File osFile, final String dialogTitle, final String errorMessage, final boolean showResourcePath, final String questionMessage ) { IStatus result = Status.CANCEL_STATUS; if( ( osFile != null ) && ( osFile.exists() ) ) { if( osFile.canWrite() ) { result = Status.OK_STATUS; } else { // prompt for making resource writable Display.getDefault().syncExec( new Runnable() { public void run() { StringBuffer buffer = new StringBuffer(); buffer.append( errorMessage ); if( showResourcePath ) { buffer.append( osFile.getAbsolutePath() ); } buffer.append( questionMessage ); String[] buttons = new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL }; Shell shell = new Shell(); MessageDialog promptSaveDia = new MessageDialog( shell, dialogTitle, null, buffer.toString(), MessageDialog.WARNING, buttons, 0 ); int ret = promptSaveDia.open(); shell.dispose(); if( ret == Window.OK ) { // make this resource writable setWritable( osFile ); } } } ); if( osFile.canWrite() ) { result = Status.OK_STATUS; } } } return result; } public static void setWritable( java.io.File osFile ) { // Since there is no method in Java to set writable directly, we have to // use following approach. java.io.File srcFile = osFile; java.io.File destFile = new java.io.File( srcFile.getParentFile(), String.valueOf( System.currentTimeMillis() ) ); FileInputStream in = null; FileOutputStream out = null; FileChannel inChannel = null, outChannel = null; // create dest file try { destFile.createNewFile(); // copy content from source file to dest file in = new FileInputStream( srcFile ); out = new FileOutputStream( destFile ); inChannel = in.getChannel(); outChannel = out.getChannel(); inChannel.transferTo( 0, inChannel.size(), outChannel ); } catch( Throwable e ) { log.error( e.getMessage(), e ); } finally { try { if( null != inChannel ) inChannel.close(); if( null != outChannel ) outChannel.close(); } catch( Throwable e ) { log.error( e.getMessage(), e ); } } // delete source file boolean success = srcFile.delete(); if( !success ) { destFile.delete(); throw new RuntimeException( "source file can not be deleted:" + srcFile.getAbsolutePath() ); } // rename dest file to source file destFile.renameTo( srcFile ); } /** * Add the given <code>file</code> to the given </code>container</code>. * * @param container * @param file * @param createLink * @return */ public static IFile addResourceToProject( IContainer container, File file, Boolean createLink ) { // TODO:Check if has package IProject iProject = container.getProject(); IFile iFile = null; iFile = container.getFile( new Path( file.getName() ) ); if( iFile != null && !iFile.exists() ) { if( createLink ) { try { iFile.createLink( new Path( file.getAbsolutePath() ), IResource.NONE, new NullProgressMonitor() ); } catch( Exception e ) { log.error( "Error linking resource to project" ); } } else { ImportUtils.copyFile( iProject, file, iFile.getProjectRelativePath() ); } } return iFile; } /** * Returns where the resources (non-package) should be created * * @param iProject * @return */ public static IFolder getResFolder( IProject iProject ) { IFolder sourceFolder = null; String resFolderName = ImportUtils.getProjectResFolderName(); if( resFolderName.length() > 0 ) { sourceFolder = iProject.getFolder( new Path( resFolderName ) ); } if( sourceFolder == null || !sourceFolder.exists() ) { // Get the 1st found source folder sourceFolder = get1stNonDerivedSourceFolder( iProject ); } return sourceFolder; } public static IFolder get1stNonDerivedSourceFolder( IProject iProject ) { IFolder sfolder = null; IPackageFragmentRoot roots[] = ProjectUtils.getProjectSourceFolders( iProject ); if( roots != null && roots.length > 0 ) { Collections.sort( Arrays.asList( roots ), new Comparator< IPackageFragmentRoot >() { @Override public int compare( IPackageFragmentRoot root1, IPackageFragmentRoot root2 ) { return root1.getElementName().compareTo( root2.getElementName() ); } } ); for( int i = 0; i < roots.length; i++ ) { sfolder = iProject.getFolder( roots[ i ].getResource().getProjectRelativePath() ); if( !sfolder.isDerived() ) { break; } } } return sfolder; } public static void deleteAll( File[] files ) { if( files == null ) { throw new IllegalArgumentException( "files cannot be null" ); //$NON-NLS-1$ } for( File file : files ) { if( !file.exists() || !file.canWrite() ) { throw new IllegalArgumentException( "Could not access or write file " + file ); //$NON-NLS-1$ } if( file.isDirectory() ) { deleteDir( file ); } else { file.delete(); } } } /** * Reads the content of a file and returns an ArrayList with the data * * @param f * File that should be read * @return ArrayList of data */ public static List< String > readFile( File f ) { List< String > data = new ArrayList< String >(); try { BufferedReader br = new BufferedReader( new FileReader( f ) ); while( br.ready() ) { data.add( br.readLine() ); } return data; } catch( FileNotFoundException e ) { return null; } catch( IOException e ) { return null; } } /** * Returns the file extension of the given file. * * @param f * @return File extension */ public static String getFileExtension( File f ) { String fileName = f.getName(); int index = fileName.lastIndexOf( IConstants.DOT_MARK ); if( index > 0 && index < fileName.length() ) { String fileExtension = fileName.substring( index + 1 ); return fileExtension; } return IConstants.EMPTY_STRING; } private static void deleteDir( File file ) { if( file == null ) { throw new IllegalArgumentException( "file cannot be null" ); //$NON-NLS-1$ } if( !file.exists() || !file.canWrite() ) { throw new IllegalArgumentException( "Could not access or write file " + file ); //$NON-NLS-1$ } for( File subFile : file.listFiles() ) { if( !subFile.exists() || !subFile.canWrite() ) { throw new IllegalArgumentException( "Could not access or write file " + subFile ); //$NON-NLS-1$ } if( subFile.isDirectory() ) { deleteDir( subFile ); } else { subFile.delete(); } } file.delete(); } }