/* * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.jcr.impl.util.io; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Created by The eXo Platform SAS. * * Helper contains method to perform operations with not empty directory. * * Date: 25 01 2011 * * @author <a href="mailto:anatoliy.bazko@exoplatform.com.ua">Anatoliy Bazko</a> * @version $Id: FSDirectory.java 34360 2010-11-11 11:11:11Z tolusha $ */ public class DirectoryHelper { /** * The logger instance for this class */ private static final Logger LOG = LoggerFactory.getLogger("exo.jcr.component.core.DirectoryHelper"); /** * Returns the files list of whole directory including its sub directories. * * @param srcPath * source path * @return List * @throws IOException * if any exception occurred */ public static List<File> listFiles(File srcPath) throws IOException { List<File> result = new ArrayList<File>(); if (!srcPath.isDirectory()) { throw new IOException(srcPath.getAbsolutePath() + " is a directory"); } for (File subFile : srcPath.listFiles()) { result.add(subFile); if (subFile.isDirectory()) { result.addAll(listFiles(subFile)); } } return result; } /** * Copy directory. * * @param srcPath * source path * @param dstPath * destination path * @throws IOException * if any exception occurred */ public static void copyDirectory(File srcPath, File dstPath) throws IOException { if (srcPath.isDirectory()) { if (!dstPath.exists()) { dstPath.mkdirs(); } String files[] = srcPath.list(); for (int i = 0; i < files.length; i++) { copyDirectory(new File(srcPath, files[i]), new File(dstPath, files[i])); } } else { InputStream in = null; OutputStream out = null; try { in = new FileInputStream(srcPath); out = new FileOutputStream(dstPath); transfer(in, out); } finally { if (in != null) { in.close(); } if (out != null) { out.flush(); out.close(); } } } } /** * Remove directory. * * @param dir * directory to remove * @throws IOException * if any exception occurred */ public static void removeDirectory(File dir) throws IOException { if (dir.isDirectory()) { for (File subFile : dir.listFiles()) { removeDirectory(subFile); } if (!dir.delete()) { throw new IOException("Can't remove folder : " + dir.getCanonicalPath()); } } else { if (!dir.delete()) { throw new IOException("Can't remove file : " + dir.getCanonicalPath()); } } } /** * Compress data. In case when <code>rootPath</code> is a directory this method * compress all files and folders inside the directory into single one. IOException * will be thrown if directory is empty. If the <code>rootPath</code> is the file * the only this file will be compressed. * * @param rootPath * the root path, can be the directory or the file * @param dstZipPath * the path to the destination compressed file * @throws IOException * if any exception occurred */ public static void compressDirectory(File rootPath, File dstZipPath) throws IOException { ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(dstZipPath)); try { if (rootPath.isDirectory()) { String[] files = rootPath.list(); if (files == null || files.length == 0) { // In java 7 no ZipException is thrown in case of an empty directory // so to remain compatible we need to throw it explicitly throw new ZipException("ZIP file must have at least one entry"); } for (int i = 0; i < files.length; i++) { compressDirectory("", new File(rootPath, files[i]), zip); } } else { compressDirectory("", rootPath, zip); } } finally { if (zip != null) { zip.flush(); zip.close(); } } } /** * Compress files and directories. */ private static void compressDirectory(String relativePath, File srcPath, ZipOutputStream zip) throws IOException { if (srcPath.isDirectory()) { zip.putNextEntry(new ZipEntry(relativePath + "/" + srcPath.getName() + "/")); zip.closeEntry(); String files[] = srcPath.list(); for (int i = 0; i < files.length; i++) { compressDirectory(relativePath + "/" + srcPath.getName(), new File(srcPath, files[i]), zip); } } else { InputStream in = new FileInputStream(srcPath); try { zip.putNextEntry(new ZipEntry(relativePath + "/" + srcPath.getName())); transfer(in, zip); zip.closeEntry(); } finally { if (in != null) { in.close(); } } } } /** * Uncompress data to the destination directory. * * @param srcZipPath * path to the compressed file, could be the file or the directory * @param dstDirPath * destination path * @throws IOException * if any exception occurred */ public static void uncompressDirectory(File srcZipPath, File dstDirPath) throws IOException { ZipInputStream in = new ZipInputStream(new FileInputStream(srcZipPath)); ZipEntry entry = null; try { while ((entry = in.getNextEntry()) != null) { File dstFile = new File(dstDirPath, entry.getName()); dstFile.getParentFile().mkdirs(); if (entry.isDirectory()) { dstFile.mkdirs(); } else { OutputStream out = new FileOutputStream(dstFile); try { transfer(in, out); } finally { out.close(); } } } } finally { if (in != null) { in.close(); } } } /** * Uncompress data to the destination directory. * * @param srcPath * path to the compressed file, could be the file or the directory * @param dstPath * destination path * @throws IOException * if any exception occurred */ public static void uncompressEveryFileFromDirectory(File srcPath, File dstPath) throws IOException { if (srcPath.isDirectory()) { if (!dstPath.exists()) { dstPath.mkdirs(); } String files[] = srcPath.list(); for (int i = 0; i < files.length; i++) { uncompressEveryFileFromDirectory(new File(srcPath, files[i]), new File(dstPath, files[i])); } } else { ZipInputStream in = null; OutputStream out = null; try { in = new ZipInputStream(new FileInputStream(srcPath)); in.getNextEntry(); out = new FileOutputStream(dstPath); transfer(in, out); } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } } } /** * Transfer bytes from in to out */ public static void transfer(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[2048]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } } /** * Rename file. Trying to remove destination first. * If file can't be renamed in standard way the coping * data will be used instead. * * @param srcFile * source file * @param dstFile * destination file * @throws IOException * if any exception occurred */ public static void deleteDstAndRename(File srcFile, File dstFile) throws IOException { if (dstFile.exists()) { if (!dstFile.delete()) { throw new IOException("Cannot delete " + dstFile); } } renameFile(srcFile, dstFile); } /** * Rename file. If file can't be renamed in standard way the coping * data will be used instead. * * @param srcFile * source file * @param dstFile * destination file * @throws IOException * if any exception occurred */ public static void renameFile(File srcFile, File dstFile) throws IOException { // Rename the srcFile file to the new one. Unfortunately, the renameTo() // method does not work reliably under some JVMs. Therefore, if the // rename fails, we manually rename by copying the srcFile file to the new one if (!srcFile.renameTo(dstFile)) { InputStream in = null; OutputStream out = null; try { in = new FileInputStream(srcFile); out = new FileOutputStream(dstFile); transfer(in, out); } catch (IOException ioe) { IOException newExc = new IOException("Cannot rename " + srcFile + " to " + dstFile); newExc.initCause(ioe); throw newExc; } finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } // delete the srcFile file. srcFile.delete(); } } /** * Returns the size of directory including all subfolders. */ public static long getSize(File dir) { long size = 0; for (File file : dir.listFiles()) { if (file.isFile()) { size += file.length(); } else { size += getSize(file); } } return size; } /** * Safely close {@link Closeable} instance. Log error * in case of exception. */ public static void safeClose(Closeable obj) { try { obj.close(); } catch (IOException e) { LOG.error("Error while closing " + obj, e); } } }