文件系统 #
一、文件系统概述 #
1.1 文件系统架构 #
text
┌─────────────────────────────────────────────────────────────┐
│ 文件系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 前端 API │ │
│ │ @tauri-apps/plugin-fs │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ │ IPC │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Rust 后端 │ │
│ │ std::fs / tokio::fs │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 操作系统 │ │
│ │ Windows / macOS / Linux │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 权限配置 #
json
// src-tauri/capabilities/default.json
{
"permissions": [
"fs:allow-read-text-file",
"fs:allow-write-text-file",
"fs:allow-read-dir",
"fs:allow-exists",
"fs:allow-mkdir",
"fs:allow-remove",
"fs:allow-rename"
]
}
二、安装插件 #
2.1 安装依赖 #
bash
pnpm add @tauri-apps/plugin-fs
2.2 注册插件 #
rust
// src-tauri/src/lib.rs
tauri::Builder::default()
.plugin(tauri_plugin_fs::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
三、文件读写 #
3.1 读取文本文件 #
typescript
import { readTextFile } from '@tauri-apps/plugin-fs';
async function readFile(path: string): Promise<string> {
try {
const content = await readTextFile(path);
return content;
} catch (error) {
console.error('Failed to read file:', error);
throw error;
}
}
3.2 写入文本文件 #
typescript
import { writeTextFile } from '@tauri-apps/plugin-fs';
async function writeFile(path: string, content: string): Promise<void> {
try {
await writeTextFile(path, content);
} catch (error) {
console.error('Failed to write file:', error);
throw error;
}
}
3.3 读取二进制文件 #
typescript
import { readFile } from '@tauri-apps/plugin-fs';
async function readBinaryFile(path: string): Promise<Uint8Array> {
const data = await readFile(path);
return data;
}
3.4 写入二进制文件 #
typescript
import { writeFile } from '@tauri-apps/plugin-fs';
async function writeBinaryFile(path: string, data: Uint8Array): Promise<void> {
await writeFile(path, data);
}
3.5 追加内容 #
typescript
import { writeTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
async function appendToFile(path: string, content: string): Promise<void> {
await writeTextFile(path, content, {
append: true,
});
}
四、目录操作 #
4.1 创建目录 #
typescript
import { mkdir } from '@tauri-apps/plugin-fs';
async function createDirectory(path: string): Promise<void> {
await mkdir(path, {
recursive: true,
});
}
4.2 读取目录 #
typescript
import { readDir } from '@tauri-apps/plugin-fs';
interface DirEntry {
name: string;
isDirectory: boolean;
isFile: boolean;
isSymlink: boolean;
}
async function listDirectory(path: string): Promise<DirEntry[]> {
const entries = await readDir(path);
return entries.map(entry => ({
name: entry.name,
isDirectory: entry.isDirectory,
isFile: entry.isFile,
isSymlink: entry.isSymlink,
}));
}
4.3 删除目录 #
typescript
import { remove } from '@tauri-apps/plugin-fs';
async function removeDirectory(path: string): Promise<void> {
await remove(path, {
recursive: true,
});
}
五、文件操作 #
5.1 检查文件是否存在 #
typescript
import { exists } from '@tauri-apps/plugin-fs';
async function fileExists(path: string): Promise<boolean> {
return await exists(path);
}
5.2 复制文件 #
typescript
import { copyFile } from '@tauri-apps/plugin-fs';
async function copy(source: string, destination: string): Promise<void> {
await copyFile(source, destination);
}
5.3 重命名文件 #
typescript
import { rename } from '@tauri-apps/plugin-fs';
async function renameFile(oldPath: string, newPath: string): Promise<void> {
await rename(oldPath, newPath);
}
5.4 删除文件 #
typescript
import { remove } from '@tauri-apps/plugin-fs';
async function deleteFile(path: string): Promise<void> {
await remove(path);
}
5.5 获取文件元数据 #
typescript
import { stat } from '@tauri-apps/plugin-fs';
interface FileMetadata {
isFile: boolean;
isDirectory: boolean;
isSymlink: boolean;
size: number;
modifiedAt: Date | null;
accessedAt: Date | null;
createdAt: Date | null;
}
async function getMetadata(path: string): Promise<FileMetadata> {
const metadata = await stat(path);
return {
isFile: metadata.isFile,
isDirectory: metadata.isDirectory,
isSymlink: metadata.isSymlink,
size: metadata.size,
modifiedAt: metadata.mtime ? new Date(metadata.mtime) : null,
accessedAt: metadata.atime ? new Date(metadata.atime) : null,
createdAt: metadata.birthtime ? new Date(metadata.birthtime) : null,
};
}
六、特殊目录 #
6.1 获取应用目录 #
typescript
import {
appConfigDir,
appDataDir,
appCacheDir,
appLogDir,
desktopDir,
documentDir,
downloadDir,
homeDir,
pictureDir,
musicDir,
videoDir,
} from '@tauri-apps/api/path';
async function getDirectories() {
return {
config: await appConfigDir(),
data: await appDataDir(),
cache: await appCacheDir(),
log: await appLogDir(),
desktop: await desktopDir(),
documents: await documentDir(),
downloads: await downloadDir(),
home: await homeDir(),
pictures: await pictureDir(),
music: await musicDir(),
videos: await videoDir(),
};
}
6.2 使用基础目录 #
typescript
import { writeTextFile } from '@tauri-apps/plugin-fs';
import { appDataDir, join } from '@tauri-apps/api/path';
async function saveToAppData(filename: string, content: string) {
const appData = await appDataDir();
const filePath = await join(appData, filename);
await writeTextFile(filePath, content);
}
七、文件监听 #
7.1 监听文件变更 #
typescript
import { watch, WatchEvent } from '@tauri-apps/plugin-fs';
async function watchFile(path: string, callback: (event: WatchEvent) => void) {
const unwatch = await watch(path, (event) => {
callback(event);
});
return unwatch;
}
// 使用示例
const unwatch = await watchFile('/path/to/file', (event) => {
console.log('File changed:', event);
if (event.type === 'modify') {
console.log('File modified');
}
});
// 停止监听
unwatch();
7.2 监听目录 #
typescript
import { watch } from '@tauri-apps/plugin-fs';
async function watchDirectory(path: string) {
const unwatch = await watch(
path,
(event) => {
console.log('Directory event:', event);
},
{ recursive: true }
);
return unwatch;
}
八、后端文件操作 #
8.1 Rust 文件命令 #
rust
use std::fs;
use std::path::PathBuf;
#[tauri::command]
fn read_file_content(path: String) -> Result<String, String> {
fs::read_to_string(&path)
.map_err(|e| format!("Failed to read file: {}", e))
}
#[tauri::command]
fn write_file_content(path: String, content: String) -> Result<(), String> {
fs::write(&path, content)
.map_err(|e| format!("Failed to write file: {}", e))
}
#[tauri::command]
fn list_files(dir: String) -> Result<Vec<String>, String> {
let entries = fs::read_dir(&dir)
.map_err(|e| format!("Failed to read directory: {}", e))?;
let files: Vec<String> = entries
.filter_map(|entry| entry.ok())
.map(|entry| entry.path().to_string_lossy().to_string())
.collect();
Ok(files)
}
8.2 异步文件操作 #
rust
use tokio::fs;
#[tauri::command]
async fn read_file_async(path: String) -> Result<String, String> {
fs::read_to_string(&path)
.await
.map_err(|e| format!("Failed to read file: {}", e))
}
#[tauri::command]
async fn write_file_async(path: String, content: String) -> Result<(), String> {
fs::write(&path, content)
.await
.map_err(|e| format!("Failed to write file: {}", e))
}
九、文件工具类 #
9.1 文件管理器 #
typescript
// utils/fileManager.ts
import {
readTextFile,
writeTextFile,
exists,
mkdir,
remove,
rename,
copyFile,
readDir,
} from '@tauri-apps/plugin-fs';
import { join, dirname } from '@tauri-apps/api/path';
export class FileManager {
static async read(path: string): Promise<string> {
return readTextFile(path);
}
static async write(path: string, content: string): Promise<void> {
const dir = await dirname(path);
if (!(await exists(dir))) {
await mkdir(dir, { recursive: true });
}
await writeTextFile(path, content);
}
static async delete(path: string): Promise<void> {
if (await exists(path)) {
await remove(path, { recursive: true });
}
}
static async move(source: string, destination: string): Promise<void> {
await rename(source, destination);
}
static async copy(source: string, destination: string): Promise<void> {
await copyFile(source, destination);
}
static async list(path: string): Promise<string[]> {
const entries = await readDir(path);
return entries.map((e) => e.name);
}
static async exists(path: string): Promise<boolean> {
return exists(path);
}
}
9.2 配置文件管理 #
typescript
// utils/configManager.ts
import { FileManager } from './fileManager';
import { appConfigDir, join } from '@tauri-apps/api/path';
interface AppConfig {
theme: string;
language: string;
fontSize: number;
}
export class ConfigManager {
private static configPath: string | null = null;
private static async getConfigPath(): Promise<string> {
if (!this.configPath) {
const configDir = await appConfigDir();
this.configPath = await join(configDir, 'config.json');
}
return this.configPath;
}
static async load(): Promise<AppConfig> {
const path = await this.getConfigPath();
if (!(await FileManager.exists(path))) {
return this.getDefaultConfig();
}
const content = await FileManager.read(path);
return JSON.parse(content);
}
static async save(config: AppConfig): Promise<void> {
const path = await this.getConfigPath();
await FileManager.write(path, JSON.stringify(config, null, 2));
}
private static getDefaultConfig(): AppConfig {
return {
theme: 'light',
language: 'en',
fontSize: 14,
};
}
}
十、最佳实践 #
10.1 错误处理 #
typescript
async function safeReadFile(path: string): Promise<string | null> {
try {
return await readTextFile(path);
} catch (error) {
console.error(`Failed to read file ${path}:`, error);
return null;
}
}
10.2 路径处理 #
typescript
import { join, resolve, basename, dirname, extname } from '@tauri-apps/api/path';
async function processPath(filePath: string) {
const absolute = await resolve(filePath);
const name = await basename(filePath);
const dir = await dirname(filePath);
const ext = await extname(filePath);
console.log({ absolute, name, dir, ext });
}
10.3 大文件处理 #
typescript
// 分块读取大文件
async function readLargeFile(path: string, chunkSize: number = 1024 * 1024) {
const file = await readFile(path);
const chunks: Uint8Array[] = [];
for (let i = 0; i < file.length; i += chunkSize) {
const chunk = file.slice(i, i + chunkSize);
chunks.push(chunk);
}
return chunks;
}
十一、总结 #
11.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 文件读写 | 使用 fs 插件 |
| 目录操作 | mkdir、readDir、remove |
| 特殊目录 | 使用 path API |
| 文件监听 | watch API |
| 后端操作 | Rust std::fs |
11.2 下一步 #
现在你已经掌握了文件系统操作,接下来让我们学习 数据库集成,了解如何在 Tauri 中使用数据库!
最后更新:2026-03-28