/*
This file is part of Reactive Cascade which is released under The MIT License.
See license.md , https://github.com/futurice/cascade and http://reactivecascade.com for details.
This is open source for the common good. Please contribute improvements by pull request or contact paulirotta@gmail.com
*/
package com.reactivecascade.util;
import android.content.Context;
import android.support.annotation.CheckResult;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import com.reactivecascade.i.IAltFuture;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static com.reactivecascade.Async.FILE;
public final class FileUtil extends Origin {
private static final int BUFFER_SIZE = 16384;
@NonNull
private final Context mContext;
@FileMode
private final int mMode;
public FileUtil(@NonNull Context context,
@FileMode int mode) {
this.mContext = context;
this.mMode = mode;
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public <IN> IAltFuture<IN, IN> writeAsync(@NonNull String fileName,
@NonNull byte[] bytes) {
return FILE.then(
() -> {
write(fileName, bytes);
});
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<String, byte[]> writeAsync(@NonNull byte[] bytes) {
return FILE.map(
fileName -> {
write(fileName, bytes);
return bytes;
});
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<byte[], byte[]> writeAsync(@NonNull String fileName) {
return FILE.then(
bytes -> {
write(fileName, bytes);
});
}
@WorkerThread
public void write(@NonNull String fileName,
@NonNull byte[] bytes) {
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = mContext.openFileOutput(fileName, mMode);
fileOutputStream.write(bytes);
} catch (FileNotFoundException e) {
final String s = "Can not locate FILE: " + fileName;
RCLog.d(this, s);
RCLog.throwRuntimeException(this, s, e);
} catch (IOException e) {
final String s = "Can not write FILE: " + fileName;
RCLog.d(this, s);
RCLog.throwRuntimeException(this, s, e);
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
RCLog.e(this, "Can not close FILE output stream", e);
}
}
}
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<String, byte[]> readAsync() {
return FILE.map(this::read);
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<?, byte[]> readAsync(@NonNull String fileName) {
return FILE.then(
() -> {
return read(fileName);
});
}
@NonNull
@WorkerThread
public byte[] read(@NonNull String fileName) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
FileInputStream fileInputStream = null;
try {
fileInputStream = mContext.openFileInput(fileName);
final byte[] buffer = new byte[BUFFER_SIZE];
int count;
for (; ; ) {
count = fileInputStream.read(buffer, 0, buffer.length);
if (count < 0) {
break;
}
bos.write(buffer, 0, count);
}
} catch (FileNotFoundException e) {
RCLog.throwRuntimeException(this, "Can not locate FILE: " + fileName, e);
} catch (IOException e) {
RCLog.throwRuntimeException(this, "Can not read FILE: " + fileName, e);
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
RCLog.e(this, "Can not close FILE input stream: " + fileName, e);
}
}
}
return bos.toByteArray();
}
@WorkerThread
public boolean delete(@NonNull String fileName) {
return mContext.deleteFile(fileName);
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<?, Boolean> deleteAsync(@NonNull final String fileName) {
return FILE.then(
() -> {
return delete(fileName);
});
}
@NonNull
@CheckResult(suggest = IAltFuture.CHECK_RESULT_SUGGESTION)
public IAltFuture<String, Boolean> deleteAsync() {
return FILE.map(this::delete);
}
@IntDef({Context.MODE_PRIVATE, Context.MODE_APPEND})
@Retention(RetentionPolicy.SOURCE)
public @interface FileMode {
}
}