lunes, 21 de febrero de 2011

Código para acomodar imagenes por fecha de modificación

Quize crear un programa pequeño para organizar un montón de fotos que tengo desordenadas en distintas carpetas. En lo particular me gusta tener las fotos almacenadas en carpetas que indiquen la fecha en que se tomaron. De esa manera puedo hacerme una idea cronólogica de cuándo se fueron tomando. Claro está que este código funciona bajo la premisa de que la fecha de modificación de las fotos es la misma de cuándo se tomaron, que es la misma de cuando se descargaron. Puede ser que no sea el caso de muchos archivos, pero al menos ayuda agregando cierto nivel de orden.


Clase Principal:


package gsolano.photoorganizer;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* This class is used to copy files from a specific folder (recursive scan in that folder)
* into a new folder structure using modification date of the files to map them correctly.
*
* @author gsolano
*
*/
public class FileOrganizerByModificationDate {

/**
* Extensions to that will be processed.
*/
protected final String [] extensionsToProcess = {"jpg","avi"};
/**
* Year(key): 2010
* ++ Date(key): 20100125
* ++++ File: 010223.jpg
* ++++ File: 232455.avi
*/
protected Map<Integer, Map<String,List<String>>> newFolderStructure;

/**
* Directory path that will be scanned.
*/
protected String pathToProcess;

/**
* Counter of total files found.
*/
protected int totalFilesToOrganize;

/**
* Default constructor.
*/
private FileOrganizerByModificationDate() {
newFolderStructure = new HashMap<Integer,Map<String,List<String>>>();
totalFilesToOrganize = 0;
}

/**
* Constructor receiving path that will be processed.
* @param pathToProcess
*/
public FileOrganizerByModificationDate(String pathToProcess){
this();
this.pathToProcess = pathToProcess;
}

/**
* Scans the path provided in the constructor.
*/
public void scan() {
if(pathToProcess != null && pathToProcess != "") {
scan(pathToProcess);
}
}

/**
* Scans a specific path.
* @param rootDirPath
*/
public void scan(String rootDirPath) {
System.out.println("Scanning: " + rootDirPath);
this.pathToProcess=rootDirPath;
File sourceDir = new File(rootDirPath);

if(sourceDir.exists() && sourceDir.isDirectory()) {
scanRecursively(sourceDir);
System.out.println("Files to organize: " + totalFilesToOrganize);

} else {
System.out.println("Directory does not exist!");
}

if(newFolderStructure.size() > 0) { // Files were added to the new structure?
try {
System.out.println("Copying files...");
copyFiles(); // Copy the files in the new directory structure.
} catch (IOException e) {
e.printStackTrace();
}
// Clean the class..
newFolderStructure.clear();
totalFilesToOrganize = 0;
}
}

/**
* Once scan is finished, this method is in charge of copying files to new structure.
* @throws IOException
*/
private void copyFiles() throws IOException{
Set<Integer> years = newFolderStructure.keySet();
int totalFilesCopied = 0;

for(Integer year : years) {
String newYearDirectoryPath = (pathToProcess.endsWith(File.separator) ? pathToProcess + year.toString() :
pathToProcess+ File.separator + year.toString());
// Let's create the year directory.
File newYearDirectory = new File(newYearDirectoryPath);
newYearDirectory.mkdir();
String newYearAbsoluteDirectoryPath = newYearDirectory.getAbsolutePath();
Set<String> newDateFolders = newFolderStructure.get(year).keySet();

// Diving into the years map.
for(String newDateFolder : newDateFolders) {
// Let's create the date folder.
String newDateFolderPath = newYearAbsoluteDirectoryPath + File.separator + newDateFolder;
File newDateDirectory = new File(newDateFolderPath);
newDateDirectory.mkdir();

List<String> files = newFolderStructure.get(year).get(newDateFolder);

for(String file : files) {
// Finally, copy the file in the respective folder.
FileCopy.copy(file, newDateFolderPath, false);
totalFilesCopied++;
System.out.print("\r"+progress(totalFilesCopied, totalFilesToOrganize));
}
}
}

}

/**
* Recursive method to find empty folders.
* @param sourceDir
*/
private void scanRecursively(File sourceDir) {
// List files and directories in the first level.
File[] listOfFiles = sourceDir.listFiles();

if (listOfFiles != null) {
for(int i=0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
String extension = getExtension(listOfFiles[i].getName());
if (isValidExtension(extension)) {
processFile(listOfFiles[i]);
totalFilesToOrganize++;
}
}
else if(listOfFiles[i].isDirectory()) { // Recursive call.
scanRecursively(listOfFiles[i]);
}
}
}
}

