use std::fs;
use std::path::Path;
use std::time::SystemTime;
#[derive(Debug)]
pub struct FileInfo {
pub file_name: String,
pub file_type: String,
pub file_path: String,
pub created_time: SystemTime,
pub modified_time: SystemTime,
pub size: u64,
pub size_kb: u64,
pub size_mb: u64,
}
pub fn archive_dir(dir: &str, name: &str) -> std::io::Result<()> {
let tar_gz = format!("{}.tar.gz", name);
let output = std::process::Command::new("tar")
.arg("czvf")
.arg(&tar_gz)
.arg(dir)
.output()?;
if !output.status.success() {
return Err(std::io::Error::new(std::io::ErrorKind::Other, "tar failed"));
}
Ok(())
}
pub fn remove_dir(dir: &str) -> std::io::Result<()> {
fs::remove_dir_all(dir)
}
pub fn remove_file(file: &str) -> std::io::Result<()> {
fs::remove_file(file)
}
pub fn read_file(file: &str) -> std::io::Result<Vec<u8>> {
fs::read(file)
}
pub fn write_file(file: &str, data: &[u8]) -> std::io::Result<()> {
fs::write(file, data)
}
pub fn read_text_file(file: &str) -> std::io::Result<String> {
fs::read_to_string(file)
}
pub fn write_text_file(file: &str, data: &str) -> std::io::Result<()> {
fs::write(file, data)
}
pub fn move_file(src: &str, dest: &str) -> std::io::Result<()> {
fs::rename(src, dest)
}
pub fn get_dir_info(dir: &str) -> std::io::Result<Vec<FileInfo>> {
let mut files_info = Vec::new();
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries {
let entry = entry?;
let path = entry.path();
let metadata = fs::metadata(&path)?;
let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
let file_type = if metadata.is_file() {
"File".to_string()
} else if metadata.is_dir() {
"Directory".to_string()
} else {
"Unknown".to_string()
};
let size = metadata.len();
let size_kb = size / 1024;
let size_mb = size_kb / 1024;
let created_time = metadata.created()?;
let modified_time = metadata.modified()?;
files_info.push(FileInfo {
file_name,
file_type,
file_path: path.to_str().unwrap().to_string(),
created_time,
modified_time,
size,
size_kb,
size_mb,
});
}
}
Ok(files_info)
}
pub fn get_size(dir: &str) -> std::io::Result<u64> {
let path = Path::new(dir);
get_size_by_path(path)
}
fn get_size_by_path(path: &Path) -> std::io::Result<u64> {
let metadata = fs::metadata(path)?;
if metadata.is_file() {
Ok(metadata.len())
} else if metadata.is_dir() {
let mut total_size = 0;
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
if path.is_symlink() {
continue;
}
total_size += get_size_by_path(&entry.path())?;
}
Ok(total_size)
} else {
Ok(0)
}
}
pub fn remove_old_files(dir: &str, keep: u64) -> std::io::Result<Vec<String>> {
let mut dir_size = get_size(dir).unwrap();
if dir_size < keep {
return Ok(vec![]);
}
let path = Path::new(dir);
let mut files = get_files(path)?;
files.retain(|path| {
fs::metadata(path)
.ok()
.map(|metadata| !metadata.file_type().is_symlink())
.unwrap_or(false)
});
files.sort_by_key(|path| {
fs::metadata(path)
.ok()
.and_then(|metadata| metadata.modified().ok())
.unwrap_or(std::time::SystemTime::UNIX_EPOCH)
});
let mut removed_files = Vec::new();
while dir_size > keep {
if let Some(file) = files.pop() {
if file.is_symlink() {
continue;
}
let metadata = fs::metadata(&file)?;
let size = metadata.len();
dir_size -= size;
removed_files.push(file.to_str().unwrap().to_string());
let _ = fs::remove_file(file.clone());
} else {
break;
}
}
Ok(removed_files)
}
pub fn remove_files(files: Vec<String>) -> std::io::Result<()> {
for file in files {
let _ = fs::remove_file(file);
}
Ok(())
}
pub fn read_files(files: Vec<String>) -> std::io::Result<Vec<Vec<u8>>> {
let mut buffers = Vec::new();
for file in files {
let buffer = read_file(&file)?;
buffers.push(buffer);
}
Ok(buffers)
}
pub fn get_files(dir: &Path) -> std::io::Result<Vec<std::path::PathBuf>> {
let mut files = Vec::new();
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries {
let path = entry?.path();
if path.is_file() {
if path.is_symlink() {
continue;
}
files.push(path);
} else if path.is_dir() {
match get_files(&path) {
Ok(sub_files) => files.extend(sub_files),
Err(_) => continue, }
}
}
}
Ok(files)
}
#[cfg(test)]
mod tests_dir_info {
use super::*;
#[test]
fn test_get_size() {
let dir = "/Users/mojih/Downloads";
let size = get_size(dir).unwrap();
println!("Total size of {} is {} bytes", dir, size);
println!("Total size of {} is {} MB", dir, size / 1024 / 1024);
}
#[test]
fn test_get_dir_info() {
let dir = "/Users/mojih/Downloads";
let files_info = get_dir_info(dir).unwrap();
for file_info in files_info {
println!("{:?}\n", file_info);
}
}
}
#[cfg(test)]
mod tests_remove_old_files {
use super::*;
#[test]
fn test_remove_old_files() {
let dir = "/Users/mojih/Downloads/test";
let keep = 1024 * 1024 * 80;
let removed_files = remove_old_files(dir, keep).unwrap();
println!("Removed files: {:?}", removed_files);
}
#[test]
fn test_get_files() {
let dir = "/Users/mojih/Downloads/test";
for entry in fs::read_dir(dir).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
println!("path: {:?}", path);
}
}
#[test]
fn test_get_size_by_path() {
let path = "/Users/mojih/Downloads/test";
let size = get_size(path);
if size.is_err() {
println!("1111Error: {:?}", size);
} else {
let size = size.unwrap();
println!("size: {:?}", size);
println!("size: {:?}", size / 1024 / 1024);
}
}
}