package me.guillaumin.android.osmtracker.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.util.Log;
public final class FileSystemUtils {
private static final String TAG = FileSystemUtils.class.getSimpleName();
/**
* The maximum recursion depth we allow when deleting directories
*/
private static final int DELETE_MAX_RECURSION_DEPTH = 1;
/**
* <p>Copies file sourceFile to the directory destination directory.</p>
*
* <p>After this method returns, the caller should trigger a media scan to ensure the copied files
* are known to the media scanner and visible over MTP. This can be done by broadcasting an
* {@code Intent.ACTION_MEDIA_SCANNER_SCAN_FILE} with the URI of the new file, or by calling
* {@code MediaScannerConnection.scanFile(file, null)}, passing the full path to the newly added
* file as the {@code file} argument.</p>
*
* @param destinationDirectory location where the file to be copied
* @param sourceFile the location of the file to copy
* @param targetFileName name of the target file
* @return true if the file was copied successfully, false otherwise
*/
public static boolean copyFile(final File destinationDirectory, final File sourceFile, final String targetFileName) {
boolean _return = false;
if (null != destinationDirectory && null != sourceFile) {
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
byte[] dataBuffer = new byte[1024];
File outputFile = new File(destinationDirectory.getAbsoluteFile()
+ File.separator + targetFileName);
try {
inputStream = new FileInputStream(sourceFile);
outputStream = new FileOutputStream(outputFile);
try {
int bytesRead = inputStream.read(dataBuffer);
while (-1 != bytesRead) {
outputStream.write(dataBuffer, 0, bytesRead);
bytesRead = inputStream.read(dataBuffer);
}
// No errors copying the file, look like we're good
_return = true;
} catch (IOException e) {
Log.w(TAG,"IOException trying to write copy file ["
+ sourceFile.getAbsolutePath() + "] to ["
+ destinationDirectory.getAbsolutePath() +"]: ["
+ e.getMessage() + "]");
}
} catch (FileNotFoundException e) {
Log.w(TAG,"File not found exception trying to write copy file ["
+ sourceFile.getAbsolutePath() + "] to ["
+ destinationDirectory.getAbsolutePath() +"]: ["
+ e.getMessage() + "]");
}
}
return _return;
}
/**
* <p>Copies all files within a directory to another directory</p>
*
* <p>After this method returns, the caller should trigger a media scan to ensure the copied files
* are known to the media scanner and visible over MTP. This can be done by calling
* {@code MediaScannerConnection.scanFile(context, files, null, null)}, passing an array of the
* newly added files as the {@code files} argument.</p>
*
* @param destinationDirectory the target directory
* @param sourceDirectory the source directory
* @return true if all contents were copied successfully, false otherwise
*/
public static boolean copyDirectoryContents(File destinationDirectory, File sourceDirectory){
if(destinationDirectory == null){
Log.e(TAG, "Unable to copy: destinationDirectory is null");
return false;
}
if(sourceDirectory == null){
Log.e(TAG, "Unable to copy: sourceDirectory is null");
return false;
}
// If the source and destination directories exist then copy the files
if (sourceDirectory.exists() && sourceDirectory.isDirectory()
&& destinationDirectory.exists() && destinationDirectory.isDirectory()
&& destinationDirectory.canWrite()) {
List<String> failedCopy = null;
for (File fileToCopy: sourceDirectory.listFiles()) {
// Find and copy the file to the output directory
Log.i(TAG,"Copying link file [" + fileToCopy.getName() + "] from ["
+ sourceDirectory.getAbsolutePath() + "] to [" + destinationDirectory + "]");
if (! copyFile(destinationDirectory, fileToCopy, fileToCopy.getName()) ) {
if (failedCopy == null) {
failedCopy = new ArrayList<String>();
}
failedCopy.add(fileToCopy.getName());
}
}
if (failedCopy != null) {
// Report on the files that could not be copied
Log.w(TAG,"Failed to copy the following files: ");
for(String fileName: failedCopy) {
Log.w(TAG,"\t [" + fileName + "]");
}
}else{
return true;
}
} else {
Log.w(TAG,"Unable to copy:\n\tInput dir Exists? [" + sourceDirectory.exists()
+ "]\n\tInput dir is directory? [" + sourceDirectory.isDirectory()
+ "]\n\tOutput dir Exists? [" + destinationDirectory.exists()
+ "]\n\tOutput dir is directory [" + destinationDirectory.isDirectory()
+ "]\n\tOutput dir is writable [" + destinationDirectory.canWrite()
+ "]");
}
return false;
}
/**
* Delete a file/directory
* @param fileToDelete the file/directory to be deleted
* @param recursive if a directory needs to be deleted with all of it's content, set this to true. please note, that recursion is currently limited to a depth of 1 subfolder
* @return true if the file/directory was completely deleted, false otherwise
*/
public static boolean delete(File fileToDelete, boolean recursive) {
return delete(fileToDelete, recursive, 0);
}
/**
* Delete a file/directory
* @param fileToDelete the file/directory to be deleted
* @param recursive if the deletion should be recursive
* @param recursionDepth takes care of the depth of recursion and aborts deletion if DELETE_MAX_RECURSION_DEPTH is reached
* @return
*/
private static boolean delete(File fileToDelete, boolean recursive, int recursionDepth){
// if we're deeper than one recursion/subfolder, we'll cancel deletion
if(recursionDepth > DELETE_MAX_RECURSION_DEPTH){
Log.w(TAG, "DELETE_MAX_RECURSION_DEPTH ("+DELETE_MAX_RECURSION_DEPTH+") reached. Directory deletion aborted.");
return false;
}
boolean deleted = false;
//If it's a directory and we should delete it recursively, try to delete all childs
if(fileToDelete.isDirectory() && recursive){
for(File child:fileToDelete.listFiles()){
if(!delete(child, true, recursionDepth+1)){
Log.w(TAG, "deletion of ["+child+"] failed, aborting now...");
return false;
}
}
}
deleted = fileToDelete.delete();
boolean isDir = fileToDelete.isDirectory();
if(deleted){
Log.i(TAG, "deleted "+(isDir ? "directory" : "file")+" ["+fileToDelete+"]");
}else{
Log.w(TAG, "unable to delete "+(isDir ? "directory" : "file")+" ["+fileToDelete+"]");
}
return deleted;
}
}