/*
* (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This library 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.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.common.utils;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
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.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
*
*/
public final class FileUtils {
private static final int BUFFER_SIZE = 1024 * 64; // 64K
private static final int MAX_BUFFER_SIZE = 1024 * 1024; // 64K
private static final int MIN_BUFFER_SIZE = 1024 * 8; // 64K
private static final Log log = LogFactory.getLog(FileUtils.class);
// This is an utility class
private FileUtils() {
}
public static void safeClose(Closeable stream) {
try {
stream.close();
} catch (IOException e) {
// do nothing
}
}
private static byte[] createBuffer(int preferredSize) {
if (preferredSize < 1) {
preferredSize = BUFFER_SIZE;
}
if (preferredSize > MAX_BUFFER_SIZE) {
preferredSize = MAX_BUFFER_SIZE;
} else if (preferredSize < MIN_BUFFER_SIZE) {
preferredSize = MIN_BUFFER_SIZE;
}
return new byte[preferredSize];
}
public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = createBuffer(in.available());
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
public static String read(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
byte[] buffer = createBuffer(in.available());
try {
int read;
while ((read = in.read(buffer)) != -1) {
sb.append(new String(buffer, 0, read));
}
} finally {
in.close();
}
return sb.toString();
}
public static byte[] readBytes(URL url) throws IOException {
return readBytes(url.openStream());
}
public static byte[] readBytes(InputStream in) throws IOException {
byte[] buffer = createBuffer(in.available());
int w = 0;
try {
int read = 0;
int len;
do {
w += read;
len = buffer.length - w;
if (len <= 0) { // resize buffer
byte[] b = new byte[buffer.length + BUFFER_SIZE];
System.arraycopy(buffer, 0, b, 0, w);
buffer = b;
len = buffer.length - w;
}
} while ((read = in.read(buffer, w, len)) != -1);
} finally {
in.close();
}
if (buffer.length > w) { // compact buffer
byte[] b = new byte[w];
System.arraycopy(buffer, 0, b, 0, w);
buffer = b;
}
return buffer;
}
public static String readFile(File file) throws IOException {
FileInputStream in = null;
try {
in = new FileInputStream(file);
return read(in);
} finally {
if (in != null) {
in.close();
}
}
}
public static List<String> readLines(File file) throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader reader = null;
try {
InputStream in = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
return lines;
}
public static void writeLines(File file, List<String> lines) throws IOException {
PrintWriter out = null;
try {
out = new PrintWriter(new FileOutputStream(file));
for (String line : lines) {
out.println(line);
}
} finally {
if (out != null) {
out.close();
}
}
}
public static byte[] readBytes(File file) throws IOException {
FileInputStream in = null;
try {
in = new FileInputStream(file);
return readBytes(in);
} finally {
if (in != null) {
in.close();
}
}
}
public static void writeFile(File file, byte[] buf) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(buf);
} finally {
if (fos != null) {
fos.close();
}
}
}
public static void writeFile(File file, String buf) throws IOException {
writeFile(file, buf.getBytes());
}
public static void download(URL url, File file) throws IOException {
InputStream in = url.openStream();
OutputStream out = new FileOutputStream(file);
try {
copy(in, out);
} finally {
if (in != null) {
in.close();
}
out.close();
}
}
public static void deleteTree(File dir) {
emptyDirectory(dir);
dir.delete();
}
public static void emptyDirectory(File dir) {
File[] files = dir.listFiles();
if (files == null) {
return;
}
int len = files.length;
for (int i = 0; i < len; i++) {
File file = files[i];
if (file.isDirectory()) {
deleteTree(file);
} else {
file.delete();
}
}
}
public static void copyToFile(InputStream in, File file) throws IOException {
OutputStream out = null;
try {
out = new FileOutputStream(file);
byte[] buffer = createBuffer(in.available());
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
} finally {
if (out != null) {
out.close();
}
}
}
public static void append(File src, File dst) throws IOException {
append(src, dst, false);
}
public static void append(File src, File dst, boolean appendNewLine) throws IOException {
InputStream in = null;
try {
in = new FileInputStream(src);
append(in, dst, appendNewLine);
} finally {
if (in != null) {
in.close();
}
}
}
public static void append(InputStream in, File file) throws IOException {
append(in, file, false);
}
public static void append(InputStream in, File file, boolean appendNewLine) throws IOException {
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(file, true));
if (appendNewLine) {
out.write(System.getProperty("line.separator").getBytes());
}
byte[] buffer = new byte[BUFFER_SIZE];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
} finally {
if (out != null) {
out.close();
}
}
}
/**
* Copies source to destination. If source and destination are the same,
* does nothing. Both single files and directories are handled.
*
* @param src the source file or directory
* @param dst the destination file or directory
* @throws IOException
*/
public static void copy(File src, File dst) throws IOException {
if (src.equals(dst)) {
return;
}
if (src.isFile()) {
copyFile(src, dst);
} else {
copyTree(src, dst);
}
}
public static void copy(File[] src, File dst) throws IOException {
for (File file : src) {
copy(file, dst);
}
}
public static void copyFile(File src, File dst) throws IOException {
if (dst.isDirectory()) {
dst = new File(dst, src.getName());
}
FileInputStream in = null;
FileOutputStream out = new FileOutputStream(dst);
try {
in = new FileInputStream(src);
copy(in, out);
} finally {
if (in != null) {
in.close();
}
out.close();
}
}
/**
* Copies recursively source to destination.
* <p>
* The source file is assumed to be a directory.
*
* @param src the source directory
* @param dst the destination directory
* @throws IOException
*/
public static void copyTree(File src, File dst) throws IOException {
if (src.isFile()) {
copyFile(src, dst);
} else if (src.isDirectory()) {
if (dst.exists()) {
dst = new File(dst, src.getName());
dst.mkdir();
} else { // allows renaming dest dir
dst.mkdirs();
}
File[] files = src.listFiles();
for (File file : files) {
copyTree(file, dst);
}
}
}
public static void copyTree(File src, File dst, PathFilter filter) throws IOException {
if (!filter.accept(new Path(src.getAbsolutePath()))) {
return;
}
if (src.isFile()) {
copyFile(src, dst);
} else if (src.isDirectory()) {
if (dst.exists()) {
dst = new File(dst, src.getName());
dst.mkdir();
} else { // allow renaming dest dir
dst.mkdirs();
}
File[] files = src.listFiles();
for (File file : files) {
copyTree(file, dst, filter);
}
}
}
/**
* Decodes an URL path so that is can be processed as a filename later.
*
* @param url the Url to be processed.
* @return the decoded path.
*/
public static String getFilePathFromUrl(URL url) {
String path = "";
if (url.getProtocol().equals("file")) {
try {
path = URLDecoder.decode(url.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error(e);
}
}
return path;
}
public static File getFileFromURL(URL url) {
File file;
String filename = getFilePathFromUrl(url);
if (filename.equals("")) {
file = null;
} else {
file = new File(filename);
}
return file;
}
public static String getParentPath(String path) {
int p = path.lastIndexOf('/');
if (p == -1) {
return null;
}
return path.substring(0, p);
}
public static String getFileName(String path) {
int p = path.lastIndexOf('/');
if (p == -1) {
return path;
}
return path.substring(p + 1);
}
public static String getFileExtension(String path) {
int p = path.lastIndexOf('.');
if (p == -1) {
return null;
}
return path.substring(p + 1);
}
public static String getFileNameNoExt(String path) {
String name = getFileName(path);
int p = name.lastIndexOf('.');
if (p == -1) {
return name;
}
return name.substring(0, p);
}
/**
* Retrieves the total path of a resource from the Thread Context.
*
* @param resource the resource name to be retrieved.
* @return the decoded path.
*/
public static String getResourcePathFromContext(String resource) {
URL url = Thread.currentThread().getContextClassLoader().getResource(
resource);
return getFilePathFromUrl(url);
}
public static File getResourceFileFromContext(String resource) {
File file;
String filename = getResourcePathFromContext(resource);
if (filename.equals("")) {
file = null;
} else {
file = new File(filename);
}
return file;
}
public static File[] findFiles(File root, String pattern, boolean recurse) {
List<File> result = new ArrayList<File>();
if (pattern == null) {
if (recurse) {
collectFiles(root, result);
} else {
return root.listFiles();
}
} else {
FileNamePattern pat = new FileNamePattern(pattern);
if (recurse) {
collectFiles(root, pat, result);
} else {
File[] files = root.listFiles();
for (File file : files) {
if (pat.match(file.getName())) {
result.add(file);
}
}
}
}
return result.toArray(new File[result.size()]);
}
public static void collectFiles(File root, FileNamePattern pattern, List<File> result) {
File[] files = root.listFiles();
for (File file : files) {
if (pattern.match(file.getName())) {
result.add(file);
if (file.isDirectory()) {
collectFiles(file, pattern, result);
}
}
}
}
public static void collectFiles(File root, List<File> result) {
File[] files = root.listFiles();
for (File file : files) {
result.add(file);
if (file.isDirectory()) {
collectFiles(root, result);
}
}
}
public static void close(InputStream in) {
if (in != null) {
try {
in.close();
} catch (IOException e) {
log.error(e);
}
}
}
public static void close(OutputStream out) {
if (out != null) {
try {
out.close();
} catch (IOException e) {
log.error(e);
}
}
}
/**
* Create a file handler (this doesn't create a real file) given a file URI.
* This method can be used to create files from invalid URL strings (e.g. containing spaces ..)
* @return a file object
*/
public static File urlToFile(String url) throws MalformedURLException {
return urlToFile(new URL(url));
}
public static File urlToFile(URL url) {
try {
return new File(url.toURI());
} catch(URISyntaxException e) {
return new File(url.getPath());
}
}
public static List<String> readLines(InputStream in) throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
return lines;
}
}