egui_file_dialog/
file_system.rs
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use crate::data::{Disks, Metadata, UserDirectories};
pub trait FileSystem {
fn metadata(&self, path: &Path) -> io::Result<Metadata>;
fn is_dir(&self, path: &Path) -> bool;
fn is_file(&self, path: &Path) -> bool;
fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>>;
fn get_disks(&self, canonicalize_paths: bool) -> Disks;
fn is_path_hidden(&self, path: &Path) -> bool;
fn create_dir(&self, path: &Path) -> io::Result<()>;
fn user_dirs(&self, canonicalize_paths: bool) -> Option<UserDirectories>;
fn current_dir(&self) -> io::Result<PathBuf>;
fn load_text_file_preview(&self, _path: &Path, _max_chars: usize) -> io::Result<String> {
Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"load_text_file_preview not implemented.".to_string(),
))
}
}
impl std::fmt::Debug for dyn FileSystem + Send + Sync {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<FileSystem>")
}
}
pub struct NativeFileSystem;
impl FileSystem for NativeFileSystem {
fn metadata(&self, path: &Path) -> io::Result<Metadata> {
let mut metadata = Metadata::default();
let md = std::fs::metadata(path)?;
metadata.size = Some(md.len());
metadata.last_modified = md.modified().ok();
metadata.created = md.created().ok();
metadata.file_type = Some(format!("{:?}", md.file_type()));
Ok(metadata)
}
fn is_dir(&self, path: &Path) -> bool {
path.is_dir()
}
fn is_file(&self, path: &Path) -> bool {
path.is_file()
}
fn read_dir(&self, path: &Path) -> io::Result<Vec<PathBuf>> {
Ok(std::fs::read_dir(path)?
.filter_map(Result::ok)
.map(|entry| entry.path())
.collect())
}
fn load_text_file_preview(&self, path: &Path, max_chars: usize) -> io::Result<String> {
let mut file = std::fs::File::open(path)?;
let mut chunk = [0; 96]; let mut buffer = String::new();
let mut total_read = 0;
while total_read < max_chars {
let bytes_read = file.read(&mut chunk)?;
if bytes_read == 0 {
break; }
let chars_read: String = String::from_utf8(chunk[..bytes_read].to_vec())
.map_err(|_| io::Error::from(io::ErrorKind::InvalidData))?;
total_read += chars_read.len();
buffer.push_str(&chars_read);
}
Ok(buffer.to_string())
}
fn get_disks(&self, canonicalize_paths: bool) -> Disks {
Disks::new_native_disks(canonicalize_paths)
}
fn is_path_hidden(&self, path: &Path) -> bool {
is_path_hidden(path)
}
fn create_dir(&self, path: &Path) -> io::Result<()> {
std::fs::create_dir(path)
}
fn user_dirs(&self, canonicalize_paths: bool) -> Option<UserDirectories> {
if let Some(dirs) = directories::UserDirs::new() {
return Some(UserDirectories::new(
UserDirectories::canonicalize(Some(dirs.home_dir()), canonicalize_paths),
UserDirectories::canonicalize(dirs.audio_dir(), canonicalize_paths),
UserDirectories::canonicalize(dirs.desktop_dir(), canonicalize_paths),
UserDirectories::canonicalize(dirs.document_dir(), canonicalize_paths),
UserDirectories::canonicalize(dirs.download_dir(), canonicalize_paths),
UserDirectories::canonicalize(dirs.picture_dir(), canonicalize_paths),
UserDirectories::canonicalize(dirs.video_dir(), canonicalize_paths),
));
}
None
}
fn current_dir(&self) -> io::Result<PathBuf> {
std::env::current_dir()
}
}
#[cfg(windows)]
fn is_path_hidden(path: &Path) -> bool {
use std::os::windows::fs::MetadataExt;
std::fs::metadata(path).is_ok_and(|metadata| metadata.file_attributes() & 0x2 > 0)
}
#[cfg(not(windows))]
fn is_path_hidden(path: &Path) -> bool {
let Some(file_name) = path.file_name() else {
return false;
};
let Some(s) = file_name.to_str() else {
return false;
};
if s.starts_with('.') {
return true;
}
false
}