AI时代,没有什么是一个提示词解决不了的。故事的开始事情是这样开始的。我的MacBookAirM1,256GB固态硬盘,8GB内存。Apple官网写着"轻、快、薄",我信了。五年后的今天,当我试图用Xcode更新一个项目时,系统弹出了这个提示:"您的启动磁盘几乎已满。"我陷入
AI时代,没有什么是一个提示词解决不了的。
事情是这样开始的。
我的MacBook Air M1,256GB固态硬盘,8GB内存。Apple官网写着"轻、快、薄",我信了。
五年后的今天,当我试图用Xcode更新一个项目时,系统弹出了这个提示:
"您的启动磁盘几乎已满。"
我陷入了沉默。
打开"关于本机"→"储存空间",那根橙色条几乎要吞噬整个进度条。我开始审视我的磁盘:
| 项目 | 占用空间 | 能删吗 |
|---|---|---|
| Xcode | 12GB | 不敢删,删了等于重装系统 |
| 应用程序 | 60GB | 删了会死 |
| macOS | 30GB | 删了会死 |
| 系统数据 | 103GB | 不敢删,鬼知道是什么 |
| 其他 | 40G | 鬼知道是什么 |
40GB的"其他",像个黑洞。
我决定花钱买解决方案。
打开App Store,搜索"清理""Clean",出来的结果让我眼花缭乱:
我陷入了一个困境:
作为一个写了资深技术的开发者,那天晚上我失眠了。
我翻来覆去在想一件事:
我每天写代码、写脚本、做自动化,为什么要用商业软件来清理自己的电脑?
2026年了,AI都这么强了。
Cursor/Kiro/Copilot可以帮我写代码,ChatGPT可以帮我设计架构。
那为什么不能让AI帮我造一个清理工具?
我打开ChatGPT,给它投喂了一个提示词:
我想要一个macOS清理工具,需要:
1. 实时显示磁盘使用情况
2. 扫描大文件和占用空间最多的文件夹
3. 识别可清理的缓存、日志、重复文件
4. 安全删除功能(预览后确认)
5. 现代化UI,类似CleanMyMac X的界面风格
6. 技术栈:Tauri + React + Rust
请帮我设计架构,给出核心代码示例。
10分钟后,我得到了一份完整的技术方案。
AI告诉我,Tauri是最佳选择:
"相比Electron,Tauri打包体积小(<10MB vs >100MB),内存占用少,非常适合资源紧张的256GB用户。"
# 初始化Tauri项目
pnpm create tauri-app
# 选择:React + TypeScript + Rust
# 进入目录
cd bloat-sweep
# 安装依赖
pnpm install
cargo install tauri-cli
3.1 获取磁盘使用情况
这个问题我扔给AI:
"如何在Rust中获取macOS的磁盘使用情况?需要获取总空间、已用空间、可用空间。"
AI给出了代码:
use std::mem;
pub struct DiskUsage {
pub total: u64,
pub available: u64,
pub used: u64,
}
pub fn get_disk_usage(path: &str) -> Result<DiskUsage, std::io::Error> {
let mut fs: libc::statfs = unsafe { mem::zeroed() };
let c_path = std::ffi::CString::new(path)?;
unsafe {
if libc::statfs(c_path.as_ptr(), &mut fs) == 0 {
Ok(DiskUsage {
total: (fs.f_blocks * fs.f_bsize) as u64,
available: (fs.f_bavail * fs.f_bsize) as u64,
used: ((fs.f_blocks - fs.f_bfree) * fs.f_bsize) as u64,
})
} else {
Err(std::io::Error::last_os_error())
}
}
}
3.2 递归扫描目录文件
"那扫描大文件呢?我想找出超过100MB的文件。"
use std::path::Path;
use std::fs;
#[derive(Debug)]
pub struct FileInfo {
pub path: std::path::PathBuf,
pub size: u64,
pub modified: std::time::SystemTime,
}
const SIZE_THRESHOLD: u64 = 100 * 1024 * 1024; // 100MB
pub fn scan_large_files(root: &Path) -> Result<Vec<FileInfo>, std::io::Error> {
let mut large_files = Vec::new();
walk_dir(root, &mut large_files)?;
Ok(large_files)
}
fn walk_dir(dir: &Path, results: &mut Vec<FileInfo>) -> Result<(), std::io::Error> {
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() {
if let Ok(metadata) = path.metadata() {
if metadata.len() > SIZE_THRESHOLD {
if let Ok(modified) = metadata.modified() {
results.push(FileInfo {
path: path.clone(),
size: metadata.len(),
modified,
});
}
}
}
} else if path.is_dir() {
// 跳过系统目录和隐藏目录
if !path.to_string_lossy().starts_with(".")
&& !is_system_directory(&path) {
walk_dir(&path, results)?;
}
}
}
}
Ok(results)
}
fn is_system_directory(path: &Path) -> bool {
let forbidden = ["/System", "/Library", "/private"];
forbidden.iter().any(|p| path.to_string_lossy().starts_with(p))
}
3.3 前端UI:用React呈现数据
// src/components/DiskUsage.tsx
import { useEffect, useState } from 'react';
import { invoke } from '@tauri-apps/api/tauri';
interface DiskUsage {
total: number;
available: number;
used: number;
}
export function DiskUsage() {
const [usage, setUsage] = useState<DiskUsage | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 调用Rust后端获取磁盘数据
invoke<DiskUsage>('get_disk_usage', { path: '/' })
.then(data => {
setUsage(data);
setLoading(false);
})
.catch(err => console.error('获取磁盘信息失败:', err));
}, []);
if (loading) return <div className="animate-pulse">正在分析磁盘...</div>;
const percentage = ((usage!.used / usage!.total) * 100).toFixed(1);
return (
<div className="bg-white rounded-xl shadow-lg p-6">
<h2 className="text-xl font-bold mb-4">磁盘使用情况</h2>
{/* 进度条 */}
<div className="w-full bg-gray-200 rounded-full h-4 mb-4">
<div
className="bg-blue-600 h-4 rounded-full transition-all duration-500"
style={{ width: `${percentage}%` }}
/>
</div>
{/* 数值显示 */}
<div className="grid grid-cols-3 gap-4 text-center">
<div>
<p className="text-gray-500 text-sm">已用空间</p>
<p className="text-xl font-bold text-red-500">
{formatBytes(usage!.used)}
</p>
</div>
<div>
<p className="text-gray-500 text-sm">可用空间</p>
<p className="text-xl font-bold text-green-500">
{formatBytes(usage!.available)}
</p>
</div>
<div>
<p className="text-gray-500 text-sm">总容量</p>
<p className="text-xl font-bold">
{formatBytes(usage!.total)}
</p>
</div>
</div>
</div>
);
}
function formatBytes(bytes: number): string {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
当我的程序试图扫描/Users以外的文件时,系统弹出了安全告警。
解决方案:在tauri.conf.json中配置权限:
{
"allowlist": {
"fs": {
"all": true,
"read": true,
"write": false,
"path": true,
"recursive": true
}
}
}
对于某些受保护的系统目录,需要在应用首次运行时请求用户授权。
全盘扫描256GB的文件,Rust代码跑一次要3分钟。
解决方案:优化策略
rayon库实现多线程并行遍历use rayon::prelude::*;
pub fn scan_with_parallelism(root: &Path) -> Result<Vec<FileInfo>, std::io::Error> {
let entries: Vec<_> = fs::read_dir(root)?
.flatten()
.filter(|e| {
// 过滤隐藏目录和系统目录
let path = e.path();
!path.to_string_lossy().starts_with(".")
})
.collect();
let files: Vec<FileInfo> = entries
.par_iter()
.filter_map(|entry| {
// 并行处理每个条目
process_entry(entry).ok()
})
.collect();
Ok(files)
}
优化后,扫描时间从3分钟降到了40秒。
最关键的问题:万一用户删错了怎么办?
解决方案:
use std::fs;
// 移动文件到废纸篓(macOS特有)
pub fn move_to_trash(file_path: &Path) -> Result<(), std::io::Error> {
let trash_path = dirs::home_dir()
.unwrap()
.join(".Trash")
.join(file_path.file_name().unwrap());
fs::rename(file_path, trash_path)
}
// 从废纸篓恢复
pub fn restore_from_trash(file_name: &str) -> Result<(), std::io::Error> {
let trash_path = dirs::home_dir()
.unwrap()
.join(".Trash")
.join(file_name);
// 记录删除时的原路径,这里简化处理
// 实际应用中需要记录元数据
Ok(())
}
经过两天的开发,我的清理工具具备了以下功能:
| 功能 | 状态 | 说明 |
|---|---|---|
| 磁盘空间可视化 | ✅ | 实时显示使用情况 |
| 大文件扫描 | ✅ | 找出超过100MB的文件 |
| 文件夹排序 | ✅ | 按占用空间排序 |
| 缓存清理 | ✅ | 识别常见缓存位置 |
| 安全删除 | ✅ | 预览后移动到废纸篓 |
| 现代化UI | ✅ | TailwindCSS + 深色模式 |
| 功能 | 计划 | 说明 |
|---|---|---|
| 重复文件检测 | v2.0 | MD5比对查找重复文件 |
| 应用卸载 | v2.0 | 完整卸载残留清理 |
| 智能建议 | v2.0 | AI推荐可清理项 |
| 项目 | 成本 |
|---|---|
| 开发时间 | 约20小时(AI辅助下) |
| 学习成本 | 约5小时(Tauri入门) |
| 金钱成本 | 0元 |
| 心理成本 | 爽 |
这次开发经历让我深刻体会到:AI真的改变了软件开发的门槛。
| 维度 | 传统开发 | AI辅助开发 |
|---|---|---|
| 需求理解 | 读文档、搜Google | 直接问AI |
| 技术选型 | 逐一对比、踩坑 | AI推荐最优解 |
| 代码编写 | Google/CSDN/StackOverflow | AI直接生成 |
| Bug调试 | print调试、阅读源码 | AI分析错误栈 |
| 性能优化 | 经验积累 | AI给出优化方案 |
【角色】
你是一个资深macOS开发者,精通Rust、Tauri、React。
【任务】
{描述你的需求}
【要求】
1. 给出完整的代码实现
2. 解释关键逻辑
3. 考虑边界情况和错误处理
4. 如果有性能考虑,请一并说明
【输出格式】
1. 方案概述
2. 核心代码(可直接复制使用)
3. 使用说明
4. 注意事项
如果你也是256GB受害者,我可以给你几条建议:
# 清理Homebrew缓存
brew cleanup
# 清理npm缓存
npm cache clean --force
# 清理Docker(如果你用Docker)
docker system prune -a
# 清理Xcode缓存
rm -rf ~/Library/Developer/Xcode/DerivedData
告诉我,我可以帮你做一个定制版。
这篇文章的起因,是256GB磁盘空间不足的焦虑。
文章的结局,是我用AI工具在2天做出了一个自己的清理工具。
AI时代,没有什么是不可能的。
如果你也对这个项目感兴趣,或者有任何问题,欢迎在评论区交流。
另外,我打算把这个工具做得更完善,如果你希望用到这个工具,评论区告诉我,我会考虑分享出来。
欢迎关注我,后续会分享更多AI辅助开发的实战经验。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!