Java tutorial
/* * Copyright (C) 2008 John-Paul.Stanford <dev@stanwood.org.uk> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.stanwood.media.util; import java.io.BufferedOutputStream; 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.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.ConnectException; import java.net.SocketTimeoutException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This is a help class that is used to perform operations on files. */ public class FileHelper { private final static Log log = LogFactory.getLog(FileHelper.class); /** A Line separator property value */ public final static String LS = System.getProperty("line.separator"); //$NON-NLS-1$ /** Stores the current users home directory */ public final static File HOME_DIR = new File(System.getProperty("user.home")); //$NON-NLS-1$ private final static char HEX_DIGITS[] = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** Time to sleep between retries */ public static final long RETRY_SLEEP_TIME = 5000; // 5 seconds /** Number of retries to retry fetching of URL's */ public static final int MAX_RETRIES = 3; /** * This will create a temporary directory using the given name. * * @param name The name of the directory to create * @return A file object pointing to the directory that was created * @throws IOException Thrown if their is a problme creating the directory */ public static File createTmpDir(String name) throws IOException { File dir = createTempFile(name, ""); //$NON-NLS-1$ if (!dir.delete()) { throw new IOException(MessageFormat.format(Messages.getString("FileHelper.UNABLE_DELETE_FILE"), //$NON-NLS-1$ dir.getAbsolutePath())); } if (!dir.mkdir()) { throw new IOException(MessageFormat.format(Messages.getString("FileHelper.UNABLE_CREATE_DIR"), //$NON-NLS-1$ dir.getAbsolutePath())); } return dir; } /** * Used to copy a source file or a directory to a destination file or directory. * * @param src The source file or directory * @param dst The destination file or directory * @throws IOException Thrown if their is a problem copying the file or directory */ public static void copy(File src, File dst) throws IOException { if (dst.exists()) { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UNABLE_COPY_ALREADY_EXISTS"), src, dst)); //$NON-NLS-1$ } if (src.isDirectory()) { if (!dst.mkdir() && !dst.exists()) { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UNABLE_CREATE_DIR"), dst)); //$NON-NLS-1$ } File[] files = src.listFiles(); for (File f : files) { copy(f, new File(dst, f.getName())); } } else { copyFile(src, dst); } } private static void copyFile(File src, File dst) throws FileNotFoundException, IOException { InputStream in = null; try { in = new FileInputStream(src); copy(in, dst); } finally { if (in != null) { try { in.close(); } catch (IOException e) { log.error(Messages.getString("FileHelper.UNABLE_CLOSE_INPUT_STREAM"), e); //$NON-NLS-1$ } } } } /** * Used to copy the contents of a input stream to a destination file. * * @param in The input stream * @param dst The destination file * @throws IOException Thrown if their is a problem copying the file */ public static void copy(InputStream in, File dst) throws IOException { if (in == null) { throw new NullPointerException("Stream is null"); //$NON-NLS-1$ } OutputStream out = null; try { out = new FileOutputStream(dst); // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } finally { if (out != null) { try { out.close(); } catch (IOException e) { log.error(Messages.getString("FileHelper.UNABLE_CLOSE_OUTPUT_STREAM"), e); //$NON-NLS-1$ } } if (in != null) { try { in.close(); } catch (IOException e) { log.error(Messages.getString("FileHelper.UNABLE_CLOSE_INPUT_STREAM"), e); //$NON-NLS-1$ } } } } /** * Used to copy the contents of a input stream to a destination file. * * @param in The input stream * @param dst The destination file * @param params Parameters which are replaced with values when the file is copied * @throws IOException Thrown if their is a problem copying the file */ public static void copy(InputStream in, File dst, Map<String, String> params) throws IOException { PrintStream out = null; BufferedReader bin = null; try { out = new PrintStream(new FileOutputStream(dst)); bin = new BufferedReader(new InputStreamReader(in)); String line; while ((line = bin.readLine()) != null) { for (Entry<String, String> e : params.entrySet()) { line = line.replaceAll("\\$" + e.getKey() + "\\$", e.getValue()); //$NON-NLS-1$ //$NON-NLS-2$ } out.println(line); } } finally { if (out != null) { out.close(); } if (bin != null) { bin.close(); } } } /** * This will copy a file from the web to a destination file on the local system * @param url The url to read from the file from * @param dest The file to be created on the location system * @return A MD5 sum of the file * @throws IOException Thrown if their is a problem reading or wring the file */ public static String copy(URL url, File dest) throws IOException { if (log.isDebugEnabled()) { log.debug("Fetching: " + url); //$NON-NLS-1$ } IOException error = null; for (int retries = 0; retries < MAX_RETRIES; retries++) { try { OutputStream out = null; InputStream is = null; try { out = new FileOutputStream(dest); if (url.getProtocol().equals("http")) { //$NON-NLS-1$ is = new WebFileInputStream(url); } else { is = url.openStream(); } MessageDigest md = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = is.read(buf)) > 0) { out.write(buf, 0, len); md.update(buf, 0, len); } out.flush(); return bytesToHexString(md.digest()); } catch (ConnectException e) { if (error == null) { error = e; } if (retries < MAX_RETRIES - 1) { log.error(MessageFormat.format(Messages.getString("FileHelper.UnableFetch1"), //$NON-NLS-1$ url.toExternalForm())); try { Thread.sleep(FileHelper.RETRY_SLEEP_TIME); } catch (InterruptedException e2) { // Ignore } } } catch (SocketTimeoutException e) { if (error == null) { error = e; } if (retries < MAX_RETRIES - 1) { log.error(MessageFormat.format(Messages.getString("FileHelper.UnableFetch2"), //$NON-NLS-1$ url.toExternalForm())); try { Thread.sleep(FileHelper.RETRY_SLEEP_TIME); } catch (InterruptedException e2) { // Ignore } } } catch (IOException e) { if (dest.exists()) { try { FileHelper.delete(dest); } catch (IOException e1) { log.error( MessageFormat.format(Messages.getString("FileHelper.UNABLE_DELETE_FILE"), dest), //$NON-NLS-1$ e1); } } throw e; } finally { if (is != null) { try { is.close(); } catch (IOException e) { log.error(Messages.getString("FileHelper.UNABLE_CLOSE_STREAM"), e); //$NON-NLS-1$ } } if (out != null) { try { out.close(); } catch (IOException e) { log.error(Messages.getString("FileHelper.UNABLE_CLOSE_STREAM"), e); //$NON-NLS-1$ } } } } catch (NoSuchAlgorithmException e) { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UNABLE_DOWNLOAD_URL"), url), e); //$NON-NLS-1$ } } throw error; } /** * Used to generate a MD5 checksum string for a file * @param file The file * @return The checksum * @throws IOException Thrown if their are any problems */ public static String getMD5Checksum(File file) throws IOException { try { InputStream is = null; try { is = new FileInputStream(file); MessageDigest md = MessageDigest.getInstance("MD5"); //$NON-NLS-1$ // Transfer bytes from in to out byte[] buf = new byte[1024]; int len; while ((len = is.read(buf)) > 0) { md.update(buf, 0, len); } return bytesToHexString(md.digest()); } finally { if (is != null) { is.close(); } } } catch (NoSuchAlgorithmException e) { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UNABLE_GET_CHECKSUM_FILE"), file), e); //$NON-NLS-1$ } } private static String bytesToHexString(byte data[]) { StringBuilder sb = new StringBuilder(data.length * 2); for (int buc = 0; buc < data.length; buc++) { sb.append(HEX_DIGITS[(data[buc] >> 4) & 0x0F]); sb.append(HEX_DIGITS[data[buc] & 0x0F]); } return sb.toString(); } /** * Used to delete a directory and all it's children * * @param dir The directory to delete * @return True if successful, otherwise false */ private static boolean deleteDir(File dir) { if (dir.isDirectory()) { String[] children = dir.list(); for (int i = 0; i < children.length; i++) { boolean success = deleteDir(new File(dir, children[i])); if (!success) { return false; } } } // The directory is now empty so delete it return dir.delete(); } /** * Used to display the contents of a file * * @param file The file to display * @param os The output stream to display it to * @throws IOException Thrown if their is a problem reading or displaying the file */ public static void displayFile(File file, PrintStream os) throws IOException { BufferedReader in = new BufferedReader(new FileReader(file)); String str; while ((str = in.readLine()) != null) { os.println(str); } in.close(); } /** * Used to display the contents of a file * @param file The file to display * @param startLine The line to start displaying from * @param endLine The line to finish displaying from * @param os The output stream used to print the file to * @throws IOException Thrown if their is a problem reading the file */ public static void displayFile(File file, int startLine, int endLine, OutputStream os) throws IOException { PrintStream ps = new PrintStream(os); if (startLine < 0) { startLine = 0; } int line = 1; BufferedReader in = new BufferedReader(new FileReader(file)); String str; while ((str = in.readLine()) != null) { if (line >= startLine && line <= endLine) { ps.println(line + ": " + str); //$NON-NLS-1$ } line++; } in.close(); } /** * Used to read the contents of a file into a string * * @param file The file to read * @return The contents of the file * @throws IOException Thrown if their is a problem reading the file */ public static String readFileContents(File file) throws IOException { StringBuilder results = new StringBuilder(); BufferedReader in = null; try { in = new BufferedReader(new FileReader(file)); String str; while ((str = in.readLine()) != null) { results.append(str + LS); } } finally { if (in != null) { in.close(); } } return results.toString(); } /** * Used to read the contents of a stream into a string * * @param inputStream The input stream * @return The contents of the file * @throws IOException Thrown if their is a problem reading the file */ public static String readFileContents(InputStream inputStream) throws IOException { if (inputStream == null) { throw new IOException(Messages.getString("FileHelper.INPUT_STREAM_IS_NULL")); //$NON-NLS-1$ } BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder results = new StringBuilder(); String str; while ((str = in.readLine()) != null) { results.append(str + LS); } return results.toString(); } finally { if (in != null) { in.close(); } } } /** * Used to list all the directories in a directory and it's sub directories. * @param dir The directory to list the files of * @return The files in the directory */ public static List<File> listDirectories(File dir) { List<File> files = new ArrayList<File>(); listDirectories(dir, files); Collections.sort(files); return files; } private static void listDirectories(File dir, List<File> dirs) { if (dir.isDirectory()) { for (File d : dir.listFiles()) { listDirectories(d, dirs); } dirs.add(dir); } } /** * Used to list all the files in a directory and it's sub directories. * @param dir The directory to list the files of * @return The files in the directory */ public static List<File> listFiles(File dir) { List<File> files = new ArrayList<File>(); listFiles(dir, files); Collections.sort(files); return files; } /** * Used to list all the files in a directory and it's sub directiories. * File files are returned as a list of absolute paths. * @param dir The directory to list the files of * @return The files in the directory */ public static List<String> listFilesAsStrings(File dir) { List<String> files = new ArrayList<String>(); List<File> files2 = listFiles(dir); for (File f : files2) { files.add(f.getAbsolutePath()); } return files; } private static void listFiles(File file, List<File> files) { if (file.isDirectory()) { for (File d : file.listFiles()) { listFiles(d, files); } } else { files.add(file); } } /** * Used to add contents to a file * @param file The file to add contetns to * @param contents The contents * @throws IOException Thrown if their is a IO problem */ public static void appendContentsToFile(File file, StringBuilder contents) throws IOException { PrintStream ps = null; try { FileOutputStream os = new FileOutputStream(file); ps = new PrintStream(os); ps.print(contents.toString()); } finally { ps.close(); } } /** * Used to unzip a file to a directory * @param is The input stream containing the file * @param destDir The directory to unzip to * @throws IOException Thrown if their are any problems */ public static void unzip(InputStream is, File destDir) throws IOException { ZipInputStream zis = null; try { zis = new ZipInputStream(is); ZipEntry entry = null; while ((entry = zis.getNextEntry()) != null) { File file = new File(destDir, entry.getName()); if (entry.isDirectory()) { if (!file.mkdir() && file.exists()) { throw new IOException("Unable to create directory: " + file); //$NON-NLS-1$ } } else { BufferedOutputStream out = null; try { int count; byte data[] = new byte[1000]; out = new BufferedOutputStream(new FileOutputStream(new File(destDir, entry.getName())), 1000); if (log.isDebugEnabled()) { log.debug("Unzipping " + entry.getName() + " with size " + entry.getSize()); //$NON-NLS-1$ //$NON-NLS-2$ } while ((count = zis.read(data, 0, 1000)) != -1) { out.write(data, 0, count); } out.flush(); } finally { if (out != null) { out.close(); } } } } } finally { if (zis != null) { zis.close(); } } } /** * Used to move a directory or file from once location to another * @param from The old name of the file or directory * @param to The new name of the file or directory * @throws IOException Thrown if their are any problems */ public static void move(File from, File to) throws IOException { if (!from.exists()) { throw new IOException(MessageFormat .format(Messages.getString("FileHelper.UNABLE_MOVE_FILE_SRC_NOT_FOUND"), from, to)); //$NON-NLS-1$ } if (to.exists()) { throw new IOException(MessageFormat .format(Messages.getString("FileHelper.UNABLE_MOVE_FILE_DEST_ALREADY_EXISTS"), from, to)); //$NON-NLS-1$ } copy(from, to); delete(from); } /** * Used to delete a file or a directory tree. If a directory is given, then all it's contents are also deleted recusrsivly. * @param file The file or directory to delete * @throws IOException Thrown if their are any problems */ public static void delete(File file) throws IOException { if (file.isDirectory()) { FileHelper.deleteDir(file); } else { if (!file.delete() && file.exists()) { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UNABLE_DELETE_FILE"), file)); //$NON-NLS-1$ } } } /** * Used to create a temporary file with the give contents * @param testConfig The contents to put in the file * @return A reference to the file * @throws IOException Thrown if their are any problems */ public static File createTmpFileWithContents(StringBuilder testConfig) throws IOException { File configFile = createTempFile("config", ".xml"); //$NON-NLS-1$ //$NON-NLS-2$ configFile.deleteOnExit(); FileHelper.appendContentsToFile(configFile, testConfig); return configFile; } /** * Used to get a stream to a URL. If their is a socket timeout exception, then * this method will wait 5 seconds and try again. It does this 3 times before throwing the * exception out if the method * @param url The URL of the stream * @return The stream * @throws IOException Thrown if their are any problems */ public static Stream getInputStream(URL url) throws IOException { SocketTimeoutException e = null; for (int tryCount = 0; tryCount < 3; tryCount++) { try { WebFileInputStream is = new WebFileInputStream(url); String MIME = is.getMIMEType(); if (MIME.equals("application/zip")) { //$NON-NLS-1$ return new Stream(new ZipInputStream(is), MIME, is.getCharset(), url.toExternalForm(), url); } else { return new Stream(is, MIME, is.getCharset(), url.toExternalForm(), url); } } catch (SocketTimeoutException e1) { log.warn(MessageFormat.format(Messages.getString("FileHelper.Timedout"), url.toExternalForm())); //$NON-NLS-1$ if (e == null) { e = e1; } try { Thread.sleep(5000); // Sleep for 3 seconds } catch (InterruptedException e2) { // Ignore } } } throw e; } /** * Used a temporary file that will be deleted when the JVM exits * @param name name of file * @param ext extension of the file * @return The file * @throws IOException Thrown if their is a problem creating the file */ public static File createTempFile(String name, String ext) throws IOException { final File file = File.createTempFile(name, ext); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { if (file.exists()) { try { FileHelper.delete(file); } catch (IOException e) { log.error(MessageFormat.format(Messages.getString("FileHelper.UNABLE_DELETE_TEMP_FILE"), //$NON-NLS-1$ file), e); } } } }); return file; } /** * Used to get the extension of the file * @param file The file * @return The extension */ public static String getExtension(File file) { String fileName = file.getAbsolutePath(); int pos = fileName.lastIndexOf("."); //$NON-NLS-1$ if (pos == -1) { return ""; //$NON-NLS-1$ } return fileName.substring(pos + 1); } /** * Used to get the name of the file * @param file The file * @return The name */ public static String getName(File file) { String fileName = file.getName(); int pos = fileName.lastIndexOf("."); //$NON-NLS-1$ if (pos == -1) { return fileName; } return fileName.substring(0, pos); } /** * Used to get the current working directory * @return the current working directory */ public static File getWorkingDirectory() { return new File(System.getProperty("user.dir")); //$NON-NLS-1$ } /** * Used to convert relative paths to absolute paths. This will remove .. from the path * @param path The relative path * @return The absolute path */ public static File resolveRelativePaths(File path) { String segments[] = path.getAbsolutePath().split(Pattern.quote(File.separator)); List<String> newSegments = new ArrayList<String>(); for (String seg : segments) { if (seg.equals("..")) { //$NON-NLS-1$ newSegments.remove(newSegments.size() - 1); } else { newSegments.add(seg); } } File result = null; for (String seg : newSegments) { if (result == null) { result = new File(seg); } else { result = new File(result, seg); } } return result; } /** * Used to rename a file. This handles the case where java's {@link File#renameTo(File)} fails. It that * occurs it copies the file and deletes the original * @param oldFile The old file name * @param newFile The new file name * @throws IOException Thrown if their are any problems */ public static void rename(File oldFile, File newFile) throws IOException { if (!oldFile.renameTo(newFile) && !newFile.exists()) { FileHelper.copy(oldFile, newFile); if (newFile.exists() && oldFile.length() == newFile.length()) { FileHelper.delete(oldFile); } else { throw new IOException( MessageFormat.format(Messages.getString("FileHelper.UnableCopy"), oldFile, newFile)); //$NON-NLS-1$ } } } }