committed by
bunnei
2 changed files with 292 additions and 296 deletions
-
296src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.java
-
292src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
@ -1,296 +0,0 @@ |
|||||
package org.yuzu.yuzu_emu.utils; |
|
||||
|
|
||||
import android.content.ContentResolver; |
|
||||
import android.content.Context; |
|
||||
import android.database.Cursor; |
|
||||
import android.net.Uri; |
|
||||
import android.os.ParcelFileDescriptor; |
|
||||
import android.provider.DocumentsContract; |
|
||||
|
|
||||
import androidx.annotation.Nullable; |
|
||||
import androidx.documentfile.provider.DocumentFile; |
|
||||
|
|
||||
import org.yuzu.yuzu_emu.model.MinimalDocumentFile; |
|
||||
|
|
||||
import java.io.FileOutputStream; |
|
||||
import java.io.IOException; |
|
||||
import java.io.InputStream; |
|
||||
import java.net.URLDecoder; |
|
||||
import java.util.ArrayList; |
|
||||
import java.util.List; |
|
||||
|
|
||||
public class FileUtil { |
|
||||
static final String PATH_TREE = "tree"; |
|
||||
static final String DECODE_METHOD = "UTF-8"; |
|
||||
static final String APPLICATION_OCTET_STREAM = "application/octet-stream"; |
|
||||
static final String TEXT_PLAIN = "text/plain"; |
|
||||
|
|
||||
/** |
|
||||
* Create a file from directory with filename. |
|
||||
* @param context Application context |
|
||||
* @param directory parent path for file. |
|
||||
* @param filename file display name. |
|
||||
* @return boolean |
|
||||
*/ |
|
||||
@Nullable |
|
||||
public static DocumentFile createFile(Context context, String directory, String filename) { |
|
||||
try { |
|
||||
Uri directoryUri = Uri.parse(directory); |
|
||||
DocumentFile parent = DocumentFile.fromTreeUri(context, directoryUri); |
|
||||
if (parent == null) return null; |
|
||||
filename = URLDecoder.decode(filename, DECODE_METHOD); |
|
||||
String mimeType = APPLICATION_OCTET_STREAM; |
|
||||
if (filename.endsWith(".txt")) { |
|
||||
mimeType = TEXT_PLAIN; |
|
||||
} |
|
||||
DocumentFile exists = parent.findFile(filename); |
|
||||
if (exists != null) return exists; |
|
||||
return parent.createFile(mimeType, filename); |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage()); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Create a directory from directory with filename. |
|
||||
* @param context Application context |
|
||||
* @param directory parent path for directory. |
|
||||
* @param directoryName directory display name. |
|
||||
* @return boolean |
|
||||
*/ |
|
||||
@Nullable |
|
||||
public static DocumentFile createDir(Context context, String directory, String directoryName) { |
|
||||
try { |
|
||||
Uri directoryUri = Uri.parse(directory); |
|
||||
DocumentFile parent = DocumentFile.fromTreeUri(context, directoryUri); |
|
||||
if (parent == null) return null; |
|
||||
directoryName = URLDecoder.decode(directoryName, DECODE_METHOD); |
|
||||
DocumentFile isExist = parent.findFile(directoryName); |
|
||||
if (isExist != null) return isExist; |
|
||||
return parent.createDirectory(directoryName); |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot create file, error: " + e.getMessage()); |
|
||||
} |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Open content uri and return file descriptor to JNI. |
|
||||
* @param context Application context |
|
||||
* @param path Native content uri path |
|
||||
* @param openmode will be one of "r", "r", "rw", "wa", "rwa" |
|
||||
* @return file descriptor |
|
||||
*/ |
|
||||
public static int openContentUri(Context context, String path, String openmode) { |
|
||||
try { |
|
||||
Uri uri = Uri.parse(path); |
|
||||
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, openmode); |
|
||||
if (parcelFileDescriptor == null) { |
|
||||
Log.error("[FileUtil]: Cannot get the file descriptor from uri: " + path); |
|
||||
return -1; |
|
||||
} |
|
||||
return parcelFileDescriptor.detachFd(); |
|
||||
} |
|
||||
catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot open content uri, error: " + e.getMessage()); |
|
||||
} |
|
||||
return -1; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow |
|
||||
* This function will be faster than DoucmentFile.listFiles |
|
||||
* @param context Application context |
|
||||
* @param uri Directory uri. |
|
||||
* @return CheapDocument lists. |
|
||||
*/ |
|
||||
public static MinimalDocumentFile[] listFiles(Context context, Uri uri) { |
|
||||
final ContentResolver resolver = context.getContentResolver(); |
|
||||
final String[] columns = new String[]{ |
|
||||
DocumentsContract.Document.COLUMN_DOCUMENT_ID, |
|
||||
DocumentsContract.Document.COLUMN_DISPLAY_NAME, |
|
||||
DocumentsContract.Document.COLUMN_MIME_TYPE, |
|
||||
}; |
|
||||
Cursor c = null; |
|
||||
final List<MinimalDocumentFile> results = new ArrayList<>(); |
|
||||
try { |
|
||||
String docId; |
|
||||
if (isRootTreeUri(uri)) { |
|
||||
docId = DocumentsContract.getTreeDocumentId(uri); |
|
||||
} else { |
|
||||
docId = DocumentsContract.getDocumentId(uri); |
|
||||
} |
|
||||
final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId); |
|
||||
c = resolver.query(childrenUri, columns, null, null, null); |
|
||||
while(c.moveToNext()) { |
|
||||
final String documentId = c.getString(0); |
|
||||
final String documentName = c.getString(1); |
|
||||
final String documentMimeType = c.getString(2); |
|
||||
final Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId); |
|
||||
MinimalDocumentFile document = new MinimalDocumentFile(documentName, documentMimeType, documentUri); |
|
||||
results.add(document); |
|
||||
} |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot list file error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
closeQuietly(c); |
|
||||
} |
|
||||
return results.toArray(new MinimalDocumentFile[0]); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Check whether given path exists. |
|
||||
* @param path Native content uri path |
|
||||
* @return bool |
|
||||
*/ |
|
||||
public static boolean Exists(Context context, String path) { |
|
||||
Cursor c = null; |
|
||||
try { |
|
||||
Uri mUri = Uri.parse(path); |
|
||||
final String[] columns = new String[] { DocumentsContract.Document.COLUMN_DOCUMENT_ID }; |
|
||||
c = context.getContentResolver().query(mUri, columns, null, null, null); |
|
||||
return c.getCount() > 0; |
|
||||
} catch (Exception e) { |
|
||||
Log.info("[FileUtil] Cannot find file from given path, error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
closeQuietly(c); |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Check whether given path is a directory |
|
||||
* @param path content uri path |
|
||||
* @return bool |
|
||||
*/ |
|
||||
public static boolean isDirectory(Context context, String path) { |
|
||||
final ContentResolver resolver = context.getContentResolver(); |
|
||||
final String[] columns = new String[] { |
|
||||
DocumentsContract.Document.COLUMN_MIME_TYPE |
|
||||
}; |
|
||||
boolean isDirectory = false; |
|
||||
Cursor c = null; |
|
||||
try { |
|
||||
Uri mUri = Uri.parse(path); |
|
||||
c = resolver.query(mUri, columns, null, null, null); |
|
||||
c.moveToNext(); |
|
||||
final String mimeType = c.getString(0); |
|
||||
isDirectory = mimeType.equals(DocumentsContract.Document.MIME_TYPE_DIR); |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot list files, error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
closeQuietly(c); |
|
||||
} |
|
||||
return isDirectory; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Get file display name from given path |
|
||||
* @param path content uri path |
|
||||
* @return String display name |
|
||||
*/ |
|
||||
public static String getFilename(Context context, String path) { |
|
||||
final ContentResolver resolver = context.getContentResolver(); |
|
||||
final String[] columns = new String[] { |
|
||||
DocumentsContract.Document.COLUMN_DISPLAY_NAME |
|
||||
}; |
|
||||
String filename = ""; |
|
||||
Cursor c = null; |
|
||||
try { |
|
||||
Uri mUri = Uri.parse(path); |
|
||||
c = resolver.query(mUri, columns, null, null, null); |
|
||||
c.moveToNext(); |
|
||||
filename = c.getString(0); |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
closeQuietly(c); |
|
||||
} |
|
||||
return filename; |
|
||||
} |
|
||||
|
|
||||
public static String[] getFilesName(Context context, String path) { |
|
||||
Uri uri = Uri.parse(path); |
|
||||
List<String> files = new ArrayList<>(); |
|
||||
for (MinimalDocumentFile file: FileUtil.listFiles(context, uri)) { |
|
||||
files.add(file.getFilename()); |
|
||||
} |
|
||||
return files.toArray(new String[0]); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Get file size from given path. |
|
||||
* @param path content uri path |
|
||||
* @return long file size |
|
||||
*/ |
|
||||
public static long getFileSize(Context context, String path) { |
|
||||
final ContentResolver resolver = context.getContentResolver(); |
|
||||
final String[] columns = new String[] { |
|
||||
DocumentsContract.Document.COLUMN_SIZE |
|
||||
}; |
|
||||
long size = 0; |
|
||||
Cursor c =null; |
|
||||
try { |
|
||||
Uri mUri = Uri.parse(path); |
|
||||
c = resolver.query(mUri, columns, null, null, null); |
|
||||
c.moveToNext(); |
|
||||
size = c.getLong(0); |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot get file size, error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
closeQuietly(c); |
|
||||
} |
|
||||
return size; |
|
||||
} |
|
||||
|
|
||||
public static boolean copyUriToInternalStorage(Context context, Uri sourceUri, String destinationParentPath, String destinationFilename) { |
|
||||
InputStream input = null; |
|
||||
FileOutputStream output = null; |
|
||||
try { |
|
||||
input = context.getContentResolver().openInputStream(sourceUri); |
|
||||
output = new FileOutputStream(destinationParentPath + "/" + destinationFilename); |
|
||||
byte[] buffer = new byte[1024]; |
|
||||
int len; |
|
||||
while ((len = input.read(buffer)) != -1) { |
|
||||
output.write(buffer, 0, len); |
|
||||
} |
|
||||
output.flush(); |
|
||||
return true; |
|
||||
} catch (Exception e) { |
|
||||
Log.error("[FileUtil]: Cannot copy file, error: " + e.getMessage()); |
|
||||
} finally { |
|
||||
if (input != null) { |
|
||||
try { |
|
||||
input.close(); |
|
||||
} catch (IOException e) { |
|
||||
Log.error("[FileUtil]: Cannot close input file, error: " + e.getMessage()); |
|
||||
} |
|
||||
} |
|
||||
if (output != null) { |
|
||||
try { |
|
||||
output.close(); |
|
||||
} catch (IOException e) { |
|
||||
Log.error("[FileUtil]: Cannot close output file, error: " + e.getMessage()); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public static boolean isRootTreeUri(Uri uri) { |
|
||||
final List<String> paths = uri.getPathSegments(); |
|
||||
return paths.size() == 2 && PATH_TREE.equals(paths.get(0)); |
|
||||
} |
|
||||
|
|
||||
public static void closeQuietly(AutoCloseable closeable) { |
|
||||
if (closeable != null) { |
|
||||
try { |
|
||||
closeable.close(); |
|
||||
} catch (RuntimeException rethrown) { |
|
||||
throw rethrown; |
|
||||
} catch (Exception ignored) { |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,292 @@ |
|||||
|
package org.yuzu.yuzu_emu.utils |
||||
|
|
||||
|
import android.content.Context |
||||
|
import android.database.Cursor |
||||
|
import android.net.Uri |
||||
|
import android.provider.DocumentsContract |
||||
|
import androidx.documentfile.provider.DocumentFile |
||||
|
import org.yuzu.yuzu_emu.model.MinimalDocumentFile |
||||
|
import java.io.FileOutputStream |
||||
|
import java.io.IOException |
||||
|
import java.io.InputStream |
||||
|
import java.net.URLDecoder |
||||
|
|
||||
|
object FileUtil { |
||||
|
const val PATH_TREE = "tree" |
||||
|
const val DECODE_METHOD = "UTF-8" |
||||
|
const val APPLICATION_OCTET_STREAM = "application/octet-stream" |
||||
|
const val TEXT_PLAIN = "text/plain" |
||||
|
|
||||
|
/** |
||||
|
* Create a file from directory with filename. |
||||
|
* @param context Application context |
||||
|
* @param directory parent path for file. |
||||
|
* @param filename file display name. |
||||
|
* @return boolean |
||||
|
*/ |
||||
|
fun createFile(context: Context?, directory: String?, filename: String): DocumentFile? { |
||||
|
var decodedFilename = filename |
||||
|
try { |
||||
|
val directoryUri = Uri.parse(directory) |
||||
|
val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null |
||||
|
decodedFilename = URLDecoder.decode(decodedFilename, DECODE_METHOD) |
||||
|
var mimeType = APPLICATION_OCTET_STREAM |
||||
|
if (decodedFilename.endsWith(".txt")) { |
||||
|
mimeType = TEXT_PLAIN |
||||
|
} |
||||
|
val exists = parent.findFile(decodedFilename) |
||||
|
return exists ?: parent.createFile(mimeType, decodedFilename) |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot create file, error: " + e.message) |
||||
|
} |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Create a directory from directory with filename. |
||||
|
* @param context Application context |
||||
|
* @param directory parent path for directory. |
||||
|
* @param directoryName directory display name. |
||||
|
* @return boolean |
||||
|
*/ |
||||
|
fun createDir(context: Context?, directory: String?, directoryName: String?): DocumentFile? { |
||||
|
var decodedDirectoryName = directoryName |
||||
|
try { |
||||
|
val directoryUri = Uri.parse(directory) |
||||
|
val parent = DocumentFile.fromTreeUri(context!!, directoryUri) ?: return null |
||||
|
decodedDirectoryName = URLDecoder.decode(decodedDirectoryName, DECODE_METHOD) |
||||
|
val isExist = parent.findFile(decodedDirectoryName) |
||||
|
return isExist ?: parent.createDirectory(decodedDirectoryName) |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot create file, error: " + e.message) |
||||
|
} |
||||
|
return null |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Open content uri and return file descriptor to JNI. |
||||
|
* @param context Application context |
||||
|
* @param path Native content uri path |
||||
|
* @param openMode will be one of "r", "r", "rw", "wa", "rwa" |
||||
|
* @return file descriptor |
||||
|
*/ |
||||
|
@JvmStatic |
||||
|
fun openContentUri(context: Context, path: String, openMode: String?): Int { |
||||
|
try { |
||||
|
val uri = Uri.parse(path) |
||||
|
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(uri, openMode!!) |
||||
|
if (parcelFileDescriptor == null) { |
||||
|
Log.error("[FileUtil]: Cannot get the file descriptor from uri: $path") |
||||
|
return -1 |
||||
|
} |
||||
|
val fileDescriptor = parcelFileDescriptor.detachFd() |
||||
|
parcelFileDescriptor.close() |
||||
|
return fileDescriptor |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot open content uri, error: " + e.message) |
||||
|
} |
||||
|
return -1 |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Reference: https://stackoverflow.com/questions/42186820/documentfile-is-very-slow |
||||
|
* This function will be faster than DoucmentFile.listFiles |
||||
|
* @param context Application context |
||||
|
* @param uri Directory uri. |
||||
|
* @return CheapDocument lists. |
||||
|
*/ |
||||
|
fun listFiles(context: Context, uri: Uri): Array<MinimalDocumentFile> { |
||||
|
val resolver = context.contentResolver |
||||
|
val columns = arrayOf( |
||||
|
DocumentsContract.Document.COLUMN_DOCUMENT_ID, |
||||
|
DocumentsContract.Document.COLUMN_DISPLAY_NAME, |
||||
|
DocumentsContract.Document.COLUMN_MIME_TYPE |
||||
|
) |
||||
|
var c: Cursor? = null |
||||
|
val results: MutableList<MinimalDocumentFile> = ArrayList() |
||||
|
try { |
||||
|
val docId: String = if (isRootTreeUri(uri)) { |
||||
|
DocumentsContract.getTreeDocumentId(uri) |
||||
|
} else { |
||||
|
DocumentsContract.getDocumentId(uri) |
||||
|
} |
||||
|
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId) |
||||
|
c = resolver.query(childrenUri, columns, null, null, null) |
||||
|
while (c!!.moveToNext()) { |
||||
|
val documentId = c.getString(0) |
||||
|
val documentName = c.getString(1) |
||||
|
val documentMimeType = c.getString(2) |
||||
|
val documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId) |
||||
|
val document = MinimalDocumentFile(documentName, documentMimeType, documentUri) |
||||
|
results.add(document) |
||||
|
} |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot list file error: " + e.message) |
||||
|
} finally { |
||||
|
closeQuietly(c) |
||||
|
} |
||||
|
return results.toTypedArray() |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Check whether given path exists. |
||||
|
* @param path Native content uri path |
||||
|
* @return bool |
||||
|
*/ |
||||
|
fun exists(context: Context, path: String?): Boolean { |
||||
|
var c: Cursor? = null |
||||
|
try { |
||||
|
val mUri = Uri.parse(path) |
||||
|
val columns = arrayOf(DocumentsContract.Document.COLUMN_DOCUMENT_ID) |
||||
|
c = context.contentResolver.query(mUri, columns, null, null, null) |
||||
|
return c!!.count > 0 |
||||
|
} catch (e: Exception) { |
||||
|
Log.info("[FileUtil] Cannot find file from given path, error: " + e.message) |
||||
|
} finally { |
||||
|
closeQuietly(c) |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Check whether given path is a directory |
||||
|
* @param path content uri path |
||||
|
* @return bool |
||||
|
*/ |
||||
|
fun isDirectory(context: Context, path: String): Boolean { |
||||
|
val resolver = context.contentResolver |
||||
|
val columns = arrayOf( |
||||
|
DocumentsContract.Document.COLUMN_MIME_TYPE |
||||
|
) |
||||
|
var isDirectory = false |
||||
|
var c: Cursor? = null |
||||
|
try { |
||||
|
val mUri = Uri.parse(path) |
||||
|
c = resolver.query(mUri, columns, null, null, null) |
||||
|
c!!.moveToNext() |
||||
|
val mimeType = c.getString(0) |
||||
|
isDirectory = mimeType == DocumentsContract.Document.MIME_TYPE_DIR |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot list files, error: " + e.message) |
||||
|
} finally { |
||||
|
closeQuietly(c) |
||||
|
} |
||||
|
return isDirectory |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Get file display name from given path |
||||
|
* @param path content uri path |
||||
|
* @return String display name |
||||
|
*/ |
||||
|
fun getFilename(context: Context, path: String): String { |
||||
|
val resolver = context.contentResolver |
||||
|
val columns = arrayOf( |
||||
|
DocumentsContract.Document.COLUMN_DISPLAY_NAME |
||||
|
) |
||||
|
var filename = "" |
||||
|
var c: Cursor? = null |
||||
|
try { |
||||
|
val mUri = Uri.parse(path) |
||||
|
c = resolver.query(mUri, columns, null, null, null) |
||||
|
c!!.moveToNext() |
||||
|
filename = c.getString(0) |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot get file size, error: " + e.message) |
||||
|
} finally { |
||||
|
closeQuietly(c) |
||||
|
} |
||||
|
return filename |
||||
|
} |
||||
|
|
||||
|
fun getFilesName(context: Context, path: String): Array<String> { |
||||
|
val uri = Uri.parse(path) |
||||
|
val files: MutableList<String> = ArrayList() |
||||
|
for (file in listFiles(context, uri)) { |
||||
|
files.add(file.filename) |
||||
|
} |
||||
|
return files.toTypedArray() |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Get file size from given path. |
||||
|
* @param path content uri path |
||||
|
* @return long file size |
||||
|
*/ |
||||
|
@JvmStatic |
||||
|
fun getFileSize(context: Context, path: String): Long { |
||||
|
val resolver = context.contentResolver |
||||
|
val columns = arrayOf( |
||||
|
DocumentsContract.Document.COLUMN_SIZE |
||||
|
) |
||||
|
var size: Long = 0 |
||||
|
var c: Cursor? = null |
||||
|
try { |
||||
|
val mUri = Uri.parse(path) |
||||
|
c = resolver.query(mUri, columns, null, null, null) |
||||
|
c!!.moveToNext() |
||||
|
size = c.getLong(0) |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot get file size, error: " + e.message) |
||||
|
} finally { |
||||
|
closeQuietly(c) |
||||
|
} |
||||
|
return size |
||||
|
} |
||||
|
|
||||
|
@JvmStatic |
||||
|
fun copyUriToInternalStorage( |
||||
|
context: Context, |
||||
|
sourceUri: Uri?, |
||||
|
destinationParentPath: String, |
||||
|
destinationFilename: String |
||||
|
): Boolean { |
||||
|
var input: InputStream? = null |
||||
|
var output: FileOutputStream? = null |
||||
|
try { |
||||
|
input = context.contentResolver.openInputStream(sourceUri!!) |
||||
|
output = FileOutputStream("$destinationParentPath/$destinationFilename") |
||||
|
val buffer = ByteArray(1024) |
||||
|
var len: Int |
||||
|
while (input!!.read(buffer).also { len = it } != -1) { |
||||
|
output.write(buffer, 0, len) |
||||
|
} |
||||
|
output.flush() |
||||
|
return true |
||||
|
} catch (e: Exception) { |
||||
|
Log.error("[FileUtil]: Cannot copy file, error: " + e.message) |
||||
|
} finally { |
||||
|
if (input != null) { |
||||
|
try { |
||||
|
input.close() |
||||
|
} catch (e: IOException) { |
||||
|
Log.error("[FileUtil]: Cannot close input file, error: " + e.message) |
||||
|
} |
||||
|
} |
||||
|
if (output != null) { |
||||
|
try { |
||||
|
output.close() |
||||
|
} catch (e: IOException) { |
||||
|
Log.error("[FileUtil]: Cannot close output file, error: " + e.message) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return false |
||||
|
} |
||||
|
|
||||
|
fun isRootTreeUri(uri: Uri): Boolean { |
||||
|
val paths = uri.pathSegments |
||||
|
return paths.size == 2 && PATH_TREE == paths[0] |
||||
|
} |
||||
|
|
||||
|
fun closeQuietly(closeable: AutoCloseable?) { |
||||
|
if (closeable != null) { |
||||
|
try { |
||||
|
closeable.close() |
||||
|
} catch (rethrown: RuntimeException) { |
||||
|
throw rethrown |
||||
|
} catch (ignored: Exception) { |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue