2015-07-08 23:03:34 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.util;
|
|
|
|
|
2015-10-29 00:46:52 +01:00
|
|
|
import android.content.Context;
|
|
|
|
import android.os.Environment;
|
|
|
|
import android.util.Log;
|
|
|
|
|
2015-08-04 23:02:36 +02:00
|
|
|
import java.io.ByteArrayOutputStream;
|
2015-07-08 23:03:34 +02:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
2015-10-29 00:46:52 +01:00
|
|
|
import java.io.FileNotFoundException;
|
2015-07-08 23:03:34 +02:00
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
2015-08-04 23:02:36 +02:00
|
|
|
import java.io.InputStream;
|
2015-07-08 23:03:34 +02:00
|
|
|
import java.nio.channels.FileChannel;
|
2015-10-29 00:46:52 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2015-07-08 23:03:34 +02:00
|
|
|
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
|
|
|
|
|
|
|
public class FileUtils {
|
2015-10-29 00:46:52 +01:00
|
|
|
// Don't use slf4j here -- would be a bootstrapping problem
|
|
|
|
private static final String TAG = "FileUtils";
|
|
|
|
|
2015-07-08 23:03:34 +02:00
|
|
|
/**
|
|
|
|
* Copies the the given sourceFile to destFile, overwriting it, in case it exists.
|
2015-07-25 21:52:52 +02:00
|
|
|
*
|
2015-07-08 23:03:34 +02:00
|
|
|
* @param sourceFile
|
|
|
|
* @param destFile
|
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
public static void copyFile(File sourceFile, File destFile) throws IOException {
|
|
|
|
if (!sourceFile.exists()) {
|
|
|
|
throw new IOException("Does not exist: " + sourceFile.getAbsolutePath());
|
|
|
|
}
|
|
|
|
copyFile(new FileInputStream(sourceFile), new FileOutputStream(destFile));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void copyFile(FileInputStream sourceStream, FileOutputStream destStream) throws IOException {
|
|
|
|
try (FileChannel fromChannel = sourceStream.getChannel(); FileChannel toChannel = destStream.getChannel()) {
|
|
|
|
fromChannel.transferTo(0, fromChannel.size(), toChannel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the existing external storage dir.
|
2015-07-25 21:52:52 +02:00
|
|
|
*
|
2015-07-08 23:03:34 +02:00
|
|
|
* @throws IOException when the directory is not available
|
|
|
|
*/
|
|
|
|
public static File getExternalFilesDir() throws IOException {
|
2015-10-29 00:46:52 +01:00
|
|
|
List<File> dirs = getWritableExternalFilesDirs();
|
|
|
|
for (File dir : dirs) {
|
|
|
|
if (canWriteTo(dir)) {
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
throw new IOException("no writable external directory found");
|
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean canWriteTo(File dir) {
|
|
|
|
File file = new File(dir, "gbtest");
|
|
|
|
try {
|
|
|
|
FileOutputStream test = new FileOutputStream(file);
|
|
|
|
try {
|
|
|
|
test.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
file.delete();
|
|
|
|
return true;
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static List<File> getWritableExternalFilesDirs() throws IOException {
|
|
|
|
Context context = GBApplication.getContext();
|
|
|
|
File[] dirs = context.getExternalFilesDirs(null);
|
|
|
|
List<File> result = new ArrayList<>(dirs.length);
|
|
|
|
if (dirs == null) {
|
|
|
|
throw new IOException("Unable to access external files dirs: null");
|
|
|
|
}
|
|
|
|
if (dirs.length == 0) {
|
|
|
|
throw new IOException("Unable to access external files dirs: 0");
|
2015-07-08 23:03:34 +02:00
|
|
|
}
|
2015-10-29 00:46:52 +01:00
|
|
|
for (int i = 0; i < dirs.length; i++) {
|
|
|
|
File dir = dirs[i];
|
|
|
|
if (!dir.exists() && !dir.mkdirs()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// if (!dir.canWrite() || !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(dir))) {
|
|
|
|
if (!dir.canWrite() || (i == 0 && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))) {
|
|
|
|
Log.i(TAG, "ignoring non-writable external storage dir: " + dir);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// if (Environment.isExternalStorageEmulated(dir)) {
|
|
|
|
if (i == 0 && Environment.isExternalStorageEmulated()) {
|
|
|
|
result.add(dir); // add last
|
|
|
|
} else {
|
|
|
|
result.add(0, dir); // add first
|
|
|
|
}
|
2015-07-08 23:03:34 +02:00
|
|
|
}
|
2015-10-29 00:46:52 +01:00
|
|
|
return result;
|
2015-07-08 23:03:34 +02:00
|
|
|
}
|
2015-08-04 23:02:36 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads the contents of the given InputStream into a byte array, but does not
|
2015-08-17 22:46:39 +02:00
|
|
|
* read more than maxLen bytes. If the stream provides more than maxLen bytes,
|
|
|
|
* an IOException is thrown.
|
2015-09-24 14:45:21 +02:00
|
|
|
*
|
|
|
|
* @param in the stream to read from
|
2015-08-04 23:02:36 +02:00
|
|
|
* @param maxLen the maximum number of bytes to read/return
|
|
|
|
* @return the bytes read from the InputStream
|
|
|
|
* @throws IOException when reading failed or when maxLen was exceeded
|
|
|
|
*/
|
|
|
|
public static byte[] readAll(InputStream in, long maxLen) throws IOException {
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(8192, in.available()));
|
|
|
|
byte[] buf = new byte[8192];
|
|
|
|
int read = 0;
|
|
|
|
long totalRead = 0;
|
|
|
|
while ((read = in.read(buf)) > 0) {
|
|
|
|
out.write(buf, 0, read);
|
|
|
|
totalRead += read;
|
|
|
|
if (totalRead > maxLen) {
|
|
|
|
throw new IOException("Too much data to read into memory. Got already " + totalRead + buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return out.toByteArray();
|
|
|
|
}
|
2015-07-08 23:03:34 +02:00
|
|
|
}
|