A Windows RAM disk manager built on .NET 10 and WinFsp.
Create, mount and manage in-memory volumes that appear as normal drive letters in Explorer.
- Mount multiple RAM disks simultaneously, each with its own drive letter
- Configurable capacity, volume label and read-only flag
- Dynamic memory allocation — disk capacity is a ceiling, not a reservation; memory is consumed only as files are written and released when files are deleted
- Edit a mounted disk — change label, capacity, auto-mount, and image path live without data loss; changing the drive letter or read-only flag remounts the disk
- Optional persistence — save the disk contents to a
.mdrimage file and restore it on next mount; Save Image is always available and prompts for a file path if none is set; the disk card shows a "Saving..." overlay while the save is in progress - Import an existing
.mdrimage — right-click the disk list and choose Import Disk... to pick an existing image file and mount it directly; capacity and volume label are read from the image and shown read-only (not re-entered), and a warning is shown up front if the file is invalid or already in use by another mounted disk - Optional auto-save — periodically save the disk contents to its image file every 1–60 minutes (configurable when creating or editing a disk); a save also fires immediately when enabled and once more right before the disk is unmounted or the app exits, so nothing is lost between intervals. Both periodic saves and the final save on unmount/exit are skipped automatically when nothing has changed since the last save, avoiding unnecessary disk I/O on an idle disk. The image file must be selected through the file picker (no manual typing) and cannot be located on a RAM disk or reused across two disks. Checking Read Only, or clearing the selected image file, unchecks and disables auto-save (and Read Only also disables image compression) — a read-only disk's contents never change, so there is nothing to save or compress, an empty read-only disk would be meaningless, and auto-save has nothing to save to without an image file. The disk card shows the timestamp of the most recent content modification
- Selectable image compression — choose a compression level (Off / Fast / Balanced / Max) for the saved
.mdrimage, trading save/load speed for file size; defaults to Fast. Selecting Balanced or Max shows an inline warning that save times may increase significantly - Auto-mount saved profiles on application startup
- Double-click a disk card to open it in Explorer; right-click for Open in Explorer and Open Image File Directory (opens the folder containing the disk's
.mdrimage file; grayed out when the disk has no image file configured) - System-tray icon for quick access; minimizes to tray on window close
- Tray icon tooltip — hover to see all mounted disks with live usage percentages
- High-usage warning — system tray notification when a disk exceeds a per-disk usage threshold, configurable when creating or editing that disk (default 90%, on by default; can be disabled entirely for a given disk); the warning auto-clears once usage drops 5 points below that threshold
- Optional start-minimized mode — launch directly to tray without showing the main window; shows a one-time tray balloon notification on that startup so the app's presence isn't missed
- Temp directory redirection — right-click a disk to set it as the Windows TEMP/TMP directory; reset to the system default from the toolbar, context menu, or tray menu; automatically resets to the system default when the disk is unmounted or remounted; on startup, if TEMP/TMP points to any RAM disk profile a warning is shown — if the disk is not set to auto-mount, TEMP is also automatically reset to the system default
- Exit confirmation — exiting the app (toolbar button or tray menu) while any disk is mounted brings the main window to the foreground and asks for confirmation; if TEMP/TMP points to any mounted RAM disk, the confirmation also warns that TEMP will be reset, and confirming resets it before exiting; when disks with auto-save are mounted, a full-window saving overlay with a spinner is displayed while the final image save runs in the background — system-initiated shutdown bypasses the confirmation prompt
- NTFS-compatible volume identity — the RAM disk reports its filesystem type as NTFS, making it fully usable as a destination for tools that require an NTFS volume (e.g. WinGet, Windows Update staging, BITS downloads)
- Format disk — right-click a disk and choose Format to delete all files and folders instantly (read-only disks are protected); the context menu is organized into three groups: navigation, configuration, and destructive operations
- Clone disk — right-click a disk and choose Clone Disk... to copy its contents either onto another mounted, writable disk (overwriting that disk's existing contents, after a confirmation prompt) or out to a brand-new
.mdrimage file with a selectable compression level; an export path already used by another mounted disk (including the source disk's own image file) is rejected immediately after picking it - Snapshot / version history — optionally cap saved snapshots by count and/or total size when creating or editing a disk; a timestamped snapshot (
{name}.yyyyMMdd-HHmmss.mdr) is written next to the main image on every save that has content changes, alongside the main image, with older snapshots pruned automatically once a limit is exceeded. Identical file content is stored only once across all snapshots of the same disk (content-addressed, deduplicated by SHA-256), so keeping many snapshots costs far less disk space than the sum of their logical sizes. Right-click a disk and choose Restore Snapshot... to pick a prior point in time from a list (with timestamp and size) and replace the disk's current contents with it, after a confirmation prompt; the restored contents are saved on the next save/auto-save rather than immediately. Deleting a disk's image file also removes all of its snapshots and any now-unused deduplicated content - System tray menu — quick access to Reset Temp Directory (executes silently with a notification bubble result) and Settings in addition to Show, New Disk, and Exit
- Main window opens centered on the primary screen and is brought to the foreground on startup
- Bilingual UI — English and Simplified Chinese, auto-detected from system locale with manual override in Settings
- Light and dark themes — follows the Windows app theme by default, with a manual override (System Default / Light / Dark) in Settings; switches instantly without restarting
- At-a-glance disk cards — the drive-letter badge shows small corner icons for read-only, current-TEMP-directory, and has-backing-image status (hover the image icon to see the image path); the usage bar displays its percentage and turns to a warning color (along with the free-space text) once usage crosses that disk's configured high-usage threshold (if enabled); read-only disks collapse the usage bar into a single line showing the backing image path instead of capacity figures that never change
- About dialog — accessible from the overflow menu; shows the app version and a link to the GitHub repository
Two ZIPs are published on the Releases page for each version — pick one:
ManagedDrive-vX.Y.Z-win-x64-portable.zip— small download; requires the .NET 10 Desktop Runtime to be installed separately.ManagedDrive-vX.Y.Z-win-x64-selfcontained.zip— larger download (bundles its own .NET runtime); no runtime install needed.
Extract either one anywhere and run ManagedDrive.exe directly. ManagedDrive.exe is a single-file executable — the ZIP contains it plus one small companion winfsp-msil.dll (the managed WinFsp interop assembly, which can't be embedded in the single-file bundle) that must stay next to it. The only registry write is the optional "Run at startup" setting; nothing else touches the registry. WinFsp must be installed separately first in both cases (see Prerequisites below).
| Requirement | Notes |
|---|---|
| Windows 10 / 11 (64-bit) | ARM64 is not currently tested |
| WinFsp 2.2.26183 (2026 Beta2) | Must be installed before running ManagedDrive. Download the installer directly: winfsp-2.2.26183.msi — do not use winget install WinFsp.WinFsp, as the winget package lags behind the latest release. The managed assembly winfsp-msil.dll is installed to C:\Program Files (x86)\WinFsp\bin\ and is referenced by the project automatically. |
| .NET 10 Desktop Runtime | Only required for the -portable ZIP (framework-dependent). Not needed for the -selfcontained ZIP. |
| .NET 10 SDK | Required to build. |
# 1. Download and install WinFsp 2.2.26183 (2026 Beta2)
# https://github.com/winfsp/winfsp/releases/download/v2.2B2/winfsp-2.2.26183.msi
# 2. Clone the repository
git clone https://github.com/coldhighsun/ManagedDrive
cd ManagedDrive
# 3. Build
dotnet build
# 4. Run
dotnet run --project src/ManagedDrive.App -c ReleaseAlternatively open ManagedDrive.slnx in Visual Studio 2022+ and press F5.
ManagedDrive/
├── src/
│ ├── ManagedDrive.Core/ # In-memory file system engine (WinFsp)
│ │ ├── DiskOptions.cs # Immutable mount configuration record
│ │ ├── FileNode.cs # Single file or directory node
│ │ ├── FileNodeMap.cs # Thread-safe path→node dictionary
│ │ ├── MemoryFileSystem.cs # FileSystemBase implementation (all WinFsp callbacks)
│ │ ├── RamDisk.cs # Mount/unmount lifecycle wrapper
│ │ ├── MountManager.cs # Multi-disk manager
│ │ ├── DiskImageSerializer.cs # Binary persistence (.mdr format)
│ │ ├── SnapshotManager.cs # Timestamped snapshot naming, listing, pruning, GC
│ │ └── SnapshotStore.cs # Snapshot index format + content-addressed blob store
│ │
│ └── ManagedDrive.App/ # WPF desktop application
│ ├── Localization/ # ResourceDictionary strings (en-US, zh-CN)
│ ├── Themes/ # AppTheme.xaml styles + light/dark color palettes, ThemeManager
│ ├── Infrastructure/ # RelayCommand
│ ├── Models/ # AppConfiguration, DiskProfile
│ ├── Services/ # SettingsStore, StartupManager, TempDirResetService
│ ├── ViewModels/ # MainViewModel, DiskViewModel
│ ├── Views/ # CreateDiskDialog, CloneDiskDialog, RestoreSnapshotDialog, SettingsDialog, ConfirmDialog, AboutDialog, TrayTooltipView
│ ├── MainWindow.xaml(.cs) # Main window
│ └── App.xaml(.cs) # Startup, tray icon, auto-mount
│
├── tests/
│ └── ManagedDrive.Tests/ # xUnit v3 unit tests (pure-managed code only)
│ ├── FileNodeTests.cs
│ ├── FileNodeMapTests.cs
│ ├── MemoryFileSystemCloneTests.cs
│ ├── DiskImageSerializerTests.cs
│ └── WildcardMatchTests.cs
│
└── benchmarks/
└── ManagedDrive.Benchmarks/ # BenchmarkDotNet throughput/latency benchmarks
├── Program.cs
├── DriveLetterHelper.cs # Picks a free mount point (D:-Z:) for the RAM disk
├── SequentialReadWriteBenchmarks.cs # Sequential read/write at 4 KB and 1 MB
├── RandomAccessBenchmarks.cs # Random-seek reads and small-file high-frequency writes
└── ConcurrentAccessBenchmarks.cs # Multi-threaded reads/writes to disjoint files, measuring FileNodeMap lock contention
ManagedDrive uses WinFsp (Windows File System Proxy) to present an in-memory directory tree as a real Windows volume. WinFsp ships a signed kernel driver that acts as a bridge; all file I/O is forwarded to MemoryFileSystem, which stores data in .NET byte arrays.
Key classes:
FileNode— holdsFsp.Interop.FileInfometadata, abyte[]data buffer, a cached leaf name, and a security descriptor.FileNodeMap— a case-insensitiveSortedDictionary<string, FileNode>that maps full paths to nodes, supports paginated child enumeration via a bounded prefix walk, and tracks total allocated bytes with an incrementally-maintained counter (O(1) reads instead of a full scan). Thread-safe via the C# 13Locktype.MemoryFileSystem : FileSystemBase— overrides all 21 required WinFsp callbacks (Create,Open,Read,Write,Rename,CanDelete,ReadDirectoryEntry, etc.) and enforces a configurable capacity ceiling, returningSTATUS_DISK_FULLwhen exceeded; memory is not pre-allocated — eachFileNodeholds only the bytes actually written.RamDisk— composesMemoryFileSystemwith aFileSystemHost. The staticCreate()factory mounts the volume and polls until the drive letter is visible in the OS (up to 2.5 s), then broadcastsSHCNE_DRIVEADDto refresh Explorer.Dispose()unmounts. When an auto-save interval is configured, a background timer saves the image immediately and then on every interval, skipping ticks where nothing has changed since the last save; a final save runs onDispose()too, also skipped if nothing changed since the last save, so unmounting, remounting, or exiting never performs a redundant write.MountManager— thread-safe registry of activeRamDiskinstances. FiresDiskMounted/DiskUnmountedevents.DiskImageSerializer— reads/writes.mdrfiles (full FS state including metadata, ACLs, and file data), optionally gzip-compressed at a user-selectable level.SnapshotManager/SnapshotStore— write a timestamped, read-only copy of the disk's contents next to the main.mdrimage after every save (when snapshot limits are configured), list/prune them, and restore one back onto a live disk. File content is deduplicated by SHA-256 hash into a shared blob store, so snapshots of a mostly-unchanged disk cost little extra space.
A little-endian binary format:
| Field | Type | Description |
|---|---|---|
| Magic | byte[4] |
MDRD |
| Version | int32 |
Currently 2 |
| CompressionLevel | byte |
ImageCompressionLevel value (0=None/1=Fastest/2=Optimal/3=SmallestSize); when not None, everything below is gzip-compressed |
| Capacity | uint64 |
Configured capacity in bytes |
| VolumeLabel | string |
Length-prefixed UTF-8 |
| NodeCount | int32 |
Number of nodes that follow |
| Node entries | — | Path, metadata (10 fields), security descriptor, file data |
Version 1 images (no CompressionLevel byte, always uncompressed) remain readable for backward compatibility.
Snapshots use a separate, independent format from .mdr images. For a main image disk.mdr, snapshots are named disk.yyyyMMdd-HHmmss.mdr in the same folder, each a small binary index file (magic MDRS) listing every file/directory's metadata plus, for non-empty files, a SHA-256 hash. The actual file content lives in a shared, content-addressed blob store at disk.snapblobs/ (sharded into 2-character hex subfolders), gzip-compressed per-blob at the disk's configured compression level — identical content across snapshots is stored only once. Pruning old snapshots also garbage-collects any blob no longer referenced by a remaining snapshot.
- Settings are stored as JSON at
%APPDATA%\ManagedDrive\settings.json, including each disk's own high-usage warning threshold (or its disabled state). - Windows startup registration uses
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run(no elevation required). - Version is derived from git tags (
v-prefixed, e.g.v0.1.0) via MinVer.
Read/write, random-access, and small-file throughput measured with BenchmarkDotNet on:
| CPU | Intel Core i9-13980HX, 24C/32T, 2.2 GHz base |
| RAM | 64 GB |
| Disk | KIOXIA KXG8AZNV1T02 NVMe SSD (1 TB) |
| OS | Windows 11 Pro (Build 26200) |
| Runtime | .NET 10.0.9 · BenchmarkDotNet 0.15.8 |
SequentialReadWriteBenchmarks creates or reads a single file via FileStream at 4 KB and 1 MB. Writes use FileOptions.WriteThrough (no OS write-back cache) and reads use FileOptions.SequentialScan.
| File Size | Operation | RAM Disk | NVMe SSD | Ratio |
|---|---|---|---|---|
| 4 KB | Write | 1.5 MB/s | 0.8 MB/s | 1.9× faster |
| 4 KB | Read | 2.2 MB/s | 4.5 MB/s | 0.5× slower |
| 1 MB | Write | 279 MB/s | 85 MB/s | 3.3× faster |
| 1 MB | Read | 547 MB/s | 1,139 MB/s | 0.5× slower |
Why are RAM disk reads slower?
Physical disk reads appear fast because the OS page cache keeps recently-written files in DRAM. The RAM disk reads go through WinFsp's kernel–userspace bridge, which adds IPC overhead compared to the direct page-cache path. In workloads where data is written once and read many times from cold cache (e.g. build outputs, temp files that outlive page-cache pressure), the RAM disk will consistently outperform SSD on reads too.4 KB note: small-file results are dominated by file-open/close syscall overhead, not transfer speed.
Raw latency (mean, [SimpleJob(warmupCount: 2, iterationCount: 3)]):
| File Size | RamDisk Write | RamDisk Read | NVMe Write | NVMe Read |
|---|---|---|---|---|
| 4 KB | 2,582 μs | 1,785 μs | 4,988 μs | 871 μs |
| 1 MB | 3,580 μs | 1,829 μs | 11,740 μs | 878 μs |
RandomAccessBenchmarks covers seek-heavy and small-file-heavy patterns not exercised by the sequential benchmarks above:
| Scenario | RAM Disk | NVMe SSD | Ratio |
|---|---|---|---|
| Random 4 KB read (30 seeks over a 16 MB file) | 3.26 ms | 1.00 ms | 3.3× slower |
| 30× small-file (4 KB) create+write | 75.5 ms (2.52 ms/file) | 115.1 ms (3.84 ms/file) | 1.5× faster |
Random reads are slower on the RAM disk for the same reason sequential reads are (WinFsp kernel–userspace round-trip per I/O), while small-file writes are faster because RAM disk file creation skips physical block allocation and journaling entirely — at the cost of far higher managed memory allocation per operation (see Alloc Ratio in the raw BenchmarkDotNet output).
dotnet test tests/ManagedDrive.TestsTests cover FileNode (allocation unit alignment, index numbers, deep-copy cloning), FileNodeMap (CRUD, case-insensitive lookup, child pagination, rename, capacity tracking), MemoryFileSystem disk-cloning (copying contents between disks, target-too-small and read-only-target rejection, clone independence), DiskImageSerializer (save/load round-trips across every compression level, legacy version-1 images, concurrent map mutation during save), and the wildcard glob matcher used by directory listing. Mount/unmount integration tests require the WinFsp driver and must be run manually.
WinFsp must be installed. The benchmark project auto-selects the first free drive letter between D: and Z: — no manual configuration needed.
dotnet run --project benchmarks/ManagedDrive.Benchmarks -c ReleaseBenchmarkDotNet will prompt you to pick which benchmark class(es) to run (SequentialReadWriteBenchmarks, RandomAccessBenchmarks, ConcurrentAccessBenchmarks, or any combination). Results are written to BenchmarkDotNet.Artifacts/results/ in the working directory.
WinFsp mounts drives in the current user's session device namespace. If an installer is extracted to TEMP and then launched by a system-level process — such as the Windows Package Manager service used by winget — that process operates in the global device namespace and cannot resolve user-session drive letters. Attempting to execute such an installer from a path like Z:\Temp\WinGet\...\setup.exe fails with:
0x800704b3— The network path was not found
Known affected packages include WeChatWin_*.exe (WeChat installer), 7z*.exe (7-Zip installer), and Git-*.exe (Git installer). Not all winget packages are affected — many install without issue.
This is an architectural limitation of WinFsp user-mode file systems and cannot be worked around in user space.
Recommendation: If you encounter installation errors, you have two options:
- Restore TEMP to the Windows default using the toolbar button in ManagedDrive, then retry the installation.
- Download the installer directly from the software's official website and run it manually, bypassing winget entirely.
ManagedDrive will warn you when you attempt to set a RAM disk as TEMP. On every subsequent startup, if TEMP still points to a RAM disk, a warning is shown again — reset TEMP to the Windows default to stop the recurring prompt.
MIT
基于 .NET 10 和 WinFsp 构建的 Windows RAM 虚拟磁盘管理器。
创建、挂载并管理内存盘,它们在文件资源管理器中以普通驱动器号的形式呈现。
- 同时挂载多个 RAM 磁盘,每个磁盘拥有独立的驱动器号
- 可配置容量、卷标和只读标志
- 动态内存分配——磁盘容量为上限而非预分配;内存随文件写入而占用,随文件删除而释放
- 编辑已挂载磁盘——修改卷标、容量、自动挂载和镜像路径无需重挂即可实时生效;更改盘符或只读标志时自动重挂
- 可选持久化——将磁盘内容保存为
.mdr镜像文件,下次挂载时自动还原;保存镜像功能始终可用,未设置镜像路径时自动弹出选择对话框;保存期间磁盘卡片会显示"正在保存..."提示 - 导入已有
.mdr镜像——在磁盘列表右键选择导入磁盘...,选取已有镜像文件后直接挂载;容量和卷标从镜像中读取并只读展示(无需重新填写),若所选文件无效或已被其他已挂载磁盘占用,会提前弹出提示 - 可选自动保存——每 1-60 分钟(创建或编辑磁盘时可配置)自动将磁盘内容保存到镜像文件;开启自动保存时会立即触发一次保存,卸载磁盘或退出应用前也会再保存一次,避免在两次定时保存之间丢失数据。若自上次保存后内容未发生变化,无论是定时保存还是卸载/退出前的最后一次保存都会自动跳过,避免不必要的磁盘 IO。镜像文件只能通过文件选择对话框设置(不可手动输入),且不能位于内存盘上,也不能与其他磁盘共用同一个镜像文件。勾选只读,或清空已选择的镜像文件,都会取消勾选并禁用自动保存(勾选只读还会同时禁用镜像压缩)——只读磁盘的内容不会变化,因此无需保存或压缩,一个没有内容的只读空盘也没有意义,而没有镜像文件时自动保存也无处可保存。磁盘卡片会显示磁盘内容最近一次被修改的时间
- 可选镜像压缩——为保存的
.mdr镜像选择压缩级别(不压缩/快速/均衡/最高),在保存/加载速度与文件大小之间取舍;默认快速。选择均衡或最高时会显示内联警告,提示保存时间可能显著增加 - 应用启动时自动挂载已保存的磁盘配置
- 双击磁盘卡片可在资源管理器中打开对应盘符;右键菜单提供在资源管理器中打开和打开镜像文件目录(打开磁盘
.mdr镜像文件所在的文件夹;若磁盘未配置镜像文件则该菜单项置灰不可点) - 系统托盘图标,关闭窗口时最小化到托盘
- 托盘图标悬浮提示——鼠标悬停时显示所有已挂载磁盘及其实时使用率
- 高用量警告——磁盘使用率超过该磁盘自身配置的阈值时通过系统托盘发出通知,阈值在创建或编辑磁盘时设置(默认 90%,默认开启,也可针对单个磁盘完全关闭);使用率降至该阈值以下 5 个百分点时自动解除
- 可选最小化启动——直接启动到托盘,不显示主窗口;启动时会弹出一次性托盘气泡通知,避免用户误以为程序未启动成功
- 临时目录重定向——右键单击磁盘可将其设为 Windows TEMP/TMP 目录;通过工具栏、右键菜单或托盘菜单恢复系统默认值;卸载或重挂时自动恢复为系统默认临时目录;启动时若 TEMP/TMP 指向任一内存盘配置,均会显示警告——若该磁盘未设置自动挂载,还会自动将 TEMP 恢复为系统默认值
- 退出确认——只要还有磁盘处于挂载状态,无论是通过工具栏按钮还是托盘菜单退出,程序都会将主窗口带到前台并要求用户确认;若 TEMP/TMP 恰好指向某个已挂载的内存盘,确认提示中还会额外警告将重置 TEMP,用户确认后先重置再退出;若有磁盘配置了自动保存,退出时会在主窗口显示全屏保存遮罩与旋转动画,待后台镜像保存完成后再关闭——系统发送关闭信号时不触发确认流程
- NTFS 兼容卷标识——内存盘以 NTFS 文件系统类型上报,可作为需要 NTFS 卷的工具(如 WinGet、Windows Update 暂存、BITS 下载)的目标路径
- 磁盘格式化——右键单击磁盘并选择格式化可立即删除所有文件和文件夹(只读磁盘受保护);右键菜单按导航、配置、破坏性操作三个分组排列
- 克隆磁盘——右键单击磁盘并选择克隆磁盘...,可将其内容复制到另一个已挂载的可写磁盘(会覆盖该磁盘现有内容,操作前需二次确认),或导出为一个全新的
.mdr镜像文件(可选择压缩级别);若所选导出路径已被其他已挂载磁盘占用(包括源磁盘自身正在使用的镜像文件),选择后会立即提示并拒绝 - 快照/版本历史——创建或编辑磁盘时,可选设置保留的快照数量上限和/或总大小上限;只要一次保存产生了内容变化,就会在主镜像旁额外写入一个带时间戳的快照(
{名称}.yyyyMMdd-HHmmss.mdr),超出上限后会自动清理最旧的快照。同一磁盘的多个快照之间,相同的文件内容只会存储一份(基于 SHA-256 内容寻址去重),因此保留大量快照所占用的磁盘空间远小于各快照逻辑大小之和。右键单击磁盘并选择还原快照...,即可从列表(含时间戳与大小)中选取某个历史时间点,用其内容替换磁盘当前内容(操作前需二次确认);还原后的内容会在下一次保存/自动保存时才写入镜像文件,而非立即写入。删除磁盘的镜像文件时,其所有快照及不再被引用的去重内容也会一并删除 - 系统托盘菜单——在显示、新建磁盘、退出之外,新增重置临时文件夹(静默执行,结果通过气泡通知反馈)和设置快捷入口
- 主窗口启动时居中显示于主屏幕并置于前台
- 双语界面——中文与英文,根据系统语言自动切换,也可在设置中手动更改
- 浅色/深色主题——默认跟随 Windows 系统主题,也可在设置中手动切换(跟随系统/浅色/深色),切换即时生效,无需重启
- 一目了然的磁盘卡片——驱动器字母徽章上会叠加只读、当前临时目录、是否绑定镜像文件等状态角标(鼠标悬停镜像图标可查看镜像路径);用量进度条旁显示百分比,使用率超过该磁盘配置的高用量阈值(若已启用)时进度条及可用空间文字会变为警示色;只读磁盘的用量区域会替换为单行文字,显示其绑定的镜像文件路径,而非无意义的容量数字
- 关于对话框——可从溢出菜单打开,显示应用版本及 GitHub 仓库链接
从 Releases 页面下载最新的绿色版 ZIP(ManagedDrive-vX.Y.Z-win-x64-portable.zip)。解压到任意目录后直接运行 ManagedDrive.exe 即可。ManagedDrive.exe 是单文件可执行程序——ZIP 中还附带一个体积很小的 winfsp-msil.dll(WinFsp 托管互操作程序集,无法打包进单文件中),需与 exe 保持在同一目录下。唯一会写入注册表的操作是可选的"开机自启"设置,除此之外不会写入注册表。仍需提前单独安装 WinFsp(见下方环境要求)。
| 要求 | 说明 |
|---|---|
| Windows 10 / 11(64 位) | 暂未测试 ARM64 |
| WinFsp 2.2.26183(2026 Beta2) | 必须安装此版本才能运行 ManagedDrive。请直接下载安装包:winfsp-2.2.26183.msi——不要使用 winget install WinFsp.WinFsp 安装,因为该 winget 包更新不及时,落后于最新发布版本。托管程序集 winfsp-msil.dll 将安装至 C:\Program Files (x86)\WinFsp\bin\,项目会自动引用。 |
| .NET 10 SDK | 编译所需。 |
# 1. 下载并安装 WinFsp 2.2.26183(2026 Beta2)
# https://github.com/winfsp/winfsp/releases/download/v2.2B2/winfsp-2.2.26183.msi
# 2. 克隆仓库
git clone https://github.com/coldhighsun/ManagedDrive
cd ManagedDrive
# 3. 编译
dotnet build
# 4. 运行
dotnet run --project src/ManagedDrive.App -c Release或者在 Visual Studio 2022+ 中打开 ManagedDrive.slnx 并按 F5。
ManagedDrive/
├── src/
│ ├── ManagedDrive.Core/ # 内存文件系统引擎(WinFsp)
│ │ ├── DiskOptions.cs # 不可变挂载配置记录
│ │ ├── FileNode.cs # 单个文件或目录节点
│ │ ├── FileNodeMap.cs # 线程安全的路径→节点字典
│ │ ├── MemoryFileSystem.cs # FileSystemBase 实现(所有 WinFsp 回调)
│ │ ├── RamDisk.cs # 挂载/卸载生命周期封装
│ │ ├── MountManager.cs # 多磁盘管理器
│ │ ├── DiskImageSerializer.cs # 二进制持久化(.mdr 格式)
│ │ ├── SnapshotManager.cs # 带时间戳的快照命名、列表、清理与垃圾回收
│ │ └── SnapshotStore.cs # 快照索引格式 + 内容寻址块存储
│ │
│ └── ManagedDrive.App/ # WPF 桌面应用程序
│ ├── Localization/ # ResourceDictionary 字符串(en-US、zh-CN)
│ ├── Themes/ # AppTheme.xaml 样式 + 浅色/深色配色字典、ThemeManager
│ ├── Infrastructure/ # RelayCommand
│ ├── Models/ # AppConfiguration、DiskProfile
│ ├── Services/ # SettingsStore、StartupManager、TempDirResetService
│ ├── ViewModels/ # MainViewModel、DiskViewModel
│ ├── Views/ # CreateDiskDialog、CloneDiskDialog、RestoreSnapshotDialog、SettingsDialog、ConfirmDialog、AboutDialog、TrayTooltipView
│ ├── MainWindow.xaml(.cs) # 主窗口
│ └── App.xaml(.cs) # 启动、托盘图标、自动挂载
│
├── tests/
│ └── ManagedDrive.Tests/ # xUnit v3 单元测试(仅纯托管代码)
│ ├── FileNodeTests.cs
│ ├── FileNodeMapTests.cs
│ ├── MemoryFileSystemCloneTests.cs
│ ├── DiskImageSerializerTests.cs
│ └── WildcardMatchTests.cs
│
└── benchmarks/
└── ManagedDrive.Benchmarks/ # BenchmarkDotNet 吞吐量/延迟基准测试
├── Program.cs
├── DriveLetterHelper.cs # 为内存盘自动选择一个空闲盘符(D:-Z:)
├── SequentialReadWriteBenchmarks.cs # 4 KB / 1 MB 顺序读写
├── RandomAccessBenchmarks.cs # 随机寻址读取 + 小文件高频写入
└── ConcurrentAccessBenchmarks.cs # 多线程并发读写互不重叠的文件,测量 FileNodeMap 锁竞争
ManagedDrive 使用 WinFsp(Windows 文件系统代理)将内存目录树呈现为真实的 Windows 卷。WinFsp 附带一个已签名的内核驱动程序作为桥接层;所有文件 I/O 均转发至 MemoryFileSystem,后者将数据存储在 .NET 字节数组中。
核心类:
FileNode— 持有Fsp.Interop.FileInfo元数据、byte[]数据缓冲区、缓存的叶子节点名称及安全描述符。FileNodeMap— 不区分大小写的SortedDictionary<string, FileNode>,将完整路径映射到节点,通过有界前缀遍历支持分页子节点枚举,并通过增量维护的计数器追踪已分配字节总量(O(1) 读取,无需全量扫描)。通过 C# 13Lock类型保证线程安全。MemoryFileSystem : FileSystemBase— 覆写全部 21 个所需的 WinFsp 回调(Create、Open、Read、Write、Rename、CanDelete、ReadDirectoryEntry等),并强制执行可配置的容量上限,超出时返回STATUS_DISK_FULL;内存不预分配——每个FileNode仅保留实际写入的字节数。RamDisk— 组合MemoryFileSystem与FileSystemHost。静态工厂方法Create()挂载卷,并轮询直至驱动器号在系统中可见(最长 2.5 秒),随后向资源管理器广播SHCNE_DRIVEADD。Dispose()执行卸载。配置了自动保存间隔时,后台计时器会立即保存一次镜像,随后按间隔重复保存,若自上次保存后内容未变化则跳过该次保存;Dispose()也会执行一次收尾保存,同样在内容未变化时跳过,确保卸载、重新挂载或退出应用时既不遗漏最新的改动,也不产生多余的写入。MountManager— 线程安全的活动RamDisk实例注册表,提供DiskMounted/DiskUnmounted事件。DiskImageSerializer— 读写.mdr文件(保存完整文件系统状态,包含元数据、ACL 和文件数据),可选按用户指定的级别进行 gzip 压缩。SnapshotManager/SnapshotStore— 在配置了快照上限的情况下,每次保存后都会在主.mdr镜像旁写入一份带时间戳的只读快照副本,并支持列出、清理旧快照及将某个快照还原到实时磁盘。文件内容按 SHA-256 哈希去重存储于共享的块存储中,因此对一个大部分内容未变化的磁盘做快照,额外占用的空间非常小。
小端序二进制格式:
| 字段 | 类型 | 说明 |
|---|---|---|
| 魔数 | byte[4] |
MDRD |
| 版本 | int32 |
当前为 2 |
| 压缩级别 | byte |
ImageCompressionLevel 取值(0=不压缩/1=快速/2=均衡/3=最高);非 0 时,后续内容整体经 gzip 压缩 |
| 容量 | uint64 |
配置的容量(字节) |
| 卷标 | string |
长度前缀 UTF-8 |
| 节点数 | int32 |
后续节点数量 |
| 节点条目 | — | 路径、元数据(10 个字段)、安全描述符、文件数据 |
版本 1 的镜像(不含压缩级别字段,始终不压缩)仍可正常读取,保持向后兼容。
快照采用与 .mdr 镜像完全独立的格式。对于主镜像 disk.mdr,其快照命名为同目录下的 disk.yyyyMMdd-HHmmss.mdr,每个都是一个小型二进制索引文件(魔数 MDRS),列出所有文件/目录的元数据,非空文件还会记录一个 SHA-256 哈希。实际文件内容存储在共享的内容寻址块存储 disk.snapblobs/ 中(按哈希前 2 位十六进制分片到子文件夹),按磁盘配置的压缩级别逐块 gzip 压缩——多个快照间相同的内容只保存一份。清理旧快照时,还会一并垃圾回收不再被任何剩余快照引用的块。
- 配置以 JSON 格式存储于
%APPDATA%\ManagedDrive\settings.json,包括每个磁盘各自的高用量告警阈值(或已禁用状态)。 - 开机自启通过
HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run注册表项实现(无需提升权限)。 - 版本号由 MinVer 从 git 标签派生(
v前缀,例如v0.1.0)。
使用 BenchmarkDotNet 测量读写、随机访问及小文件吞吐量,测试环境:
| CPU | Intel Core i9-13980HX,24C/32T,基础频率 2.2 GHz |
| 内存 | 64 GB |
| 磁盘 | KIOXIA KXG8AZNV1T02 NVMe SSD(1 TB) |
| 系统 | Windows 11 Pro(Build 26200) |
| 运行时 | .NET 10.0.9 · BenchmarkDotNet 0.15.8 |
SequentialReadWriteBenchmarks 通过 FileStream 在 4 KB 和 1 MB 大小下对单个文件进行创建或读取操作。写入使用 FileOptions.WriteThrough(禁用操作系统写回缓存),读取使用 FileOptions.SequentialScan。
| 文件大小 | 操作 | 内存盘 | NVMe SSD | 倍率 |
|---|---|---|---|---|
| 4 KB | 写入 | 1.5 MB/s | 0.8 MB/s | 快 1.9× |
| 4 KB | 读取 | 2.2 MB/s | 4.5 MB/s | 慢 0.5× |
| 1 MB | 写入 | 279 MB/s | 85 MB/s | 快 3.3× |
| 1 MB | 读取 | 547 MB/s | 1,139 MB/s | 慢 0.5× |
为何内存盘读取反而更慢?
物理磁盘的读取速度之所以快,是因为操作系统页面缓存将最近写入的文件保留在 DRAM 中。内存盘的读取则需要经过 WinFsp 的内核–用户态桥接,引入了额外的 IPC 开销,比直接走页面缓存路径更慢。在数据写入一次、多次读取且页面缓存已失效的场景下(如构建产物、临时文件),内存盘的读取性能同样会超越 SSD。4 KB 说明: 小文件结果主要受文件打开/关闭的系统调用开销主导,不反映实际传输速率。
原始延迟(均值,[SimpleJob(warmupCount: 2, iterationCount: 3)]):
| 文件大小 | 内存盘写入 | 内存盘读取 | NVMe 写入 | NVMe 读取 |
|---|---|---|---|---|
| 4 KB | 2,582 μs | 1,785 μs | 4,988 μs | 871 μs |
| 1 MB | 3,580 μs | 1,829 μs | 11,740 μs | 878 μs |
RandomAccessBenchmarks 补充了顺序读写未覆盖的寻址密集与小文件密集场景:
| 场景 | 内存盘 | NVMe SSD | 倍率 |
|---|---|---|---|
| 随机 4 KB 读取(对 16 MB 文件随机寻址 30 次) | 3.26 ms | 1.00 ms | 慢 3.3× |
| 30 次小文件(4 KB)创建+写入 | 75.5 ms(2.52 ms/文件) | 115.1 ms(3.84 ms/文件) | 快 1.5× |
随机读取在内存盘上更慢,原因与顺序读取相同(每次 I/O 都要经过 WinFsp 内核–用户态往返);而小文件写入更快,是因为内存盘创建文件完全跳过了物理块分配和日志记录——代价是每次操作的托管内存分配量显著更高(详见原始 BenchmarkDotNet 输出中的 Alloc Ratio)。
dotnet test tests/ManagedDrive.Tests测试覆盖 FileNode(分配单元对齐、索引编号、深拷贝克隆)、FileNodeMap(增删改查、大小写无关查找、子节点分页、重命名、容量追踪)、MemoryFileSystem 的磁盘克隆逻辑(跨磁盘复制内容、目标容量不足与目标只读时的拒绝、克隆节点的独立性)、DiskImageSerializer(各压缩级别的保存/加载往返、旧版本 1 镜像、保存期间并发修改磁盘节点)以及目录枚举所用的通配符匹配逻辑。挂载/卸载集成测试需要 WinFsp 驱动程序,须手动运行。
须已安装 WinFsp。基准测试项目会自动选择 D: 到 Z: 之间第一个空闲盘符,无需手动配置。
dotnet run --project benchmarks/ManagedDrive.Benchmarks -c ReleaseBenchmarkDotNet 会提示你选择要运行的基准测试类(SequentialReadWriteBenchmarks、RandomAccessBenchmarks、ConcurrentAccessBenchmarks,或任意组合)。结果将写入工作目录下的 BenchmarkDotNet.Artifacts/results/。
WinFsp 将驱动器挂载在当前用户的会话设备命名空间中。若安装包被解压到 TEMP 后由系统级进程启动(例如 winget 所使用的 Windows 软件包管理器服务),该进程运行于全局设备命名空间,无法解析用户会话级别的驱动器号。尝试从 Z:\Temp\WinGet\...\setup.exe 之类的路径执行安装程序时,会报错:
0x800704b3— 网络路径键入不正确 / The network path was not found
已知受影响的安装包包括 WeChatWin_*.exe(微信安装程序)、7z*.exe(7-Zip 安装程序)和 Git-*.exe(Git 安装程序)。并非所有 winget 包都受影响——大多数包可正常安装。
这是 WinFsp 用户态文件系统的架构性限制,无法在用户空间层面绕过。
建议: 如遇安装报错,可采用以下任一方式解决:
- 通过 ManagedDrive 工具栏的按钮将 TEMP 恢复为 Windows 默认值,再重试安装。
- 直接前往软件官网下载安装包手动安装,绕过 winget。
每次将内存盘设置为临时目录时,ManagedDrive 均会弹出警告提示。此后每次启动,只要 TEMP 仍指向内存盘,警告便会再次弹出——将 TEMP 恢复为 Windows 默认值后即可停止重复提示。
MIT