/* * */ package org.smartly.commons.util; import org.smartly.commons.logging.Level; import org.smartly.commons.logging.Logger; import org.smartly.commons.logging.util.LoggingUtils; import java.io.*; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; /** * @author */ public abstract class FileUtils { private static final Logger logger = LoggingUtils.getLogger(FileUtils.class.getName()); public static final int BLOCK_SIZE = 1024 * 4; /** * Preserves the last modified time and other attributes if possible. * * @see #copy(java.io.File, java.io.File, int) */ public static final int CP_PRESERVE = 0x0001; /** * Copy only when the source is newer or when the destination is missing. * * @see #copy(java.io.File, java.io.File, int) */ public static final int CP_UPDATE = 0x0002; /** * Overwrites the destination file. * * @see #copy(java.io.File, java.io.File, int) */ public static final int CP_OVERWRITE = 0x0004; /** * Ensure all directories are created * * @param fileName * @throws IOException */ public static String mkdirs(final String fileName) throws IOException { File dir = null; final String ext = PathUtils.getFilenameExtension(fileName); if (!StringUtils.hasText(ext)) { dir = new File(fileName); } else { final File file = new File(fileName); dir = file.getParentFile(); } if (null != dir && !dir.exists()) { boolean done = dir.mkdirs(); if (!done) { throw new IOException("Unable to create Directory: " + dir.getAbsolutePath()); } } return fileName; } public static boolean tryMkdirs(final String fileName) { File dir = null; final String ext = PathUtils.getFilenameExtension(fileName); if (!StringUtils.hasText(ext)) { dir = new File(fileName); } else { final File file = new File(fileName); dir = file.getParentFile(); } return (null != dir && !dir.exists()) && dir.mkdirs(); } public static void delete(final String[] paths) throws IOException { for (final String path : paths) { delete(path); } } public static void delete(final String path) throws IOException { final File file = new File(path); if (file.exists()) { if (file.isFile()) { file.delete(); } else { final Path root = Paths.get(path); Files.walkFileTree(root, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { Files.delete(file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(final Path file, final BasicFileAttributes attrs) throws IOException { if (!file.toString().equalsIgnoreCase(root.toString())) { delete(file.toString()); } return FileVisitResult.CONTINUE; } }); try { file.delete(); } catch (Throwable ignored) { } } } } public static boolean exists(final String fileName) { return (new File(fileName)).exists(); } public static long getCRC(final String fileName) { long result = 0; try { final FileInputStream is = new FileInputStream(fileName); try { result = getCRC(is); } finally { is.close(); } } catch (Throwable ignored) { } return result; } public static long getCRC(final File file) { long result = 0; try { final FileInputStream is = new FileInputStream(file); try { result = getCRC(is); } finally { is.close(); } } catch (Throwable ignored) { } return result; } public static long getCRC(final InputStream is) { try { // Computer CRC32 checksum final CheckedInputStream cis = new CheckedInputStream( is, new CRC32()); byte[] buf = new byte[128]; while (cis.read(buf) >= 0) { } long checksum = cis.getChecksum().getValue(); // System.out.println(checksum + " " + fileSize + " " + fileName); return checksum; } catch (Throwable ignored) { } return 0; } public static long getSize(final String filename) { final File file = new File(filename); if (file.exists()) { return file.length(); } return 0; } public static long getSize(final InputStream is) { long size = 0L; try { byte[] barr = new byte[1024]; while (true) { int r = is.read(barr); if (r <= 0) { break; } size += r; } } catch (Throwable ignored) { } return size; } //--------------------------------------------------------------------- // Copy methods for java.io.File //--------------------------------------------------------------------- /** * Copy the contents of the given input File to the given output File. * * @param in the file to copy from * @param out the file to copy to * @throws java.io.IOException in case of I/O errors */ public static void copy(final File in, final File out) throws IOException { copy( new BufferedInputStream(new FileInputStream(in)), new BufferedOutputStream(new FileOutputStream(out))); } /** * Copy the contents of the given byte array to the given output File. * * @param in the byte array to copy from * @param out the file to copy to * @throws java.io.IOException in case of I/O errors */ public static void copy(byte[] in, File out) throws IOException { ByteArrayInputStream inStream = new ByteArrayInputStream(in); OutputStream outStream = new BufferedOutputStream(new FileOutputStream(out)); copy(inStream, outStream); } /** * Copy the contents of the given input File into a new byte array. * * @param in the file to copy from * @return the new byte array that has been copied to * @throws java.io.IOException in case of I/O errors */ public static byte[] copyToByteArray(final File in) throws IOException { return copyToByteArray(new BufferedInputStream(new FileInputStream(in))); } public static byte[] copyToByteArray(final File in, final long skip, final long length) throws IOException { return copyToByteArray(new BufferedInputStream(new FileInputStream(in)), skip, length); } /** * Copies a file or a directory into another. * <p/> * <p>If neither {@link #CP_UPDATE} nor {@link #CP_OVERWRITE}, * IOException is thrown if the destination exists. * * @param flags any combination of {@link #CP_UPDATE}, {@link #CP_PRESERVE}, * {@link #CP_OVERWRITE}. */ public static void copy(File src, File dst, int flags) throws IOException { if (!src.exists()) { throw new FileNotFoundException(src.toString()); } if (dst.isDirectory()) { if (src.isDirectory()) { copyDir(src, dst, flags); } else { copyFile(src, new File(dst, src.getName()), flags); } } else if (dst.isFile()) { if (src.isDirectory()) { throw new IOException("Unable to copy a directory, " + src + ", to a file, " + dst); } else { copyFile(src, dst, flags); } } else { if (src.isDirectory()) { copyDir(src, dst, flags); } else { copyFile(src, dst, flags); } } } //--------------------------------------------------------------------- // Copy methods for java.io.Reader / java.io.File //--------------------------------------------------------------------- /** * Copies a reader into a file (the original content, if any, are erased). * The source and destination files will be closed after copied. * * @param dst the destination * @param reader the source * @param charset the charset; null as default (ISO-8859-1). */ public static void copy(Reader reader, File dst, String charset) throws IOException { final File parent = dst.getParentFile(); if (parent != null) { parent.mkdirs(); } final Writer writer = charset != null ? new OutputStreamWriter(new FileOutputStream(dst), charset) : new FileWriter(dst); copy(reader, writer, true); } //--------------------------------------------------------------------- // Copy methods for java.io.InputStream / java.io.File //--------------------------------------------------------------------- /** * Copies an input stream into a file * (the original content, if any, are erased). * The file will be closed after copied. * * @param in the source * @param dst the destination */ public static void copy(final InputStream in, final File dst) throws IOException { final File parent = dst.getParentFile(); if (parent != null) { parent.mkdirs(); } final OutputStream out = new BufferedOutputStream(new FileOutputStream(dst)); copy(in, out); } //--------------------------------------------------------------------- // Copy methods for java.io.InputStream / java.io.OutputStream //--------------------------------------------------------------------- /** * Copy the contents of the given InputStream to the given OutputStream. * Closes both streams when done. * * @param in the stream to copy from * @param out the stream to copy to * @throws java.io.IOException in case of I/O errors */ public static void copy(final InputStream in, final OutputStream out) throws IOException { try { byte[] buffer = new byte[BLOCK_SIZE]; int nrOfBytes = -1; while ((nrOfBytes = in.read(buffer)) != -1) { out.write(buffer, 0, nrOfBytes); } out.flush(); } finally { try { in.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close InputStream", ex); } try { out.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close OutputStream", ex); } } } /** * Copy a chunk of given input to output. * * @param in the stream to copy from * @param out the stream to copy to * @param offset skip bytes length * @param length read length * @throws IOException */ public static void copy(final InputStream in, final OutputStream out, final long offset, final long length) throws IOException { try { in.skip(offset); byte[] buffer = new byte[BLOCK_SIZE]; long count = 0; while (true) { long remaining = length - count; int read = in.read(buffer, 0, remaining > buffer.length ? buffer.length : (int) remaining); if (read <= 0) break; count += read; out.write(buffer, 0, read); if (count >= length) break; } out.flush(); } finally { try { in.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close InputStream", ex); } try { out.close(); } catch (IOException ex) { logger.log(Level.WARNING, "Could not close OutputStream", ex); } } } /** * Copy the contents of the given byte array to the given OutputStream. * * @param in the byte array to copy from * @param out the OutputStream to copy to * @throws java.io.IOException in case of I/O errors */ public static void copy(byte[] in, OutputStream out) throws IOException { copy(new ByteArrayInputStream(in), out); } /** * Copy the contents of the given InputStream into a new byte array. * * @param in the stream to copy from * @return the new byte array that has been copied to * @throws java.io.IOException in case of I/O errors */ public static byte[] copyToByteArray(final InputStream in) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); copy(in, out); return out.toByteArray(); } public static byte[] copyToByteArray(final InputStream in, final long skip, final long length) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); copy(in, out, skip, length); return out.toByteArray(); } //--------------------------------------------------------------------- // Copy methods for java.io.Reader / java.io.Writer //--------------------------------------------------------------------- /** * Copy the contents of the given Reader to the given Writer. * Closes both when done. * * @param reader the Reader to copy from * @param writer the Writer to copy to * @throws java.io.IOException reader case of I/O errors */ public static void copy(final Reader reader, final Writer writer) throws IOException { copy(reader, writer, true); } /** * Copy the contents of the given Reader to the given Writer. * Closes both when done. * * @param reader the Reader to copy from * @param writer the Writer to copy to * @param close True if reader and writer must be closed on exit. * @throws java.io.IOException reader case of I/O errors */ public static void copy(final Reader reader, final Writer writer, final boolean close) throws IOException { try { final char[] buf = new char[BLOCK_SIZE]; for (int v; (v = reader.read(buf)) >= 0; ) { if (v > 0) { writer.write(buf, 0, v); } } writer.flush(); } finally { try { if (close) { reader.close(); } } catch (IOException ex) { logger.log(Level.WARNING, "Could not close Reader", ex); } try { if (close) { writer.close(); } } catch (IOException ex) { logger.log(Level.WARNING, "Could not close Writer", ex); } } } /** * Copy the contents of the given String to the given output Writer. * * @param in the String to copy from * @param out the Writer to copy to * @throws java.io.IOException in case of I/O errors */ public static void copy(String in, Writer out) throws IOException { copy(new StringReader(in), out, true); } /** * Copy the contents of the given Reader into a String. * * @param in the reader to copy from * @return the String that has been copied to * @throws java.io.IOException in case of I/O errors */ public static String copyToString(final Reader in) throws IOException { final StringWriter out = new StringWriter(); copy(in, out, true); return out.toString(); } /** * Returns all characters reader the reader, never null * (but its length might zero). * <p>Notice: this method is memory hungry. */ public static StringBuffer copyToStringBuffer(Reader in) throws IOException { final StringWriter out = new StringWriter(BLOCK_SIZE); copy(in, out, true); return out.getBuffer(); } /** * Shortcut to copy(string.getBytes(encoding), output); * * @param output File * @param data Data to write * @param encoding charset * @throws IOException */ public static void writeStringToFile(final File output, final String data, final String encoding) throws IOException { final byte[] bytes = data.getBytes(encoding); copy(bytes, output); } /** * Shortcut to new String(copyToByteArray(file)); * * @param file File * @return String * @throws IOException */ public static String readFileToString(final File file) throws IOException { final byte[] bytes = copyToByteArray(file); return new String(bytes); } public static String readFileToString(final File file, final String encoding) throws IOException { final byte[] bytes = copyToByteArray(file); return new String(bytes, encoding); } //--------------------------------------------------------------------- // List methods //--------------------------------------------------------------------- public static void listFiles(final List<File> fileList, final List<File> startDir) { for (final File file : startDir) { if (file.isDirectory()) { listFiles(fileList, file); } else { fileList.add(file); } } } public static void listFiles(final List<File> fileList, final File startDir) { listFiles(fileList, startDir, "*.*", null, -1); } public static void listFiles(final List<File> fileList, final File startDir, final String includeWildChars) { listFiles(fileList, startDir, includeWildChars, null, -1); } /** * Get all the files under the specified folder (including all the files under sub-folders) * * @param startDir Initial folder * @param includeWildChars Allowed comma separated wild chars. i.e. "*.html, *.zip" or "*.*" * @param excludeWildChars Disallowed comma separated wild chars. i.e. "template*.html, *.zip". * @param fileList - the fileList to be returned */ public static void listFiles(final List<File> fileList, final File startDir, final String includeWildChars, final String excludeWildChars) { listFiles(fileList, startDir, includeWildChars, excludeWildChars, -1); } /** * List all files included in includeWildChars rage, but not included in * excludeWildChars range. * * @param startDir Starting directory * @param includeWildChars Comma separated values of wild-char to include. i.e. * "*.png, *.jpg" * @param excludeWildChars Comma separated values of wild-char to exclude. i.e. * "template*.png, template*.jpg" * @param deepLevel Level of recursion. If -1, all folders will be explored. * @param fileList A list to fill with retrieved file names. */ public static void listFiles(final List<File> fileList, final File startDir, final String includeWildChars, final String excludeWildChars, int deepLevel) { final String iwc; if (!StringUtils.hasLength(includeWildChars)) { iwc = "*.*"; } else { iwc = includeWildChars; } final String ewc; if (!StringUtils.hasLength(excludeWildChars)) { ewc = null; } else { ewc = excludeWildChars; } final String[] iwcTokens = StringUtils.split(iwc, ","); final String[] ewcTokens = StringUtils.split(ewc, ","); listAllFiles(fileList, startDir, // starting dir iwcTokens, // include tokens ewcTokens, // exclude tokens 0, // current level deepLevel // max deep level ); } // ------------------------------------------------------------------------ // p r i v a t e // ------------------------------------------------------------------------ /** * Assumes both dst and src is a file. */ private static void copyFile(File src, File dst, int flags) throws IOException { assert src.isFile(); if (dst.equals(src)) { throw new IOException("Copy to the same file, " + src); } if ((flags & CP_OVERWRITE) == 0) { if ((flags & CP_UPDATE) != 0) { if (dst.lastModified() >= src.lastModified()) { return; } //nothing to do } else if (dst.exists()) { throw new IOException("The destination already exists, " + dst); } } copy(new FileInputStream(src), dst); if ((flags & CP_PRESERVE) != 0) { dst.setLastModified(src.lastModified()); } } /** * Assumes both dst and src is a directory. */ private static void copyDir(File src, File dst, int flags) throws IOException { assert src.isDirectory(); final File[] srcs = src.listFiles(); for (int j = 0; j < srcs.length; ++j) { copy(srcs[j], new File(dst, srcs[j].getName()), flags); //recursive } } private static void listAllFiles(final List<File> fileList, final File startDir, final String[] includeWildChars, final String[] excludeWildChars, final int currentLevel, final int deepLevel) { int level = currentLevel; if (startDir.exists() && startDir.isDirectory()) { final File[] files = startDir.listFiles(); if (null != files) { for (int i = 0; i < files.length; i++) { final File file = files[i]; if (file.isFile()) { if (fileMatch(file, includeWildChars, excludeWildChars)) { fileList.add(file); } } else if (file.isDirectory()) { if ((deepLevel > -1) && (level >= deepLevel)) { continue; } level++; try { listAllFiles(fileList, file, includeWildChars, excludeWildChars, level, deepLevel); } catch (Exception e) { } level--; } } } }// if } private static boolean fileMatch(final File file, final String[] includeWildChars, String... excludeWildChars) { if (null == excludeWildChars || excludeWildChars.length == 0) { return fileMatch(file, includeWildChars); } else { return fileMatch(file, includeWildChars) && !fileMatch(file, excludeWildChars); } } private static boolean fileMatch(final File file, final String[] wildChars) { boolean result = false; for (final String wildChar : wildChars) { final String[] tokens = wildChar.split("\\."); final String nameFilter = tokens[0]; final String extFilter = tokens[1]; final String fileName = file.getName().toLowerCase(); final String clearNameFilter = nameFilter.replace("*", ""); final String clearExtFilter = extFilter.replace("*", ""); if (extFilter.equals("*")) { // All extensions if (nameFilter.equals("*")) { // *.* result = true; } else if (nameFilter.endsWith("*")) { // file*.* if (fileName.startsWith(clearNameFilter.toLowerCase())) { result = true; } } else { // file.* if (fileName.equalsIgnoreCase(nameFilter)) { result = true; } } } else { // only certain extensions if (nameFilter.equals("*")) { // *.EXT if (fileName.endsWith(extFilter.toLowerCase())) { result = true; } } else if (nameFilter.endsWith("*")) { // file*.EXT if (fileName.startsWith(clearNameFilter.toLowerCase()) && fileName.endsWith(extFilter.toLowerCase())) { result = true; } } else { // file.EXT if (fileName.equalsIgnoreCase(nameFilter + "." + extFilter)) { result = true; } } } if (result) { break; } } return result; } }