/**
* Process the file found. The file path is added to the new map structure used later to create
* the new directory structure and copy the file.
* @param file
*/
private void processFile(File file) {

DateFormat dfYearOnly = new SimpleDateFormat("yyyy");

Date lastModified = new Date(file.lastModified());
Integer yearOfFile = Integer.valueOf(dfYearOnly.format(lastModified));
DateFormat df = new SimpleDateFormat("yyyyMMdd");
String dateFolder = df.format(lastModified);

if(!newFolderStructure.containsKey(yearOfFile)) {
newFolderStructure.put(yearOfFile, new HashMap<String, List<String>>());
}
if(!newFolderStructure.get(yearOfFile).containsKey(dateFolder)) {
newFolderStructure.get(yearOfFile).put(dateFolder, new LinkedList<String>());
}
newFolderStructure.get(yearOfFile).get(dateFolder).add(file.getAbsolutePath());
}

/**
* Get file's extension *
* @param fileName
* @return file extension
*/
private String getExtension(final String fileName) {
final int x = fileName.lastIndexOf(".");
return (x > 0 && x < fileName.length()) ? fileName.substring(fileName.lastIndexOf(".")+1, fileName.length()) : "" ;
}

/**
* Validates if the extension is valid to be processed.
* @param extension
* @return
*/
private boolean isValidExtension(String extension) {
for(String extensionToProcess : extensionsToProcess) {
if(extensionToProcess.equalsIgnoreCase(extension)){
return true;
}
}
return false;
}

/**
* Simple function to calculate progress of the copy process.
* @param numerator
* @param denominator
* @return
*/
private String progress(int numerator, int denominator) {
float progress = 0;
progress = ((float)numerator / denominator)*100;
DecimalFormat df1 = new DecimalFormat("##.00");
return df1.format(progress)+"%";
}

public static void main(String[] args) {
FileOrganizerByModificationDate organizer =
new FileOrganizerByModificationDate(args[0]);
organizer.scan();
}
}



Clase para hacer el copiado:


package gsolano.photoorganizer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
* Utility class to copy a file from a source path to a target path.
*
* @author gsolano
*
*/
public class FileCopy {

public static void copy(String fromFileName, String toFileName,
boolean overrideFiles) throws IOException {
File fromFile = new File(fromFileName);
File toFile = new File(toFileName);

if (!fromFile.exists())
throw new IOException("FileCopy: " + "no such source file: "
+ fromFileName);
if (!fromFile.isFile())
throw new IOException("FileCopy: " + "can't copy directory: "
+ fromFileName);
if (!fromFile.canRead())
throw new IOException("FileCopy: " + "source file is unreadable: "
+ fromFileName);

if (toFile.isDirectory())
toFile = new File(toFile, fromFile.getName());
if (toFile.exists()) {
if (!toFile.canWrite()) {
throw new IOException("FileCopy: "
+ "destination file is unwriteable: " + toFileName);
}
if (!overrideFiles) {
// File exist, do not override it.
return;
}

String parent = toFile.getParent();
if (parent == null)
parent = System.getProperty("user.dir");
File dir = new File(parent);
if (!dir.exists())
throw new IOException("FileCopy: "
+ "destination directory doesn't exist: " + parent);
if (dir.isFile())
throw new IOException("FileCopy: "
+ "destination is not a directory: " + parent);
if (!dir.canWrite())
throw new IOException("FileCopy: "
+ "destination directory is unwriteable: " + parent);
} else {
// Create directory.
new File(toFile.getParent()).mkdirs();
}

FileInputStream from = null;
FileOutputStream to = null;
try {
from = new FileInputStream(fromFile);
to = new FileOutputStream(toFile);
byte[] buffer = new byte[4096];
int bytesRead;

while ((bytesRead = from.read(buffer)) != -1)
to.write(buffer, 0, bytesRead); // write
} finally {
if (from != null)
try {
from.close();
} catch (IOException e) {
;
}
if (to != null)
try {
to.close();
toFile.setLastModified(fromFile.lastModified());

} catch (IOException e) {
;
}
}
}
}


Salida:

No hay comentarios:

Publicar un comentario