package com.vaguehope.onosendai.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONTokener;
import android.database.Cursor;
public final class IoHelper {
private static final int I_1024 = 1024;
private static final int COPY_BUFFER_SIZE = 1024 * 4;
private IoHelper () {
throw new AssertionError();
}
public static void closeQuietly (final Cursor c) {
if (c == null) return;
c.close();
}
public static void closeQuietly (final Closeable c) {
if (c == null) return;
try {
c.close();
}
catch (final IOException e) {/**/} // NOSONAR this is intentional, is in the name of the method.
}
public static String readableFileSize (final long size) {
// http://stackoverflow.com/questions/3263892/format-file-size-as-mb-gb-etc
if (size <= 0) return "0";
final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
final int digitGroups = (int) (Math.log10(size) / Math.log10(I_1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(I_1024, digitGroups)) + " " + units[digitGroups];
}
public static long copy (final File source, final File sink) throws IOException {
final OutputStream out = new FileOutputStream(sink);
try {
return copy(source, out);
}
finally {
closeQuietly(out);
}
}
public static long copy (final File source, final OutputStream sink) throws IOException {
final InputStream in = new FileInputStream(source);
try {
return copy(in, sink);
}
finally {
closeQuietly(in);
}
}
public static long copy (final InputStream source, final File sink) throws IOException {
final OutputStream out = new FileOutputStream(sink);
try {
return copy(source, out);
}
finally {
closeQuietly(out);
}
}
public static long copy (final InputStream source, final OutputStream sink) throws IOException {
final byte[] buffer = new byte[COPY_BUFFER_SIZE];
long bytesReadTotal = 0L;
int bytesRead;
while ((bytesRead = source.read(buffer)) != -1) {
sink.write(buffer, 0, bytesRead);
bytesReadTotal += bytesRead;
}
return bytesReadTotal;
}
public interface CopyProgressListener {
void onCopyProgress (int bytesCopied);
}
public static int copyWithProgress (final InputStream source, final OutputStream sink, final CopyProgressListener listener) throws IOException {
final byte[] buffer = new byte[COPY_BUFFER_SIZE];
int bytesReadTotal = 0;
int bytesRead;
while ((bytesRead = source.read(buffer)) != -1) {
sink.write(buffer, 0, bytesRead);
bytesReadTotal += bytesRead;
listener.onCopyProgress(bytesReadTotal);
}
return bytesReadTotal;
}
public static String toString (final InputStream is) throws IOException {
return toString(is, -1);
}
public static String toString (final InputStream is, final int maxLength) throws IOException {
return toString(is, maxLength, null);
}
public static String toString (final InputStream is, final int maxLength, final String charsetName) throws IOException {
if (is == null) return null;
final StringBuilder sb = new StringBuilder();
final BufferedReader rd = new BufferedReader(new InputStreamReader(is, charsetName != null ? charsetName : "UTF-8"));
try {
String line;
while ((line = rd.readLine()) != null) {
if (sb.length() > 0) sb.append("\n");
if (maxLength < 0 || sb.length() + line.length() < maxLength) {
sb.append(line);
}
else {
sb.append(line.subSequence(0, maxLength - sb.length()));
}
if (maxLength >= 0 && sb.length() >= maxLength) break;
}
return sb.toString();
}
finally {
is.close();
}
}
/**
* Returns null if file does not exist.
*/
public static String fileToString (final File file) throws IOException {
try {
final FileInputStream stream = new FileInputStream(file);
try {
final FileChannel fc = stream.getChannel();
final MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
/* Instead of using default, pass in a decoder. */
return Charset.defaultCharset().decode(bb).toString();
}
finally {
stream.close();
}
}
catch (final FileNotFoundException e) {
return null;
}
}
public static void stringToFile (final String data, final File f) throws IOException {
streamToFile(new ByteArrayInputStream(data.getBytes("UTF-8")), f);
}
public static void resourceToFile (final String res, final File f) throws IOException {
final InputStream is = IoHelper.class.getResourceAsStream(res);
try {
streamToFile(is, f);
}
finally {
closeQuietly(is);
}
}
public static void streamToFile (final InputStream is, final File f) throws IOException {
final OutputStream os = new FileOutputStream(f);
try {
copy(is, os);
}
finally {
closeQuietly(os);
}
}
public static void collectionToFile (final Collection<String> data, final File f) throws IOException {
try {
final JSONArray arr = new JSONArray();
for (final String d : data) {
arr.put(d);
}
stringToFile(arr.toString(2), f);
}
catch (final JSONException e) {
throw new IOException(e.toString(), e);
}
}
public static Collection<String> fileToCollection (final File f) throws IOException {
try {
final String s = IoHelper.fileToString(f);
final Object root = new JSONTokener(s).nextValue();
if (root instanceof JSONArray) {
final JSONArray arr = (JSONArray) root;
final Collection<String> ret = new ArrayList<String>(arr.length());
for (int i = 0; i < arr.length(); i++) {
ret.add(arr.getString(i));
}
return ret;
}
else {
throw new IOException("Expected root object to be array, was: " + root.getClass());
}
}
catch (final JSONException e) {
throw new IOException(e.toString(), e);
}
}
}