I have to develop a class that creates new files. If a file with the given name already exists, it should be renamed by addition of the timestamp to the file name. The file name should be human-readable, so I can use neither UUID nor createTempFile
. The code works, but looks too bulky.
public class FileBackup {
/**
* Creates new file. If file with given name exists, then backups
* it by renaming and adding time stamp to file name;
*
* @param filePath the fully qualified name of file
* @return the file on success; otherwise returns null
*
* @throws IOException
*/
public static File backupAndCreateFile(String filePath) throws IOException {
File fileToCreate = new File(filePath);
boolean backupRequired = fileToCreate.isFile();
if (backupRequired && !backupFile(fileToCreate)) {
return null;
}
File file = new File(filePath);
return file.createNewFile() ? file : null;
}
private static final String pattern = "-dd_M_yyyy-hh_mm_ss";
private static final DateFormat dateFormat = new SimpleDateFormat(pattern);
private static String generateBackupName (String filePath) {
String name = getFileName (filePath);
String ext = getFileExtention (filePath);
return name + dateFormat.format(new Date()) + ext;
}
private static String getFileName (String filePath) {
int i = filePath.lastIndexOf('.');
return i == -1 ? filePath : filePath.substring(0, i);
}
private static String getFileExtention (String filePath) {
int i = filePath.lastIndexOf('.');
return i == -1 ? "" : filePath.substring(i);
}
private static boolean backupFile (File file) {
String filePath = file.getAbsolutePath();
while (true) {
String backupName = generateBackupName (filePath);
File backup = new File(backupName);
if (!backup.isFile()) return file.renameTo(backup);
// File with generated name exists, so
// sleep for 0.5 second and try another name
try {
Thread.sleep(500);
} catch (InterruptedException e) {return false;}; // never should be here
}
}
}
SimpleDateFormat
as a static final field, is a bad idea: since that class isn't thread-safe, it's bound to cause failures when used concurrently by multiple threads. Prefer to store them as local variables (and if the cost of creation is too much, asThreadLocal<SimpleDateFormat>
. \$\endgroup\$