You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Android-Download/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtils.kt

201 lines
6.3 KiB

/*
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.util
import android.content.ContentResolver
import android.database.Cursor
import android.net.Uri
import android.provider.OpenableColumns
import com.arialyy.aria.core.DuaContext
import com.arialyy.aria.orm.entity.BlockRecord
import timber.log.Timber
import java.io.File
import java.io.InputStream
import java.util.Locale
object FileUtils {
val HTTP_REGEX =
Regex(
"(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]",
RegexOption.IGNORE_CASE
)
fun mergeBlock(blockRecordList: List<BlockRecord>, targetPath: Uri): Boolean {
if (blockRecordList.isEmpty()) {
Timber.e("block record list empty")
return false
}
if (!uriEffective(targetPath)) {
Timber.e("invalid uri: $targetPath")
return false
}
val fileList = arrayListOf<File>()
blockRecordList.forEach {
fileList.add(File(it.blockPath))
}
return FileUtil.mergeFile()
}
/**
* check if url is correct
*/
fun checkUrl(url: String) = HTTP_REGEX.matches(url)
/**
* https://github.com/javakam/FileOperator/blob/master/library_core/src/main/java/ando/file/core/FileUtils.kt
*
* 1. Check if Uri is correct
* 2. Whether the file corresponding to Uri exists (may be deleted, or the system db has Uri related records, but the file is invalid or damaged)
*
* https://stackoverflow.com/questions/7645951/how-to-check-if-resource-pointed-by-uri-is-available
*/
fun uriEffective(uri: Uri?): Boolean {
if (uri == null) return false
val resolver = DuaContext.context.contentResolver
//1. Check Uri
var cursor: Cursor? = null
val isUriExist: Boolean = try {
cursor = resolver.query(uri, null, null, null, null)
//cursor null: content Uri was invalid or some other error occurred
//cursor.moveToFirst() false: Uri was ok but no entry found.
(cursor != null && cursor.moveToFirst())
} catch (t: Throwable) {
Timber.e("1.Check Uri Error: ${t.message}")
false
} finally {
try {
cursor?.close()
} catch (t: Throwable) {
}
}
//2. Check File Exist
//如果系统 db 存有 Uri 相关记录, 但是文件失效或者损坏 (If the system db has Uri related records, but the file is invalid or damaged)
return isUriExist && checkFileExistByUri(uri, resolver)
}
/**
* check file exist
* @return true exist
*/
fun checkFileExistByUri(uri: Uri, resolver: ContentResolver): Boolean {
var ins: InputStream? = null
val isFileExist: Boolean = try {
ins = resolver.openInputStream(uri)
// file exists
true
} catch (t: Throwable) {
// File was not found eg: open failed: ENOENT (No such file or directory)
Timber.e("2. Check File Exist Error: ${t.message}")
false
} finally {
try {
ins?.close()
} catch (t: Throwable) {
}
}
return isFileExist
}
/**
* ### 路径分割
*
* ```
* eg:
* srcPath=/storage/emulated/0/Movies/myVideo.mp4 path=/storage/emulated/0/Movies name=myVideo suffix=mp4 nameSuffix=myVideo.mp4
*
* /xxx/xxx/note.txt -> path: /xxx/xxx name: note suffix: txt
* ///note.txt -> path: /// name: note suffix: txt
* /note.txt -> path: "" name: note suffix: txt
* note.txt -> path: "" name: note suffix: txt
* ```
*/
fun splitFilePath(
srcPath: String?,
nameSplit: Char = '/',
suffixSplit: Char = '.',
block: ((path: String, name: String, suffix: String, nameSuffix: String) -> Unit)? = null,
) {
if (srcPath.isNullOrBlank()) return
val cut = srcPath.lastIndexOf(nameSplit)
// /xxx/xxx/note.txt +0: /xxx/xxx +1: /xxx/xxx/
val path = if (cut == -1) "" else srcPath.substring(0, cut)
val nameSuffix = if (cut == -1) srcPath else srcPath.substring(cut + 1)
val dot = nameSuffix.lastIndexOf(suffixSplit)
if (dot != -1) {
val suffix = nameSuffix.substring((dot + 1)).lowercase(Locale.getDefault())
val name = nameSuffix.substring(0, dot)
Timber.d("splitFilePath srcPath=$srcPath path=$path name=$name suffix=$suffix nameSuffix=$nameSuffix")
block?.invoke(path, name, suffix, nameSuffix)
}
}
/**
* abc.jpg -> jpg
*/
fun getFileNameSuffix(path: String): String {
var nameSuffix = path
splitFilePath(srcPath = path) { _: String, _: String, suffix: String, _: String ->
nameSuffix = suffix
}
return nameSuffix
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> /storage/emulated/0/Movies
*/
fun getFilePathFromFullPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
// (cut+1): /storage/emulated/0/Movies/
if (cut != -1) return path.substring(0, cut)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromPath(path: String?, split: Char = '/'): String? {
if (path.isNullOrBlank()) return null
val cut = path.lastIndexOf(split)
if (cut != -1) return path.substring(cut + 1)
return path
}
/**
* /storage/emulated/0/Movies/myVideo.mp4 -> myVideo.mp4
*/
fun getFileNameFromUri(uri: Uri?): String? =
uri?.use {
var filename: String? = null
val resolver = DuaContext.context.contentResolver
val mimeType = resolver.getType(uri)
if (mimeType == null) {
filename = getFileNameFromPath(FileUri.getPathByUri(uri))
} else {
resolver.query(uri, null, null, null, null)?.use { c: Cursor ->
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (c.moveToFirst()) filename = c.getString(nameIndex)
}
}
filename
}
}