package nl.tudelft.bw4t.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLDecoder; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.log4j.Logger; /** * A class of File operations. */ public final class FileUtils { /** * error message used when could not find file */ private static final String COULD_NOT_FIND_FILE = "Could not find '%s'"; /** * The log4j logger, logs to the console. */ private static final Logger LOGGER = Logger.getLogger(FileUtils.class); /** * error message used when we failed to close a file. */ private static final String FAILED_TO_CLOSE = "Failed to close file '%s'"; /** * Utility class, cannot be instantiated. */ private FileUtils() { } /** * Copy a file to another file. * * @param toCopy * the original file * @param destFile * the destination file * @return true iff the file was copied correctly */ public static boolean copyFile(final File toCopy, final File destFile) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(toCopy); fos = new FileOutputStream(destFile); return FileUtils.copyStream(fis, fos); } catch (final FileNotFoundException e) { LOGGER.error(String.format("Failed to copy file '%s' to '%s'", toCopy, destFile), e); } finally { close(toCopy, fis, fos); } return false; } /** * Closes FileInputStream and/or FileOutpusStream * (when the exist/not null) * * @param fis FileInputStream * @param fos FileOutputStream * @param toCopy original file */ private static void close(final File toCopy, FileInputStream fis, FileOutputStream fos) { if (fis != null) { try { fis.close(); } catch (IOException e) { LOGGER.warn(String.format(FAILED_TO_CLOSE, toCopy), e); } } if (fos != null) { try { fos.close(); } catch (IOException e) { LOGGER.warn(String.format(FAILED_TO_CLOSE, toCopy), e); } } } /** * copy all of the files in the given directory . * * @param toCopy * the folder to be copied * @param destDir * the folder to be copied to * @return true iff the files were successfully copied */ private static boolean copyFilesRecusively(final File toCopy, final File destDir) { assert destDir.isDirectory(); if (!toCopy.isDirectory()) { return FileUtils.copyFile(toCopy, new File(destDir, toCopy.getName())); } else { final File newDestDir = new File(destDir, toCopy.getName()); if (!newDestDir.exists() && !newDestDir.mkdir()) { return false; } for (final File child : toCopy.listFiles()) { if (!FileUtils.copyFilesRecusively(child, newDestDir)) { return false; } } } return true; } /** * Copy resource files from a jar file to a directory * * @param destDir * the destination directory * @param jarConnection * the url of the folder in the jar to be copied * @return true iff the file were successfully copied * @throws IOException */ public static boolean copyJarResourcesRecursively(final JarURLConnection jarConnection, final File destDir) throws IOException { final JarFile jarFile = jarConnection.getJarFile(); final String entryName = jarConnection.getEntryName(); String entryNameParent = entryName.substring(0, entryName.lastIndexOf('/') + 1); for (final Enumeration<JarEntry> e = jarFile.entries(); e.hasMoreElements();) { final JarEntry entry = e.nextElement(); if (entry.getName().startsWith(entryName)) { boolean copy = copyJar(destDir, jarFile, entryNameParent, entry); if (!copy) return copy; } } return true; } /** * Copy resource files from a jar file to a directory * * @param destDir * the destination directory * @param jarFile * @param entryNameParent * @param entry JarEntry * @return true iff the file were successfully copied * @throws IOException */ private static boolean copyJar(final File destDir, final JarFile jarFile, String entryNameParent, final JarEntry entry) throws IOException { final String filename = FileUtils.removeStart(entry.getName(), entryNameParent); final File f = new File(destDir, filename); if (!entry.isDirectory()) { final InputStream entryInputStream = jarFile.getInputStream(entry); if (!FileUtils.copyStream(entryInputStream, f)) { return false; } entryInputStream.close(); } else { if (!FileUtils.ensureDirectoryExists(f)) { throw new IOException("Could not create directory: " + f.getAbsolutePath()); } } return true; } /** * Copy files from local filesystem or resources to a folder in the filesystem. * * @param originUrl * the origin url containing the files * @param destination * the folder to copy to * @return true iff the files were copied successfully */ public static boolean copyResourcesRecursively(final URL originUrl, final File destination) { try { final URLConnection urlConnection = originUrl.openConnection(); if (urlConnection instanceof JarURLConnection) { return FileUtils.copyJarResourcesRecursively((JarURLConnection) urlConnection, destination); } else { return FileUtils.copyFilesRecusively(new File(URLDecoder.decode(originUrl.getPath(), "UTF-8")), destination); } } catch (final IOException e) { LOGGER.error("Failed to copy files from Jar", e); } return false; } /** * Copy contents from the inputstream to the given file, closes the inputstream afterwards. * * @param is * the inputstream * @param f * the outputfile * @return true iff the file was successfully copied */ private static boolean copyStream(final InputStream is, final File f) { FileOutputStream fos = null; try { fos = new FileOutputStream(f); return FileUtils.copyStream(is, fos); } catch (final FileNotFoundException e) { LOGGER.warn(String.format(COULD_NOT_FIND_FILE, f), e); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { LOGGER.warn(String.format(FAILED_TO_CLOSE, f), e); } } } return false; } /** * this function copies the contents of the inputstream to the outputstream and closes both streams. * * @param is * the inputstream * @param os * the outputstream * @return true iff the contents were successfully copied */ private static boolean copyStream(final InputStream is, final OutputStream os) { try { final byte[] buf = new byte[1024]; int len = 0; while ((len = is.read(buf)) > 0) { os.write(buf, 0, len); } is.close(); os.close(); return true; } catch (final IOException e) { LOGGER.error("Failed to copy stream", e); } return false; } /** * check whether the given directory exists or tries to make it. * * @param f * the file to be checked * @return true iff the directory exists or was created */ private static boolean ensureDirectoryExists(final File f) { return f.exists() || f.mkdir(); } /** * * @param str Original String * @param remove String to remove * @return rest of string after removing remove in front * when str does not start with remove, return str */ public static String removeStart(String str, String remove) { if (isEmpty(str) || isEmpty(remove)) { return str; } if (str.startsWith(remove)) { return str.substring(remove.length()); } return str; } /** * @param cs CharSequence to check * @return true iff cs is null or has length zero */ public static boolean isEmpty(CharSequence cs) { return cs == null || cs.length() == 0; } /** * Checks whether the file name has the required extension. * @param fileName The file name including extension. * @param extensionRequired The extension required for the file name. * @return Whether the file name has the required extension. */ public static boolean hasRequiredExtension(String fileName, String extensionRequired) { return getExtension(fileName).equals(extensionRequired); } /** * Gets the extension, including the starting dot, of a file name. * @param fileName The file name including extension. * @return The extension of the file. */ public static String getExtension(String fileName) { String[] splitFileName = fileName.split("\\."); if (splitFileName.length <= 1) { return ""; } int lastDotIndex = splitFileName.length - 1; return "." + splitFileName[lastDotIndex]; } /** * Gets the file name without it's extension. * @param fileName The file name. * @return The file name without extension. */ public static String getFileNameWithoutExtension(String fileName) { int extensionLength = getExtension(fileName).length(); return fileName.substring(0, fileName.length() - extensionLength); } }