/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library 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 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.command.util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.Flushable;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.List;
import java.util.LinkedList;
/**
* Convenience IO methods.
*
* @author chris boertien
*/
public final class IOUtils {
private static final int BUFFER_SIZE = 4096;
private static final String ex_null_param = "A required paramater is null";
/**
* Call the close method of a list of Closeable objects.
*
* This will not throw a NullPointerException if any of the objects are null.
*
* This is a convenience method that traps the exception from various
* stream close() methods.
*
* @param objs one or more Closeable objects.
*/
public static void close(Closeable... objs) {
close(false, objs);
}
/**
* Call the close method of a list of Closeable objects.
*
* If the flush parameter is set to true, and an object implements
* the Flushable interface, then the flush method will be called before
* the close method is called.
*
* This will not throw a NullPointerException if any of the objects are null.
*
* This will not throw an IOException if either the close or flush methods throw
* an IOException.
*
* If calling flush causes an IOException, close will still be called.
*
* @param flush if true, check if the object is Flushable
* @param objs one or more Closeable objects
*/
public static void close(boolean flush, Closeable... objs) {
for (Closeable obj : objs) {
if (obj != null) {
if (flush && (obj instanceof Flushable)) {
try {
((Flushable) obj).flush();
} catch (IOException _) {
// ignore
}
}
try {
obj.close();
} catch (IOException _) {
// ignore
}
}
}
}
/**
* Call the flush method of a list of Flushable objects.
*
* This method will not throw a NullPointerException if any of the objects are null.
*
* This method will trap the IOException from flush.
*
* @param objs one or more Flushable objects
*/
public static void flush(Flushable... objs) {
for (Flushable obj : objs) {
if (obj != null) {
try {
obj.flush();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* Copies data from an InputStream to an OutputStream.
*
* This method allocates a 4096 byte buffer each time it is called.
*
* At the end of writing, the OutputStream will be flushed, but no streams will be closed.
*
* @param in the stream to read from
* @param out the stream to write to
* @return the number of bytes read from the input stream
* @throws NullPointerException if either in or out are null
* @throws IOException if an I/O error occurs
*/
public static long copyStream(InputStream in, OutputStream out) throws IOException {
return copyStream(in, out, new byte[BUFFER_SIZE]);
}
/**
* Copies data from an InputStream to an OutputStream.
*
* This method allocates a buffer of 'bufferSize' when it is called.
*
* At the end of writing, the OutputStream will be flushed, but no streams will be closed.
*
* @param in the stream to read from
* @param out the stream to write to
* @param bufferSize the size of buffer to use for the copy
* @return the number of bytes read from the input stream
* @throws NullPointerException if either in or out are null
* @throws IOException if an I/O error occurs
*/
public static long copyStream(InputStream in, OutputStream out, int bufferSize) throws IOException {
return copyStream(in, out, new byte[bufferSize]);
}
/**
* Copies data from an InputStream to an OutputStream
*
* If copying multiple streams, this method may be prefered to the others
* as a way to use the same buffer instead of allocating a new buffer on each call.
*
* At the end of writing, the OutputStream will be flushed, but no streams will be closed.
*
* @param in the stream to read from
* @param out the stream to write to
* @param buffer a pre-allocated buffer to use.
* @return the number of bytes read from the input stream
* @throws NullPointerException if either in, out or buffer are null
* @throws IOException if an I/O error occurs
*/
public static long copyStream(InputStream in, OutputStream out, byte[] buffer) throws IOException {
checkNull(in, out, buffer);
long totalBytes = 0;
int len = 0;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
totalBytes += len;
}
out.flush();
return totalBytes;
}
/**
* Opens an InputStream on a file for reading.
*
* This method will not throw a FileNotFoundException or SecurityException like
* the FileInputStream constructor would.
*
* @param file the file to open a stream on
* @return an InputStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
*/
public static InputStream openInputStream(File file) {
return openInputStream(file, false);
}
/**
* Opens an InputStream on a file for reading.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileInputStream constructor would.
*
* @param file the file to open a stream on
* @param buffer if true, wrap the stream in a buffered stream
* @return an InpustStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
*/
public static InputStream openInputStream(File file, boolean buffer) {
return openInputStream(file, buffer, BUFFER_SIZE);
}
/**
* Opens an InputStream on a file for reading.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileInputStream constructor would.
*
* @param file the file to open a stream on
* @param buffer if true, wrap the stream in a buffered stream
* @param bufferSize the buffer size to use if buffer is true
* @return an InpustStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
* @throws IllegalArgumentException if bufferSize < 0
*/
public static InputStream openInputStream(File file, boolean buffer, int bufferSize) {
checkNull(file);
try {
InputStream in = new FileInputStream(file);
if (buffer) {
in = new BufferedInputStream(in, bufferSize);
}
return in;
} catch (FileNotFoundException e) {
return null;
} catch (SecurityException e2) {
return null;
}
}
/**
* Opens a Reader on a file.
*
* This method will not throw a FileNotFoundException like the FileReader
* constructor would.
*
* @param file the file to open the reader on
* @return the reader, or null if the file could not be opened
* @throws NullPointerException if file is null
*/
public static Reader openReader(File file) {
checkNull(file);
try {
return new FileReader(file);
} catch (FileNotFoundException e) {
// fall through
}
return null;
}
/**
* Opens a BufferedReader on a file.
*
* This method will not throw a FileNotFoundException like the FileReader
* constructor would.
*
* @param file the file to open the reader on
* @return the reader, or null if the file could not be opened
* @throws NullPointerException if file is null
*/
public static BufferedReader openBufferedReader(File file) {
return openBufferedReader(file, BUFFER_SIZE);
}
/**
* Opens a BufferedReader on a file.
*
* This method will not throw a FileNotFoundException like the FileReader
* constructor would.
*
* @param file the file to open the reader on
* @param bufferSize the buffer size to use for this reader
* @return the reader, or null if the file could not be opened
* @throws NullPointerException if file is null
*/
public static BufferedReader openBufferedReader(File file, int bufferSize) {
Reader reader = openReader(file);
if (reader != null) {
return new BufferedReader(reader, bufferSize);
}
return null;
}
/**
* Wraps a {@code Reader} with a {@code BufferedReader}.
*
* @param reader the reader to wrap
* @return a {@code BufferedReader}
* @throws NullPointerException if reader is null
*/
public static BufferedReader openBufferedReader(Reader reader) {
return openBufferedReader(reader, BUFFER_SIZE);
}
/**
* Wraps a {@code Reader} with a {@code BufferedReader}.
*
* @param reader the reader to wrap
* @param bufferSize the size of buffer to use
* @return a {@code BufferedReader}
* @throws NullPointerException if reader is null
*/
public static BufferedReader openBufferedReader(Reader reader, int bufferSize) {
checkNull(reader);
return new BufferedReader(reader, bufferSize);
}
/**
* Opens a LineNumberReader on a file.
*
* This method will not throw a FileNotFoundException like the FileReader
* constructor would.
*
* @param file the file to open the reader on
* @param bufferSize the buffer size to use for this reader
* @return the reader, or null if the file could not be opened
* @throws NullPointerException if file is null
*/
public static LineNumberReader openLineReader(File file, int bufferSize) {
Reader reader = openReader(file);
if (reader != null) {
return new LineNumberReader(reader, bufferSize);
}
return null;
}
/**
* Opens an OutputStream on a file for writing.
*
* If the file exists and has content, it will be overwritten. That is to say the append
* paramater will be false.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileOutputStream constructor would.
*
* @param file the file to open a stream on
* @return an OutputStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
*/
public static OutputStream openOutputStream(File file) {
return openOutputStream(file, false, 0);
}
/**
* Opens an OutputStream on a file for writing.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileOutputStream constructor would.
*
* @param file the file to open a stream on
* @param append if true, open the stream in append mode
* @return an OutputStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
*/
public static OutputStream openOutputstream(File file, boolean append) {
return openOutputStream(file, append, 0);
}
/**
* Opens an OutputStream on a file for writing.
*
* The stream will be wrapped in a buffered stream if bufferSize is > 0.
*
* If the file exists and has content, it will be overwritten. That is to say the append
* paramater will be false.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileOutputStream constructor would.
*
* @param file the file to open a stream on
* @param bufferSize if this is > 0, use it as the buffer size for the stream
* @return an OutputStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
* @throws IllegalArgumentException if bufferSize < 0
*/
public static OutputStream openOutputStream(File file, int bufferSize) {
return openOutputStream(file, false, bufferSize);
}
/**
* Opens an OutputStream on a file for writing.
*
* The stream will be wrapped in a buffered stream if bufferSize is > 0.
*
* This method will not throw a FileNotFoundException or a SecurityException like
* the FileOutputStream constructor would.
*
* @param file the file to open a stream on
* @param bufferSize if this is > 0, use it as the buffer size for the stream
* @param append if true, open the stream in append mode
* @return an OutputStream on the file, or null if an exception was thrown
* @throws NullPointerException if file is null
* @throws IllegalArgumentException if bufferSize < 0
*/
public static OutputStream openOutputStream(File file, boolean append, int bufferSize) {
checkNull(file);
try {
OutputStream out = new FileOutputStream(file, append);
if (bufferSize > 0) {
out = new BufferedOutputStream(out, bufferSize);
}
return out;
} catch (FileNotFoundException e) {
return null;
} catch (SecurityException e2) {
return null;
}
}
/**
* Prompt the user with a question, asking for a yes or no response.
*
* The default response if none is given will be 'yes'
*
* @param in the reader to read user input from.
* @param out the writer to send the prompt to the user
* @param prompt the prompt to send to the user
* @return true if the user said yes, false if no
*/
public static boolean promptYesOrNo(Reader in, PrintWriter out, String prompt) {
return promptYesOrNo(in, out, prompt, true);
}
/**
* Prompt the user with a question, asking for a yes or no response.
*
* If out is not attached to a terminal, then the user will not see the prompt
*
* If in is not attached to a terminal, then this method has undefined behavior.
*
* If the user inputs an answer that does not being with an 'n', 'N', 'y' or 'Y'
* then it will prompt the user again. If something causes this loop to execute
* indefinetly, it has limited loop iterations. If this loop cap is reached, the
* method will return false.
*
* If the user inputs nothing, then the defaultChoice is used.
*
* If the Reader is not a BufferedReader, then it will be wrapped in one.
*
* @param in the reader to read user input from.
* @param out the writer to send the prompt to the user
* @param prompt the prompt to send to the user
* @param defaultChoice if the user inputs no reply, this value is returned
* @return true if the user said yes, false if no
* @throws NullPointerException if in, out or str are null
*/
public static boolean promptYesOrNo(Reader in, PrintWriter out, String prompt, boolean defaultChoice) {
checkNull(in, out, prompt);
String input;
// put a cap on the loops so it doesn't become an infinite loop
// this can happen if Reader is not attached to a tty
for (int i = 0; i < 10; i++) {
input = prompt(in, out, prompt);
if (input == null) {
return false;
}
if (input.length() == 0) {
return defaultChoice;
}
switch(input.charAt(0)) {
case 'y' :
case 'Y' :
return true;
case 'n' :
case 'N' :
return false;
}
}
return false;
}
/**
* Prompt the user with a question and capture the response.
*
* If out is not attached to a terminal, then the user will not see the prompt
*
* If in is not attached to a terminal, then this method has undefined behavior.
*
* If the Reader is not a BufferedReader, then it will be wrapped in one.
*
* @param in the reader to read user input from.
* @param out the writer to send the prompt to the user
* @param prompt the prompt to send to the user
* @return the string captured from the user, or null if an I/O error occurred.
* @throws NullPointerException if in, out or str are null
*/
public static String prompt(Reader in, PrintWriter out, String prompt) {
checkNull(in, out, prompt);
String input;
BufferedReader reader;
if (in instanceof BufferedReader) {
reader = (BufferedReader) in;
} else {
reader = new BufferedReader(in);
}
out.print(prompt);
try {
input = reader.readLine();
} catch (IOException e) {
return null;
}
return input;
}
public static List<String> readLines(File file) {
BufferedReader reader = openBufferedReader(file);
if (reader == null) {
return null;
}
try {
return readLines(reader);
} finally {
close(reader);
}
}
public static List<String> readLines(Reader reader) {
return readLines(new BufferedReader(reader, BUFFER_SIZE), -1);
}
public static List<String> readLines(BufferedReader reader) {
return readLines(reader, -1);
}
/**
* Read all of the lines from a Reader.
*
* Calling this is the same as readLines(new BufferedReader(reader), max)
*
* @param reader the source to read from
* @param max the max number of lines to read, if this is -1 Integer.MAX_VALUE is used
* @return a list of strings, possibly empty, or null if there was an exception.
* @throws NullPointerException if reader is null
*/
public static List<String> readLines(Reader reader, int max) {
return readLines(new BufferedReader(reader, BUFFER_SIZE), max);
}
/**
* Read all of the lines from a Reader.
*
* If there are no lines to read, an empty List will be returned.
*
* If there was an exception while reading, null will be returned.
*
* @param reader the source to read from
* @param max the max number of lines to read, if this is -1 Integer.MAX_VALUE is used
* @return a list of strings, possibly empty, or null if there was an exception.
* @throws NullPointerException if reader is null
*/
public static List<String> readLines(BufferedReader reader, int max) {
checkNull(reader);
List<String> ret = new LinkedList<String>();
String line;
int count = 0;
try {
if (max > 0) {
while ((count++ < max) && (line = reader.readLine()) != null) {
ret.add(line);
}
} else {
while ((line = reader.readLine()) != null) {
ret.add(line);
}
}
} catch (IOException e) {
return null;
}
return ret;
}
/**
* Check for null objects in a list of objects.
*/
private static void checkNull(Object... objs) {
for (Object obj : objs) {
if (obj == null) throw new NullPointerException(ex_null_param);
}
}
}