| Crates.io | switchy_fs |
| lib.rs | switchy_fs |
| version | 0.1.4 |
| created_at | 2025-05-07 20:53:30.757919+00 |
| updated_at | 2025-07-21 19:17:36.644204+00 |
| description | Switchy File-system package |
| homepage | |
| repository | https://github.com/MoosicBox/MoosicBox |
| max_upload_size | |
| id | 1664460 |
| size | 43,996 |
Cross-platform filesystem abstraction with sync and async operations.
The FS package provides:
sync moduleunsync modulestd::fs based implementationtokio::fs based async implementationAdd this to your Cargo.toml:
[dependencies]
fs = { path = "../fs" }
# With specific features
fs = {
path = "../fs",
features = ["sync", "async", "std", "tokio"]
}
# For testing
fs = {
path = "../fs",
features = ["simulator", "sync", "async"]
}
use fs::sync::{File, OpenOptions, read_to_string, create_dir_all, remove_dir_all};
use std::io::{Read, Write, Seek, SeekFrom};
fn sync_file_operations() -> std::io::Result<()> {
// Create directory
create_dir_all("./data")?;
// Create and write to file
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./data/example.txt")?;
file.write_all(b"Hello, World!")?;
// Read file contents
let contents = read_to_string("./data/example.txt")?;
println!("File contents: {}", contents);
// Append to file
let mut file = OpenOptions::new()
.append(true)
.open("./data/example.txt")?;
file.write_all(b"\nAppended line")?;
// Read with seeking
let mut file = OpenOptions::new()
.read(true)
.open("./data/example.txt")?;
file.seek(SeekFrom::Start(0))?;
let mut buffer = String::new();
file.read_to_string(&mut buffer)?;
println!("Full contents: {}", buffer);
// Clean up
remove_dir_all("./data")?;
Ok(())
}
use fs::unsync::{File, OpenOptions, read_to_string, create_dir_all, remove_dir_all};
use switchy_async::io::{AsyncReadExt, AsyncWriteExt, AsyncSeekExt, SeekFrom};
async fn async_file_operations() -> std::io::Result<()> {
// Create directory
create_dir_all("./async_data").await?;
// Create and write to file
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("./async_data/example.txt")
.await?;
file.write_all(b"Hello, Async World!").await?;
// Read file contents
let contents = read_to_string("./async_data/example.txt").await?;
println!("File contents: {}", contents);
// Append to file
let mut file = OpenOptions::new()
.append(true)
.open("./async_data/example.txt")
.await?;
file.write_all(b"\nAsync appended line").await?;
// Read with seeking
let mut file = OpenOptions::new()
.read(true)
.open("./async_data/example.txt")
.await?;
file.seek(SeekFrom::Start(0)).await?;
let mut buffer = String::new();
file.read_to_string(&mut buffer).await?;
println!("Full contents: {}", buffer);
// Clean up
remove_dir_all("./async_data").await?;
Ok(())
}
use fs::sync::OpenOptions;
// Create new file, fail if exists
let file = OpenOptions::new()
.create(true)
.write(true)
.open("new_file.txt")?;
// Open existing file for reading
let file = OpenOptions::new()
.read(true)
.open("existing_file.txt")?;
// Open file for appending
let file = OpenOptions::new()
.append(true)
.open("log_file.txt")?;
// Create or truncate file for writing
let file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open("output_file.txt")?;
// Read and write access
let file = OpenOptions::new()
.read(true)
.write(true)
.open("data_file.txt")?;
use fs::sync::{create_dir_all, remove_dir_all};
// Create nested directories
create_dir_all("./deep/nested/directory/structure")?;
// Remove directory and all contents
remove_dir_all("./deep")?;
// Async versions
use fs::unsync::{create_dir_all, remove_dir_all};
create_dir_all("./async/nested/dirs").await?;
remove_dir_all("./async").await?;
// Convert between sync and async options
use fs::{sync, unsync};
let async_options = unsync::OpenOptions::new()
.create(true)
.write(true);
// Convert to sync options
let sync_options: sync::OpenOptions = async_options.into();
// Or use explicit conversion
let sync_options = async_options.into_sync();
#[cfg(test)]
mod tests {
use fs::sync::{File, OpenOptions, read_to_string};
#[test]
fn test_file_operations() {
// When simulator feature is enabled, all operations use mock filesystem
let mut file = OpenOptions::new()
.create(true)
.write(true)
.open("test_file.txt")
.unwrap();
file.write_all(b"test data").unwrap();
let contents = read_to_string("test_file.txt").unwrap();
assert_eq!(contents, "test data");
}
}
use fs::{GenericSyncFile, GenericAsyncFile};
use std::io::{Read, Write, Seek};
// Function that works with any sync file implementation
fn process_sync_file<F: GenericSyncFile>(mut file: F) -> std::io::Result<String> {
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
// Function that works with any async file implementation
async fn process_async_file<F: GenericAsyncFile>(mut file: F) -> std::io::Result<String> {
let mut contents = String::new();
file.read_to_string(&mut contents).await?;
Ok(contents)
}
sync: Enable synchronous filesystem operationsasync: Enable asynchronous filesystem operationsstd: Use standard library filesystem implementationtokio: Use Tokio async filesystem implementationsimulator: Use mock filesystem for testingThe package automatically selects the appropriate backend based on enabled features:
simulator feature is enabled, all operations use mock filesystemstd feature is enabled (and not simulator), uses std::fstokio feature is enabled (and not simulator), uses tokio::fsuse fs::sync::{File, OpenOptions};
use std::io::ErrorKind;
match OpenOptions::new().read(true).open("nonexistent.txt") {
Ok(file) => {
// File opened successfully
}
Err(e) => match e.kind() {
ErrorKind::NotFound => {
println!("File not found");
}
ErrorKind::PermissionDenied => {
println!("Permission denied");
}
_ => {
println!("Other error: {}", e);
}
}
}
std::fs and std::io (optional)tokio::fs and tokio::io (optional)