blob: 7b98b329ae0c9b6a45b65d38ed3c6660d638cfc7 [file] [log] [blame]
/*
* Copyright (c) 2007-2013 Eike Stepper (Berlin, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eike Stepper - initial API and implementation
* Christian W. Damus (CEA LIST) - bug 418454
*/
package org.eclipse.net4j.util.io;
import org.eclipse.net4j.internal.util.bundle.OM;
import org.eclipse.net4j.util.ReflectUtil;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.WrappedException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayReader;
import java.io.CharArrayWriter;
import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Eike Stepper
*/
public final class IOUtil
{
/**
* @since 3.1
*/
public static final int EOF = -1;
/**
* @since 3.1
*/
public static final long DEFAULT_TIMEOUT = 2500;
public static final int DEFAULT_BUFFER_SIZE = 8192;
/**
* @since 2.0
*/
public static final String WILDCARD_SINGLE_CHAR = "?"; //$NON-NLS-1$
/**
* @since 2.0
*/
public static final String WILDCARD_MULTI_CHARS = "*"; //$NON-NLS-1$
/**
* @since 2.0
*/
public static final String WILDCARD_MULTI_DIRS = "**"; //$NON-NLS-1$
private static final char SEP = File.separatorChar;
private static final char SEP_UNIX = '/';
private static final char SEP_WINDOWS = '\\';
private IOUtil()
{
}
public static InputStream IN()
{
return System.in;
}
public static PrintStream OUT()
{
return System.out;
}
public static PrintStream ERR()
{
return System.err;
}
/**
* @since 3.1
*/
public static void print(StackTraceElement[] elements)
{
print(elements, System.err);
}
/**
* @since 3.1
*/
public static void print(StackTraceElement[] elements, PrintStream stream)
{
synchronized (stream)
{
for (int i = 0; i < elements.length; i++)
{
stream.println("\tat " + elements[i]);
}
}
}
public static void print(Throwable t, PrintStream stream)
{
t.printStackTrace(stream);
}
public static void print(Throwable t)
{
print(t, System.err);
}
/**
* @since 2.0
*/
public static String toString(Throwable t)
{
try
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
String message = t.getMessage() + "\n"; //$NON-NLS-1$
bytes.write(message.getBytes());
print(t, new PrintStream(bytes));
return bytes.toString();
}
catch (IOException ex)
{
throw WrappedException.wrap(ex);
}
}
/**
* @since 3.5
*/
public static boolean isFreePort(int port)
{
ServerSocket socket = null;
try
{
socket = new ServerSocket(port);
return true;
}
catch (Throwable ex)
{
return false;
}
finally
{
IOUtil.closeSilent(socket);
}
}
/**
* @since 3.5
*/
public static int getFreePort() throws IOException
{
ServerSocket socket = null;
try
{
socket = new ServerSocket(0);
socket.setReuseAddress(true);
return socket.getLocalPort();
}
finally
{
IOUtil.closeSilent(socket);
}
}
/**
* @since 3.5
*/
public static boolean openSystemBrowser(String url)
{
try
{
ClassLoader classLoader = OM.BUNDLE.getClass().getClassLoader();
// java.awt.Desktop was introduced with Java 1.6!
Class<?> desktopClass = classLoader.loadClass("java.awt.Desktop");
Method getDesktopMethod = ReflectUtil.getMethod(desktopClass, "getDesktop");
Method browseMethod = ReflectUtil.getMethod(desktopClass, "browse", URI.class);
Object desktop = getDesktopMethod.invoke(null);
browseMethod.invoke(desktop, new URI(url));
return true;
}
catch (Throwable ex)
{
//$FALL-THROUGH$
}
return false;
}
public static FileInputStream openInputStream(String fileName) throws IORuntimeException
{
return openInputStream(new File(fileName));
}
public static FileInputStream openInputStream(File file) throws IORuntimeException
{
try
{
return new FileInputStream(file);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static FileOutputStream openOutputStream(String fileName) throws IORuntimeException
{
return openOutputStream(new File(fileName));
}
public static FileOutputStream openOutputStream(File file) throws IORuntimeException
{
try
{
return new FileOutputStream(file);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static FileReader openReader(String fileName) throws IORuntimeException
{
return openReader(new File(fileName));
}
public static FileReader openReader(File file) throws IORuntimeException
{
try
{
return new FileReader(file);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static FileWriter openWriter(String fileName) throws IORuntimeException
{
return openWriter(new File(fileName));
}
public static FileWriter openWriter(File file) throws IORuntimeException
{
try
{
return new FileWriter(file);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static Exception closeSilent(Closeable closeable)
{
try
{
if (closeable != null)
{
closeable.close();
}
return null;
}
catch (Exception ex)
{
OM.LOG.error(ex);
return ex;
}
}
public static void close(Closeable closeable) throws IORuntimeException
{
try
{
if (closeable != null)
{
closeable.close();
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static Exception closeSilent(org.eclipse.net4j.util.collection.Closeable closeable)
{
try
{
if (closeable != null)
{
closeable.close();
}
return null;
}
catch (Exception ex)
{
OM.LOG.error(ex);
return ex;
}
}
public static void close(org.eclipse.net4j.util.collection.Closeable closeable) throws IORuntimeException
{
if (closeable != null)
{
closeable.close();
}
}
/**
* @since 3.3
*/
public static IOException flushSilent(Flushable flushable)
{
try
{
if (flushable != null)
{
flushable.flush();
}
return null;
}
catch (IOException ex)
{
OM.LOG.error(ex);
return ex;
}
}
/**
* @since 3.3
*/
public static void flush(Flushable flushable) throws IORuntimeException
{
try
{
if (flushable != null)
{
flushable.flush();
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
/**
* @since 2.0
*/
public static String makeRelative(File file, File toFolder)
{
String fileName = normalizeSeparator(file.getAbsolutePath());
String folderName = normalizeSeparator(toFolder.getAbsolutePath());
if (fileName.startsWith(folderName))
{
String relative = fileName.substring(folderName.length());
if (relative.startsWith(File.separator))
{
relative = relative.substring(1);
}
return relative;
}
throw new IllegalArgumentException("Different prefixes: " + fileName + " != " + folderName); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* @since 2.0
*/
public static String normalizeSeparator(String string)
{
if (SEP == SEP_UNIX)
{
return string.replace(SEP_WINDOWS, SEP_UNIX);
}
else if (SEP == SEP_WINDOWS)
{
return string.replace(SEP_UNIX, SEP_WINDOWS);
}
return string;
}
public static void mkdirs(File folder)
{
if (!folder.exists())
{
if (!folder.mkdirs())
{
throw new IORuntimeException("Unable to create directory " + folder.getAbsolutePath()); //$NON-NLS-1$
}
}
}
public static int delete(File file)
{
if (file == null)
{
return 0;
}
int deleted = 0;
if (file.isDirectory())
{
for (File child : file.listFiles())
{
deleted += delete(child);
}
}
if (file.delete())
{
return deleted + 1;
}
file.deleteOnExit();
return deleted;
}
public static void copyTree(File source, File target) throws IORuntimeException
{
if (source.isDirectory())
{
mkdirs(target);
File[] files = source.listFiles();
for (File file : files)
{
String name = file.getName();
copyTree(new File(source, name), new File(target, name));
}
}
else
{
copyFile(source, target);
}
}
public static void copyTrees(Collection<File> sources, File target) throws IORuntimeException
{
for (File source : sources)
{
copyTree(source, target);
}
}
public static void copyText(File source, File target, IOFilter<String>... lineFilters) throws IORuntimeException
{
BufferedReader reader = null;
BufferedWriter writer = null;
try
{
reader = new BufferedReader(openReader(source));
writer = new BufferedWriter(openWriter(target));
copyText(reader, writer, lineFilters);
}
finally
{
closeSilent(reader);
closeSilent(writer);
}
}
public static void copyText(BufferedReader reader, BufferedWriter writer, IOFilter<String>... lineFilters)
{
try
{
String line;
while ((line = reader.readLine()) != null)
{
for (IOFilter<String> lineFilter : lineFilters)
{
line = lineFilter.filter(line);
}
writer.write(line);
writer.newLine();
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
/**
* @since 3.1
*/
public static long copyBinary(InputStream inputStream, OutputStream outputStream) throws IOException
{
if (!(inputStream instanceof BufferedInputStream) && !(inputStream instanceof ByteArrayInputStream))
{
inputStream = new BufferedInputStream(inputStream);
}
if (!(outputStream instanceof BufferedOutputStream) && !(outputStream instanceof ByteArrayOutputStream))
{
outputStream = new BufferedOutputStream(outputStream);
}
long size = 0;
int b;
while ((b = inputStream.read()) != EOF)
{
outputStream.write(b);
++size;
}
outputStream.flush();
return size;
}
/**
* @since 3.1
*/
public static void copyBinary(InputStream inputStream, OutputStream outputStream, long size) throws IOException
{
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
long remaining = size;
while (remaining > 0L)
{
int bytesToCopy = (int)Math.min(remaining, buffer.length);
int bytesRead = inputStream.read(buffer, 0, bytesToCopy);
if (bytesRead < 1)
{
throw new EOFException("Read only " + (size - remaining) + "+" + bytesRead + "="
+ (size - remaining + bytesRead) + " but expected to read " + size);
}
outputStream.write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
outputStream.flush();
}
/**
* @since 3.1
*/
public static long copyCharacter(Reader reader, Writer writer) throws IOException
{
if (!(reader instanceof BufferedReader) && !(reader instanceof CharArrayReader))
{
reader = new BufferedReader(reader);
}
if (!(writer instanceof BufferedWriter) && !(writer instanceof CharArrayWriter))
{
writer = new BufferedWriter(writer);
}
long size = 0;
int c;
while ((c = reader.read()) != EOF)
{
writer.write(c);
++size;
}
writer.flush();
return size;
}
/**
* @since 3.1
*/
public static void copyCharacter(Reader reader, Writer writer, long size) throws IOException
{
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
long remaining = size;
while (remaining > 0L)
{
int charsToCopy = (int)Math.min(remaining, buffer.length);
int charsRead = reader.read(buffer, 0, charsToCopy);
if (charsRead < 1)
{
throw new EOFException("Read only " + (size - remaining) + "+" + charsRead + "="
+ (size - remaining + charsRead) + " but expected to read " + size);
}
writer.write(buffer, 0, charsRead);
remaining -= charsRead;
}
writer.flush();
}
public static int copy(InputStream input, OutputStream output, int size, byte buffer[]) throws IORuntimeException
{
try
{
int written = 0;
int bufferSize = buffer.length;
int n = Math.min(size, bufferSize);
while (n > 0 && (n = input.read(buffer, 0, n)) != -1)
{
output.write(buffer, 0, n);
written += n;
size -= n;
n = Math.min(size, bufferSize);
}
return written;
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static void copy(InputStream input, OutputStream output, byte buffer[]) throws IORuntimeException
{
try
{
int n;
while ((n = input.read(buffer)) != -1)
{
output.write(buffer, 0, n);
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static void copy(InputStream input, OutputStream output, int bufferSize) throws IORuntimeException
{
copy(input, output, new byte[bufferSize]);
}
public static void copy(InputStream input, OutputStream output) throws IORuntimeException
{
copy(input, output, DEFAULT_BUFFER_SIZE);
}
/**
* @see NIOUtil#copyFile(File, File)
*/
public static void copyFile(File source, File target) throws IORuntimeException
{
mkdirs(target.getParentFile());
FileInputStream input = null;
FileOutputStream output = null;
try
{
input = openInputStream(source);
output = openOutputStream(target);
copy(input, output);
}
finally
{
closeSilent(input);
closeSilent(output);
}
}
/**
* @since 3.4
*/
public static String readText(URL url) throws IORuntimeException
{
Reader input = null;
try
{
URLConnection connection = url.openConnection();
connection.setDoInput(true);
connection.setUseCaches(true);
connection.connect();
Charset charset;
String encoding = connection.getContentEncoding();
if (encoding == null)
{
charset = Charset.defaultCharset();
}
else
{
charset = Charset.forName(encoding);
}
input = new InputStreamReader(connection.getInputStream(), charset);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
try
{
CharArrayWriter output = new CharArrayWriter();
copyCharacter(input, output);
return output.toString();
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
finally
{
closeSilent(input);
}
}
/**
* @since 3.1
*/
public static String readTextFile(File file) throws IORuntimeException
{
Reader input = openReader(file);
try
{
CharArrayWriter output = new CharArrayWriter();
copyCharacter(input, output);
return output.toString();
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
finally
{
closeSilent(input);
}
}
public static byte[] readFile(File file) throws IORuntimeException
{
if (file.length() > Integer.MAX_VALUE)
{
throw new IllegalArgumentException("File too long: " + file.length()); //$NON-NLS-1$
}
int size = (int)file.length();
FileInputStream input = openInputStream(file);
try
{
ByteArrayOutputStream output = new ByteArrayOutputStream(size);
copy(input, output);
return output.toByteArray();
}
finally
{
closeSilent(input);
}
}
public static void writeFile(File file, byte[] bytes) throws IORuntimeException
{
FileOutputStream output = openOutputStream(file);
try
{
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
copy(input, output);
}
finally
{
closeSilent(output);
}
}
public static List<File> listDepthFirst(File file)
{
FileCollector collector = new FileCollector();
visitDepthFirst(file, collector);
return collector.getFiles();
}
public static List<File> listBreadthFirst(File file)
{
FileCollector collector = new FileCollector();
visitBreadthFirst(file, collector);
return collector.getFiles();
}
public static void visitDepthFirst(File file, IOVisitor visitor) throws IORuntimeException
{
try
{
boolean recurse = visitor.visit(file);
if (recurse && file.isDirectory())
{
visitDepthFirst(file.listFiles(), visitor);
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static void visitDepthFirst(File[] files, IOVisitor visitor)
{
for (File file : files)
{
visitDepthFirst(file, visitor);
}
}
public static void visitBreadthFirst(File file, IOVisitor visitor) throws IORuntimeException
{
File[] files = { file };
visitBreadthFirst(files, visitor);
}
public static void visitBreadthFirst(File[] files, IOVisitor visitor) throws IORuntimeException
{
try
{
boolean[] recurse = new boolean[files.length];
for (int i = 0; i < files.length; i++)
{
File file = files[i];
recurse[i] = visitor.visit(file);
}
for (int i = 0; i < files.length; i++)
{
File file = files[i];
if (file.isDirectory() && recurse[i])
{
File[] children = file.listFiles();
for (File child : children)
{
visitBreadthFirst(child, visitor);
}
}
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static <IO extends Closeable> void safeRun(IO io, IORunnable<IO> runnable) throws IORuntimeException
{
try
{
runnable.run(io);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
finally
{
close(io);
}
}
public static void safeInput(File file, IORunnable<FileInputStream> runnable) throws IORuntimeException
{
safeRun(openInputStream(file), runnable);
}
public static void safeOutput(File file, IORunnable<FileOutputStream> runnable) throws IORuntimeException
{
safeRun(openOutputStream(file), runnable);
}
public static void safeRead(File file, IORunnable<FileReader> runnable) throws IORuntimeException
{
safeRun(openReader(file), runnable);
}
public static void safeWrite(File file, IORunnable<FileWriter> runnable) throws IORuntimeException
{
safeRun(openWriter(file), runnable);
}
public static boolean equals(InputStream stream1, InputStream stream2) throws IORuntimeException
{
try
{
for (;;)
{
int byte1 = stream1.read();
int byte2 = stream2.read();
if (byte1 != byte2)
{
return false;
}
if (byte1 == -1) // Implies byte2 == -1
{
return true;
}
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
/**
* @since 3.2
*/
public static boolean equals(Reader reader1, Reader reader2) throws IORuntimeException
{
try
{
for (;;)
{
int char1 = reader1.read();
int char2 = reader2.read();
if (char1 != char2)
{
return false;
}
if (char1 == -1) // Implies char2 == -1
{
return true;
}
}
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
}
public static boolean equals(File file1, File file2) throws IORuntimeException
{
if (file1.length() != file2.length())
{
return false;
}
FileInputStream stream1 = null;
FileInputStream stream2 = null;
try
{
stream1 = new FileInputStream(file1);
stream2 = new FileInputStream(file2);
return equals(stream1, stream2);
}
catch (IOException ex)
{
throw new IORuntimeException(ex);
}
finally
{
closeSilent(stream1);
closeSilent(stream2);
}
}
/**
* @since 2.0
*/
public static List<File> glob(String pattern, File folder)
{
List<File> result = new ArrayList<File>();
pattern = normalizeSeparator(pattern);
if (pattern.endsWith(File.separator))
{
pattern += WILDCARD_MULTI_DIRS;
}
globRecurse(pattern, folder, result);
return result;
}
private static void globRecurse(String pattern, File folder, List<File> result)
{
int sep = pattern.indexOf(SEP);
if (sep != -1)
{
globSegment(pattern.substring(0, sep), pattern.substring(sep + 1), folder, result);
}
else
{
globSegment(pattern, null, folder, result);
}
}
private static void globSegment(String segment, String pattern, File folder, List<File> result)
{
boolean multiDirs = false;
if (segment.contains(WILDCARD_MULTI_DIRS))
{
if (!segment.equals(WILDCARD_MULTI_DIRS))
{
throw new IllegalArgumentException("Invalid pattern segment: " + segment); //$NON-NLS-1$
}
multiDirs = true;
}
for (File file : folder.listFiles())
{
String tmp = segment;
if (multiDirs && file.isDirectory())
{
globRecurse(WILDCARD_MULTI_DIRS + File.separator + pattern, file, result);
tmp = WILDCARD_MULTI_CHARS;
}
if (StringUtil.glob(tmp, file.getName()))
{
if (pattern == null)
{
// Match
result.add(file);
}
else if (file.isDirectory())
{
// Recurse
globRecurse(pattern, file, result);
}
}
}
}
/**
* @author Eike Stepper
*/
public static class FileCollector implements IOVisitor
{
private List<File> files = new ArrayList<File>();
public FileCollector()
{
}
public List<File> getFiles()
{
return files;
}
public boolean visit(File file) throws IOException
{
files.add(file);
return true;
}
}
}