feat: add native folder size calculator

This commit is contained in:
Kagura 2024-10-17 23:13:28 +08:00
parent 52483f05fd
commit 7741898163
11 changed files with 513 additions and 7 deletions

2
app/.gitignore vendored
View file

@ -1,2 +1,4 @@
/build
/src/main/rust/libsysinfo/target/
/src/main/rust/libfshelper/target/
/src/main/rust/libfshelper/.vscode/

View file

@ -3,10 +3,13 @@ package com.dazuoye.filemanager.fileSystem
import android.content.Context
import android.icu.text.DecimalFormat
import android.text.format.DateFormat
import android.util.Log
import com.dazuoye.filemanager.fileSystem.byTypeFileLister.DocumentLister
import com.dazuoye.filemanager.fileSystem.byTypeFileLister.ImageLister
import com.dazuoye.filemanager.fileSystem.byTypeFileLister.MusicLister
import com.dazuoye.filemanager.fileSystem.byTypeFileLister.VideoLister
import com.dazuoye.filemanager.utils.FSHelper.getFolderSizeBytesNativeMethod
import com.dazuoye.filemanager.utils.FSHelper.getFolderSizeNativeMethod
import java.io.File
import java.net.URLConnection
import java.nio.file.Files
@ -14,6 +17,7 @@ import java.nio.file.attribute.BasicFileAttributes
import java.sql.Date
import java.sql.Timestamp
import java.time.Instant
import kotlin.math.log
class WrappedFile(private val f: File, skipCalculateDirectorySize: Boolean = false) {
companion object {
@ -111,7 +115,11 @@ class WrappedFile(private val f: File, skipCalculateDirectorySize: Boolean = fal
isSizeCalculated = false
0
} else {
getFolderSize(f)
try {
getFolderSizeBytesNativeMethod(f.path)
} catch (_: Exception) {
getFolderSize(f)
}
}
}
@ -129,13 +137,23 @@ class WrappedFile(private val f: File, skipCalculateDirectorySize: Boolean = fal
}
fun getSizeString(): String {
if (size == 0L && type == Type.DIRECTORY && !isSizeCalculated) {
// Calculate Size
size = getFolderSize(f)
isSizeCalculated = true
} else {
return "0B"
if (type == Type.DIRECTORY) { // 下面只对文件夹有效
if (size == 0L && !isSizeCalculated) {
// Calculate Size
try {
val sizeStr = getFolderSizeNativeMethod(f.path)
isSizeCalculated = true
return sizeStr
} catch (e: Exception) {
Log.e("getFolderSizeNativeMethod", "getSizeString: ${e.toString()}")
}
// 备用方法
isSizeCalculated = true
size = getFolderSize(f)
}
}
// 最后 format (fallback方法 + 普通文件)
return getSizeString(size.toULong())
}

View file

@ -0,0 +1,17 @@
package com.dazuoye.filemanager.utils;
public class FSHelper {
static {
System.loadLibrary("fshelper");
}
public static String getFolderSizeNativeMethod(String dir) {
return getFolderSizeNative(dir);
}
public static long getFolderSizeBytesNativeMethod(String dir) {
return getFolderSizeBytesNative(dir);
}
private static native String getFolderSizeNative(String dir);
private static native long getFolderSizeBytesNative(String dir);
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,5 @@
[target.aarch64-linux-android]
linker = "/home/kagura/Programs/AndroidStudio/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang"
[target.x86_64-linux-android]
linker = "/home/kagura/Programs/AndroidStudio/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android35-clang"

295
app/src/main/rust/libfshelper/Cargo.lock generated Normal file
View file

@ -0,0 +1,295 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bytes"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
[[package]]
name = "cesu8"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "combine"
version = "4.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
dependencies = [
"bytes",
"memchr",
]
[[package]]
name = "fshelper"
version = "0.1.0"
dependencies = [
"jni",
"walkdir",
]
[[package]]
name = "jni"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
dependencies = [
"cesu8",
"cfg-if",
"combine",
"jni-sys",
"log",
"thiserror",
"walkdir",
"windows-sys 0.45.0",
]
[[package]]
name = "jni-sys"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "proc-macro2"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "syn"
version = "2.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View file

@ -0,0 +1,11 @@
[package]
name = "fshelper"
version = "0.1.0"
edition = "2021"
[dependencies]
jni = "0.21.1"
walkdir = "2.5.0"
[lib]
crate-type = ["cdylib"]

View file

@ -0,0 +1,4 @@
fn main() {
println!("cargo:rustc-link-arg=-z");
println!("cargo:rustc-link-arg=max-page-size={}",1024*16);
}

View file

@ -0,0 +1,109 @@
use jni::objects::{JClass, JString};
use jni::sys::{jlong, jstring};
use jni::JNIEnv;
use std::{fs, i64};
use walkdir::WalkDir;
#[no_mangle]
pub extern "system" fn Java_com_dazuoye_filemanager_utils_FSHelper_getFolderSizeNative<'local>(
mut env: JNIEnv<'local>,
_: JClass<'local>,
input: JString<'local>,
) -> jstring {
let dir: String = env
.get_string(&input)
.expect("failed to parse input")
.into();
if !fs::exists(&dir).expect(format!("Cannot stat {}", dir).as_str()) {
return env
.new_string(format!("{} not exists!", dir))
.expect("Couldn't create java string!")
.into_raw();
}
// 从这里保证文件至少存在了
let mut size: u64 = 0;
for entry in WalkDir::new(dir) {
match entry {
Ok(item) => {
match item.metadata() {
Ok(metadata) => size += metadata.len(),
Err(e) => {
eprintln!("Error getting metadata for item: {:?}", e);
continue;
}
}
},
Err(e) => {
eprintln!("Error walking directory: {:?}", e);
continue;
}
}
}
let output = env
.new_string(format_size(size))
.expect("Couldn't create java string!");
output.into_raw()
}
#[no_mangle]
pub extern "system" fn Java_com_dazuoye_filemanager_utils_FSHelper_getFolderSizeBytesNative<'local>(
mut env: JNIEnv<'local>,
_: JClass<'local>,
input: JString<'local>,
) -> jlong {
let dir: String = env
.get_string(&input)
.expect("failed to parse input")
.into();
if !fs::exists(&dir).expect(format!("Cannot stat {}", dir).as_str()) {
return 0;
}
// 从这里保证文件至少存在了
let mut size: u64 = 0;
for entry in WalkDir::new(dir) {
match entry {
Ok(item) => {
match item.metadata() {
Ok(metadata) => size += metadata.len(),
Err(e) => {
eprintln!("Error getting metadata for item: {:?}", e);
continue;
}
}
},
Err(e) => {
eprintln!("Error walking directory: {:?}", e);
continue;
}
}
}
match i64::try_from(size) {
Ok(compatible) => compatible,
Err(_) => i64::MAX
}
}
fn format_size(size: u64) -> String {
// 定义单位
let units = ["B", "KB", "MB", "GB", "TB", "PB"];
let mut size = size as f64;
let mut unit_index = 0;
// 按 1024 递减计算,直到找到合适的单位
while size >= 1024.0 && unit_index < units.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
// 保留两位小数格式化输出
format!("{:.2} {}", size, units[unit_index])
}

View file

@ -0,0 +1,45 @@
use std::fs;
use walkdir::WalkDir;
fn main() {
let dir: String = String::from(".");
if !fs::exists(&dir).expect(format!("Cannot stat {}", dir).as_str()) {
return;
}
// 从这里保证文件至少存在了
let mut size: u64 = 0;
for entry in WalkDir::new(dir) {
match entry {
Ok(item) => match item.metadata() {
Ok(metadata) => size += metadata.len(),
Err(e) => {
eprintln!("Error getting metadata for item: {:?}", e);
continue;
}
},
Err(e) => {
eprintln!("Error walking directory: {:?}", e);
continue;
}
}
}
println!("{}", format_size(size))
}
fn format_size(size: u64) -> String {
// 定义单位
let units = ["B", "KB", "MB", "GB", "TB", "PB"];
let mut size = size as f64;
let mut unit_index = 0;
// 按 1024 递减计算,直到找到合适的单位
while size >= 1024.0 && unit_index < units.len() - 1 {
size /= 1024.0;
unit_index += 1;
}
// 保留两位小数格式化输出
format!("{:.2} {}", size, units[unit_index])
}