package cn.flightfeather.thirdapp.util.file
|
|
import android.content.Context
|
import android.graphics.Bitmap
|
import android.graphics.BitmapFactory
|
import android.media.MediaMetadataRetriever
|
import android.net.Uri
|
import android.os.Build
|
import android.os.Environment
|
import android.support.v4.content.FileProvider
|
import cn.flightfeather.thirdapp.R
|
import cn.flightfeather.thirdapp.util.CommonUtils
|
import cn.flightfeather.thirdapp.util.DateUtil
|
import cn.flightfeather.thirdapp.util.file.FileUtils.GB
|
import cn.flightfeather.thirdapp.util.file.FileUtils.KB
|
import cn.flightfeather.thirdapp.util.file.FileUtils.MB
|
import io.reactivex.Observable
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.schedulers.Schedulers
|
import java.io.File
|
import java.io.FileOutputStream
|
import java.util.*
|
import kotlin.collections.ArrayList
|
import kotlin.math.round
|
|
/**
|
* @author riku
|
* Date: 2019/6/11
|
* 文件操作工具类
|
*/
|
object FileUtils {
|
|
const val KB = 1024L
|
const val MB = 1024 * KB
|
const val GB = 1024 * MB
|
|
//文档
|
private val FILE_EXTENSION_LIST = listOf(
|
"xls", "xlsx", "ppt", "pptx", "doc",
|
"docx", "pdf", "html", "htm", "txt",
|
"rar", "zip", "7z"
|
)
|
|
//图片
|
private val IMAGE_EXTENSION_LIST = listOf(
|
"png", "gif", "jpg", "jpeg"
|
)
|
|
//音视频
|
val VIDEO_EXTENSION_LIST = listOf(
|
"mp4", "mp3", "3gp", "m4a"
|
)
|
|
|
private val FILE_TYPE_TITLE_MAP = mapOf(
|
Pair("xls", "EXCEL"),
|
Pair("xlsx", "EXCEL"),
|
Pair("doc", "WORD"),
|
Pair("docx", "WORD"),
|
Pair("pdf", "PDF"),
|
Pair("ppt", "PPT"),
|
Pair("pptx", "PPT")
|
)
|
|
private const val UNKNOWN = "OTHERS"
|
|
val ROOT_PATH: String = Environment.getExternalStorageDirectory().absolutePath
|
|
/**
|
* 获取缓存目录
|
*/
|
fun getCacheDir(context: Context? = null): File {
|
return File(Environment.getExternalStorageDirectory().absolutePath, "/TaiZhang/files/")
|
}
|
|
fun getAudioDir(): File {
|
return File(Environment.getExternalStorageDirectory().absolutePath, "/TaiZhang/audio/")
|
}
|
|
/**
|
* 压缩图片至JPG格式
|
*/
|
fun compress2JPG(context: Context, path: String): File {
|
val file = File(path)
|
|
val opts = BitmapFactory.Options()
|
//将图片的长宽缩小为1/2
|
opts.inSampleSize = 2
|
val bm = BitmapFactory.decodeFile(file.absolutePath, opts)
|
|
return compress2JPG(context, bm)
|
}
|
|
fun compress2JPG(context: Context, bitmap: Bitmap): File {
|
val fileName = "${Date().time}.jpg"
|
val outputFile =
|
File(getCacheDir(context), "thumbnail${File.separator}$fileName")
|
if (!outputFile.parentFile.exists()) {
|
outputFile.parentFile.mkdirs()
|
}
|
|
// val opts = BitmapFactory.Options()
|
// //将图片的长宽缩小为1/2
|
// opts.inSampleSize = 2
|
// val bm = BitmapFactory.decodeFile(file.absolutePath, opts)
|
|
val normalSize = 1440
|
val width: Int
|
val height: Int
|
|
if (bitmap.width >= bitmap.height) {
|
width = normalSize
|
height = normalSize * bitmap.height / bitmap.width
|
} else {
|
height = normalSize
|
width = normalSize * bitmap.width / bitmap.height
|
}
|
|
val bmSmall = Bitmap.createScaledBitmap(bitmap, width, height, true)
|
|
bmSmall.compress(Bitmap.CompressFormat.JPEG, 80, FileOutputStream(outputFile.absolutePath))
|
|
bitmap.recycle()
|
bmSmall.recycle()
|
|
return outputFile
|
}
|
|
private fun getAllFile(path: String = ROOT_PATH, index: Int = 0, onFound: (fileItems: List<FileItem>) -> Unit) {
|
val file = File(path)
|
var files = emptyArray<File>()
|
try {
|
files = file.listFiles()
|
} catch (e: Exception) {
|
e.printStackTrace()
|
}
|
//获取失败
|
// if (files.isEmpty()) {
|
// onFound(emptyList())
|
// }
|
|
for (f in files) {
|
if (f.isHidden) continue
|
if (path != ROOT_PATH ||
|
(f.path.contains("download", true)
|
|| f.path.contains("android", true)
|
|| f.path.contains("tencent", true)
|
)
|
) {
|
|
//如果是文件目录,则继续查找
|
if (f.isDirectory) {
|
getAllFile(f.path, index + 1, onFound)
|
} else if (getOfficeFileTitle(getExtensionName(f.name)) != UNKNOWN) {
|
val updateTime = DateUtil.getYearToMinStr(Date(f.lastModified()))
|
onFound(
|
listOf(
|
FileItem(f.name, f.path, updateTime, f.size())
|
)
|
)
|
}
|
}
|
}
|
|
//判断进入的第一层文件路径的所有文件遍历完成后,返回一个特定的对象表示查询结束
|
if (index == 0) {
|
onFound(
|
listOf(
|
FileItem("done", "done")
|
)
|
)
|
}
|
}
|
|
/**
|
* 获取文件路径下的所有文件列表
|
*/
|
fun getAllFiles(path: String = ROOT_PATH): Observable<List<FileItem>> = Observable.create<List<FileItem>> { emitter ->
|
getAllFile(path) {
|
emitter.onNext(it)
|
}
|
emitter.onComplete()
|
}.subscribeOn(Schedulers.io())
|
.observeOn(AndroidSchedulers.mainThread())
|
|
/**
|
* 获取文件路径下的所有文件列表
|
*/
|
fun showFileDir(path: String = ROOT_PATH): List<FileItem> {
|
val fileListItems = mutableListOf<FileItem>()
|
val file = File(path)
|
var files = emptyArray<File>()
|
|
try {
|
files = file.listFiles()
|
} catch (e: Exception) {
|
e.printStackTrace()
|
}
|
//获取失败
|
if (files.isEmpty()) {
|
return emptyList()
|
}
|
|
//如果当前目录不是根目录
|
// if (ROOT_PATH != path) {
|
// fileListItems.add(FileItem("@1", ROOT_PATH))
|
// fileListItems.add(FileItem("@2", file.parent))
|
// }
|
|
files.sortWith(compareBy({ !it.isDirectory }, { it.name }))
|
//添加所有文件
|
for (f in files) {
|
if (!f.isHidden) {
|
val updateTime = DateUtil.getYearToMinStr(Date(f.lastModified()))
|
fileListItems.add(FileItem(f.name, f.path, updateTime, f.size(), f.list()?.size ?: 0))
|
}
|
}
|
|
return fileListItems
|
}
|
|
/**
|
* 获取文件扩展名
|
*/
|
fun getExtensionName(filename: String?): String {
|
if (!filename.isNullOrEmpty()) {
|
val dot = filename.lastIndexOf('.')
|
if (dot > -1 && dot < filename.length - 1) {
|
return filename.substring(dot + 1)
|
}
|
}
|
return ""
|
}
|
|
/**
|
* 获取文件名
|
*/
|
fun getFileName(path: String?): String {
|
if (!path.isNullOrEmpty()) {
|
val dot = path.lastIndexOf('/')
|
if (dot > -1 && dot < path.length - 1) {
|
return path.substring(dot + 1)
|
}
|
}
|
return ""
|
}
|
|
|
/**
|
* 获取文件类型对应的简称标题
|
*/
|
fun getOfficeFileTitle(extensionName: String): String =
|
FILE_TYPE_TITLE_MAP[extensionName] ?: UNKNOWN
|
|
fun getOfficeFileTitleByName(fileName:String):String =
|
getOfficeFileTitle(getExtensionName(fileName))
|
|
/**
|
* 获取文件类型中文简称
|
*/
|
fun getFileTypeName(path: String?): String = when (getExtensionName(path)) {
|
in FILE_EXTENSION_LIST -> "文档"
|
in IMAGE_EXTENSION_LIST -> "图片"
|
in VIDEO_EXTENSION_LIST -> "音视频"
|
else -> "其他"
|
}
|
|
fun hasEnoughMemory(file: File): Boolean {
|
return file.freeSpace > 50 * MB
|
}
|
|
/**
|
* 获取视频缩略图
|
*/
|
fun getVideoBitmapObservable(context: Context, uri: String?): Observable<File> =
|
Observable.create<File> { emitter ->
|
val retriever = MediaMetadataRetriever()
|
try {
|
if (uri?.contains("http") == true) {
|
retriever.setDataSource(uri, mutableMapOf<String, String>())
|
} else {
|
retriever.setDataSource(uri)
|
}
|
val bitmap = retriever.frameAtTime
|
if (bitmap != null) {
|
val b = compress2JPG(context, bitmap)
|
emitter.onNext(b)
|
}
|
} catch (e: Exception) {
|
emitter.onError(e)
|
}
|
emitter.onComplete()
|
}.subscribeOn(Schedulers.io())
|
|
fun getVideoBitmap(context: Context, uri: String?): File? {
|
val retriever = MediaMetadataRetriever()
|
try {
|
if (uri?.contains("http") == true) {
|
retriever.setDataSource(uri, mutableMapOf<String, String>())
|
} else {
|
retriever.setDataSource(uri)
|
}
|
val bitmap = retriever.frameAtTime
|
if (bitmap != null) {
|
compress2JPG(context, bitmap).let {
|
return it
|
}
|
}
|
} catch (e: Exception) {
|
}
|
|
return null
|
}
|
|
|
fun getUri(context: Context?, path: String?): Uri? {
|
return getUri(context, File(path))
|
}
|
|
fun getUri(context: Context?, file: File): Uri? {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
context?.let {
|
FileProvider.getUriForFile(it, it.getString(R.string.file_provide), file)
|
}
|
} else {
|
Uri.fromFile(file)
|
}
|
}
|
|
|
fun parseToFileSize(length: Long): String {
|
return when (length) {
|
in 0..KB -> "$length B"
|
in KB..MB -> "${round(length.toDouble().div(KB.toDouble()).times(100)).div(100.0)} K"
|
in MB..GB -> "${round(length.toDouble().div(MB.toDouble()).times(100)).div(100.0)} M"
|
else -> if (length >= GB) {
|
"${round(length.toDouble().div(GB.toDouble()).times(100)).div(100.0)} G"
|
} else {
|
""
|
}
|
}
|
}
|
}
|
|
/**
|
* 拓展文件列表删除
|
*/
|
fun List<File>.delete() {
|
this.forEach {
|
it.delete()
|
}
|
}
|
|
/**
|
* 拓展获取文件大小
|
*/
|
fun File.size(): String {
|
return when (val bytes = this.length()) {
|
in 0..KB -> "$bytes B"
|
in KB..MB -> "${round(bytes.toDouble().div(KB.toDouble()).times(100)).div(100)} K"
|
in MB..GB -> "${round(bytes.toDouble().div(MB.toDouble()).times(100)).div(100)} M"
|
else -> if (bytes >= GB) {
|
"${round(bytes.toDouble().div(GB.toDouble()).times(100)).div(100)} G"
|
} else {
|
""
|
}
|
}
|
}
|
|
data class FileItem(
|
val name: String,
|
val path: String,
|
val updateTime: String = "",
|
val size: String = "",
|
val listFileNum: Int = 0
|
)
|