/*
* Copyright (C) 2006 http://www.chaidb.org
*
* 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 2
* 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.
*
*/
package org.chaidb.db.helper;
import org.apache.log4j.Logger;
import java.io.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
/**
* Implements some file system related utility methods in a platform independent
* manner.
*/
public class FileUtil {
public static final String ZIP = ".zip";
private static final Logger logger = Logger.getLogger(FileUtil.class);
/**
* File separator on this platform
*/
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
/**
* deletes a file or a directory including all files and sub-directories
*
* @param tbrDir The file/directory to be removed
* @return A boolean flag indicating whether the file has been deleted
* successfully
*/
public static boolean removeFileOrDirectory(File tbrDir) {
if (!tbrDir.isDirectory()) {
return tbrDir.delete();
}
String[] filesTbd = tbrDir.list();
if (filesTbd != null) {
for (int i = 0; i < filesTbd.length; i++) {
String f_str = tbrDir.getAbsolutePath() + FILE_SEPARATOR + filesTbd[i];
/* if (f_str.indexOf(":")>0) {
f_str = f_str.substring(f_str.indexOf(":")+1);
}
*/
File tbd = new File(f_str);
if (tbd.isDirectory()) {
if (!removeFileOrDirectory(tbd)) return false;
} else {
if (!tbd.delete()) return false;
}
}
}
return tbrDir.delete();
}
public static boolean removeFiles(File tbrDir, String regEx) {
if (!tbrDir.isDirectory()) {
if (matchPattern(tbrDir.getName(), regEx)) {
return tbrDir.delete();
} else {
return true;
}
}
String[] filesTbd = tbrDir.list();
if (filesTbd != null) {
for (int i = 0; i < filesTbd.length; i++) {
String f_str = tbrDir.getAbsolutePath() + FILE_SEPARATOR + filesTbd[i];
/* if (f_str.indexOf(":")>0) {
f_str = f_str.substring(f_str.indexOf(":")+1);
}
*/
File tbd = new File(f_str);
if (tbd.isDirectory()) {
if (!removeFiles(tbd, regEx)) return false;
} else {
if (matchPattern(tbd.getName(), regEx)) {
if (!tbd.delete()) return false;
}
}
}
}
return true;
}
public static boolean matchPattern(String fileName, String regex) {
if (regex == null) return true;
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(fileName);
return m.matches();
}
public static long getFileOrDirectorySize(File tbrDir) {
long size = 0;
if (!tbrDir.isDirectory()) {
size = size + tbrDir.length();
} else {
String[] filesTbd = tbrDir.list();
if (filesTbd != null) {
for (int i = 0; i < filesTbd.length; i++) {
String f_str = tbrDir.getAbsolutePath() + FILE_SEPARATOR + filesTbd[i];
File tbd = new File(f_str);
if (tbd.isDirectory()) {
size = size + getFileOrDirectorySize(tbd);
} else {
size = size + tbd.length();
}
}
}
}
return size;
}
public static boolean emptyDirectory(File dir, boolean recursive) {
if (!dir.isDirectory()) {
return false;
}
File[] files = dir.listFiles();
if (files == null) {
return false;
}
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory() && recursive) {
if (!emptyDirectory(files[i], recursive)) return false;
} else {
if (!files[i].delete()) return false;
}
}
return true;
}
public static boolean removeDirectory(String dir) {
File dirFile = new File(dir);
if (!dirFile.isDirectory()) return false;
return removeFileOrDirectory(dirFile);
}
/**
* saves file as dir/fileName
*
* @param dir The dir to save the file
* @param fileName The file name
* @param in The inputstream which holds the content of the file
*/
public static void saveFile(String dir, String fileName, InputStream in) throws IOException {
FileOutputStream out = new FileOutputStream(new File(dir + File.separator + fileName));
byte[] buf = new byte[1024];
int ret = in.read(buf);
while (ret > 0) {
out.write(buf, 0, ret);
ret = in.read(buf);
}
out.close();
in.close();
}
public static void saveFile(String filePath, InputStream in) throws IOException {
FileOutputStream out = new FileOutputStream(new File(filePath));
byte[] buf = new byte[1024];
int ret = in.read(buf);
while (ret > 0) {
out.write(buf, 0, ret);
ret = in.read(buf);
}
out.close();
in.close();
}
public static void saveFile(String filePath, String content) throws IOException {
FileOutputStream out = new FileOutputStream(filePath);
byte[] data = null;
try {
data = content.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
}
out.write(data);
out.close();
}
/**
* reads the entire contents of a file and returns them as a byte array
*
* @param file The file whose contents are to be read
* @throws IOException Exception while reading from the input file
*/
public static byte[] readFileContents(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int available = fis.available();
while (available > 0) {
byte[] availableBytes = new byte[available];
int bytesRead = fis.read(availableBytes);
baos.write(availableBytes, 0, bytesRead);
available = fis.available();
}
fis.close();
return baos.toByteArray();
}
public static void copyFile(String srcName, String destName) throws IOException {
FileInputStream fi = null;
FileOutputStream fo = null;
long lastMT = new File(srcName).lastModified();
try {
fi = new FileInputStream(srcName);
fo = new FileOutputStream(destName);
byte[] buff = new byte[4096];
while (true) {
int nReaded = fi.read(buff);
if (nReaded < 0) {
break;
}
fo.write(buff, 0, nReaded);
}
fo.close();
fo = null;
new File(destName).setLastModified(lastMT);
} finally {
if (fi != null) {
try {
fi.close();
} catch (Exception e) {
}
}
if (fo != null) {
try {
fo.close();
} catch (Exception e) {
}
}
}
}
public static void copyDirectory(String srcName, String destName) throws IOException {
File srcDir = new File(srcName);
if (!srcDir.isDirectory()) throw new IOException("Source file: " + srcName + " is not a directory");
File destDir = new File(destName);
if (!destDir.exists()) {
if (!destDir.mkdirs()) throw new IOException("Can't create destination directory:" + destName);
}
File[] srcFiles = srcDir.listFiles();
// String localDir = srcDir.getAbsolutePath();
if (srcFiles != null) {
for (int i = 0; i < srcFiles.length; i++) {
String destFileName = destName + File.separatorChar + srcFiles[i].getName();
if (srcFiles[i].isDirectory()) {
copyDirectory(srcFiles[i].toString(), destFileName);
} else {
copyFile(srcFiles[i].toString(), destFileName);
}
}
}
}
/* copy source file from srcFrom to srcTo, srcTo is excluded */
public static boolean copyFile(String srcName, long srcFrom, long srcTo, String dstName, long dstFrom) throws IOException {
RandomAccessFile fSrc = null;
RandomAccessFile fDst = null;
try {
int BLOCKSIZE = 4096;
byte[] buf = new byte[BLOCKSIZE];
fSrc = new RandomAccessFile(srcName, "r");
fDst = new RandomAccessFile(dstName, "rw");
fSrc.seek(srcFrom);
fDst.seek(dstFrom);
int size;
long len = srcTo - srcFrom;
while (len > 0) {
if (len > BLOCKSIZE) size = BLOCKSIZE;
else size = (int) len;
size = fSrc.read(buf, 0, size);
if (size < 0) break; //have error
fDst.write(buf, 0, size);
len = len - size;
}
} finally {
try {
if (fSrc != null) fSrc.close();
if (fDst != null) fDst.close();
} catch (IOException ioe) {
throw ioe;
}
} //finally
return true;
}
/**
* copy file from sSrcFileName into sDstFileName and the postion from
* lStart to lEnd, if the sDstFileName exist zip file then unzip it.
* After do it, it will exist the sDstFileName file, and if there the zip file,
* it will delete it.
*
* @param sSrcFileName
* @param lFrom
* @param lTo
* @param sDstFileName
*/
public static void copyFile(String sSrcFileName, long lFrom, long lTo, String sDstFileName) throws FileNotFoundException, IOException {
if (hasZipFile(sDstFileName)) {
unzipFile(sDstFileName, 0, sDstFileName);
File f = new File(sDstFileName + ZIP);
f.delete();
}
copyFile(sSrcFileName, lFrom, lTo, sDstFileName, lFrom);
}
/**
* write fully lCount data to the out.
* Try read from input, if there are no datas to read then using padded data
* to fill untill the out data reached lCount length.
*
* @param input
* @param lCount
* @param out
* @param nBufferSize buffer length
* @param data temporary data buffer, it's used for improve program performance.
* @throws IOException
*/
private static void writeFully(InputStream input, long lCount, OutputStream out, int nBufferSize, byte[] data) throws IOException {
if (lCount <= 0) {
return;
}
long lReserved = lCount;
int nShouldRead = 0;
while (true) {
//caculate should read
if (lReserved >= nBufferSize) {
nShouldRead = nBufferSize;
} else {
nShouldRead = (int) lReserved;
}
int nReaded = input.read(data, 0, nShouldRead);
//If can read then read and write, else use 0 to padded it.
if (nReaded != -1) {
out.write(data, 0, nReaded);
lReserved -= nReaded;
} else {
Arrays.fill(data, (byte) 0);
out.write(data, 0, nShouldRead);
lReserved -= nShouldRead;
}
if (lReserved == 0) {
break;
}
}//end while
}
/**
* write fully lCount data to the out.
* Using padded data to fill untill the out data reached lCount length.
*
* @param lCount
* @param out
* @param nBufferSize buffer length
* @param data temporary data buffer, it's used for improve program performance.
* @throws IOException
*/
private static void writeFully(long lCount, OutputStream out, int nBufferSize, byte[] data) throws IOException {
if (lCount <= 0) {
return;
}
Arrays.fill(data, (byte) 0);
long lReserved = lCount;
int nShouldWrite = 0;
while (true) {
//caculate should read
if (lReserved >= nBufferSize) {
nShouldWrite = nBufferSize;
} else {
nShouldWrite = (int) lReserved;
}
out.write(data, 0, nShouldWrite);
lReserved -= nShouldWrite;
if (lReserved == 0) {
break;
}
}//end while
}
/**
* zip the sSrcFileName from lStart into the sDstFileName.
* If the unzip sDestFileName has been existed, you should first read the unzip
* dest file which readed length is lStart, and then zip it, the unzip
* sDestFileName should delete.
*
* @param sSrcFileName source file name
* @param lStart start position, it's also the destination file's start position
* @param sDstFileName destionation file, the file name isn't end with .zip,
* but aftered ziped, the filename will be added .zip.
*/
public static void zipFile(String sSrcFileName, long lStart, String sDstFileName) throws FileNotFoundException, IOException {
int nBufferSize = 4096;
FileOutputStream dest = null;
ZipOutputStream out = null;
BufferedInputStream bis = null;
File fDstFile = null;
if (hasZipFile(sDstFileName)) {
unzipFile(sDstFileName, 0, sDstFileName);
}
IOException ioe = null;
try {
dest = new FileOutputStream(sDstFileName + ZIP);
out = new ZipOutputStream(new BufferedOutputStream(dest));
ZipEntry entry = new ZipEntry(sDstFileName);
out.putNextEntry(entry);
bis = new BufferedInputStream(new FileInputStream(sSrcFileName), nBufferSize);
bis.skip(lStart);
byte[] data = new byte[nBufferSize];
//It has combined the dest file if it exists or filled char after
//executed the following codes.
fDstFile = new File(sDstFileName);
if (lStart > 0) {
if (fDstFile.exists()) {
FileInputStream normalFile = new FileInputStream(fDstFile);
writeFully(normalFile, lStart, out, nBufferSize, data);
normalFile.close();
}//end if
else {
writeFully(lStart, out, nBufferSize, data);
}//end else
}
//read from sSrcFileName into the sDstFileName
while (true) {
int nByte = bis.read(data);
if (nByte == -1) {
break;
}
out.write(data, 0, nByte);
}//end while
} catch (IOException ioe1) {
ioe = ioe1;
} finally {
try {
if (bis != null) {
bis.close();
}
if (out != null) {
out.close();
}
if (dest != null) {
dest.close();
}
} catch (Exception e) {
}
}//end finally
if (ioe != null) {
//if zip file failed, we should delete the zip file
try {
if (hasZipFile(sDstFileName)) {
File f = new File(sDstFileName + ZIP);
f.delete();
}
} catch (Exception e) {
}
throw ioe;
}
if (fDstFile != null) {
fDstFile.delete();
}
}
/**
* unzip the sSrcFileName.zip into the sDstFileName, the length is lLen.
*
* @param sSrcFileName which will be added .zip extention
* @param lLen unzip till to the length
* @param sDstFileName Destination file name which has no .zip
* @throws FileNotFoundException
* @throws IOException
*/
public static void unzipFile(String sSrcFileName, String sDstFileName, long lLen) throws FileNotFoundException, IOException {
int nBufferSize = 4096;
FileOutputStream dest = null;
BufferedInputStream bis = null;
ZipFile zipFile = null;
IOException ioe = null;
byte[] data = null;
try {
zipFile = new ZipFile(sSrcFileName + ZIP);
Enumeration e = zipFile.entries();
ZipEntry entry = null;
if (e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
}
bis = new BufferedInputStream(zipFile.getInputStream(entry));
dest = new FileOutputStream(sDstFileName);
data = new byte[nBufferSize];
writeFully(bis, lLen, dest, nBufferSize, data);
} catch (IOException e) {
ioe = e;
logger.warn(e);
} finally {
try {
if (bis != null) {
bis.close();
}
if (dest != null) {
dest.close();
}
if (zipFile != null) {
zipFile.close();
}
} catch (Exception e) {
}
}
if (ioe != null) {
//unzip file failed, retry to copy the orginal file
File f = new File(sSrcFileName);
if (!f.exists()) {
throw ioe;
}
bis = null;
dest = null;
RandomAccessFile rafDest = null;
if (data == null) {
data = new byte[nBufferSize];
}
try {
bis = new BufferedInputStream(new FileInputStream(f));
rafDest = new RandomAccessFile(sDstFileName, "rw");
dest = new FileOutputStream(rafDest.getFD());
writeFully(bis, lLen, dest, nBufferSize, data);
} finally {
try {
if (bis != null) {
bis.close();
}
if (dest != null) {
dest.close();
}
if (rafDest != null) {
rafDest.close();
}
} catch (Exception e) {
}
}
f = new File(sSrcFileName + ZIP);
if (f.exists()) {
f.delete();
}
}
}
/**
* conclude whether there are zip file exists
*/
public static boolean hasZipFile(String sFileName) {
File f = new File(sFileName + ZIP);
return f.exists();
}
/**
* unzip file sSrcFileName from lStart into sDstFileName
*
* @param sSrcFileName
* @param lStart
* @param sDstFileName
* @throws FileNotFoundException
* @throws IOException
*/
public static void unzipFile(String sSrcFileName, long lStart, String sDstFileName) throws FileNotFoundException, IOException {
int nBufferSize = 4096;
BufferedInputStream bis = null;
RandomAccessFile out = null;
ZipFile zipFile = null;
try {
zipFile = new ZipFile(sSrcFileName + ZIP);
Enumeration e = zipFile.entries();
ZipEntry entry = null;
if (e.hasMoreElements()) {
entry = (ZipEntry) e.nextElement();
}
bis = new BufferedInputStream(zipFile.getInputStream(entry));
bis.skip(lStart);
out = new RandomAccessFile(sDstFileName, "rw");
out.seek(lStart);
byte[] data = new byte[nBufferSize];
while (true) {
int nReaded = bis.read(data);
if (nReaded == -1) {
break;
}
out.write(data, 0, nReaded);
}//end while
} finally {
try {
if (out != null) {
out.close();
}
if (bis != null) {
bis.close();
}
if (zipFile != null) {
zipFile.close();
}
} catch (Exception e) {
}
}
}
public static void backupFile(String sSrcFileName, String tmpExt) throws IOException {
if (sSrcFileName == null || sSrcFileName.equalsIgnoreCase("")) {
return;
}
String sBakFileNam = sSrcFileName + "." + tmpExt;
File srcFile = new File(sSrcFileName);
File bakFile = new File(sBakFileNam);
if (bakFile.exists()) {
if (!bakFile.delete()) {
throw new IOException("Cannot remove old backup file.");
}
}
if (srcFile.exists()) {
if (!srcFile.renameTo(bakFile)) {
throw new IOException("Some files are used by other processes.");
}
try {
copyFile(sBakFileNam, sSrcFileName);
} catch (IOException e) {
srcFile = new File(sSrcFileName);
bakFile = new File(sBakFileNam);
if (srcFile.exists()) {
srcFile.delete();
}
bakFile.renameTo(srcFile);
throw e;
}
}
}
public static void restoreFile(String sSrcFileName, String tmpExt) throws IOException {
if (sSrcFileName == null || sSrcFileName.equalsIgnoreCase("")) {
return;
}
String sBakFileName = sSrcFileName + "." + tmpExt;
File srcFile = new File(sSrcFileName);
File bakFile = new File(sBakFileName);
if (srcFile.exists()) {
if (!srcFile.delete()) {
if (bakFile.exists()) {
throw new IOException("Cannot delete the broken file " + sSrcFileName + ", please restore it manually from " + sBakFileName);
} else {
throw new IOException("Cannot delete the broken file " + sSrcFileName + ", please delete it manually.");
}
}
}
if (bakFile.exists()) {
if (!bakFile.renameTo(srcFile)) {
try {
copyFile(sBakFileName, sSrcFileName);
} catch (IOException e) {
throw new IOException("Cannot restore " + sSrcFileName + " from " + sBakFileName + ", please restore it manually.");
}
bakFile.delete();
}
}
}
public static void clearBackupFile(String sSrcFileName, String tmpExt) {
if (sSrcFileName == null || sSrcFileName.equalsIgnoreCase("")) {
return;
}
String sBakFileName = sSrcFileName + "." + tmpExt;
File bakFile = new File(sBakFileName);
if (bakFile.exists()) {
bakFile.delete();
}
}
public static void createFileDir(String zipFile) throws IOException {
int lastIndex = zipFile.lastIndexOf(FILE_SEPARATOR);
String fileDirName = zipFile.substring(0, lastIndex);
new File(fileDirName).mkdirs();
}
}