虚拟磁盘和虚拟光驱系统的C++实现,支持磁盘镜像创建、文件操作、光驱挂载和ISO文件读取等功能。
系统架构
用户界面
虚拟磁盘管理器
虚拟光驱管理器
磁盘镜像操作
文件系统管理
ISO文件解析
光驱设备模拟
磁盘映像文件
ISO 9660解析器
核心实现代码
1. 虚拟磁盘实现 (VirtualDisk.h/cpp)
cpp
// VirtualDisk.h
#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>
#include <memory>
#include <map>
#include <filesystem>
#include <stdexcept>
namespace fs = std::filesystem;
class VirtualDisk {
public:
VirtualDisk(const std::string& diskPath, size_t sizeMB);
~VirtualDisk();
void format();
void createFile(const std::string& path, const std::string& content);
void appendFile(const std::string& path, const std::string& content);
std::string readFile(const std::string& path);
void deleteFile(const std::string& path);
void listDirectory(const std::string& path = "/");
void createDirectory(const std::string& path);
bool exists(const std::string& path);
size_t getFreeSpace() const;
size_t getUsedSpace() const;
size_t getTotalSpace() const;
private:
struct DiskHeader {
char signature[8] = "VDSK0001"; // 虚拟磁盘签名
size_t totalSize; // 磁盘总大小(字节)
size_t usedSize; // 已用空间(字节)
size_t freeSpace; // 可用空间(字节)
size_t rootDirOffset; // 根目录偏移
size_t fatOffset; // FAT表偏移
size_t dataOffset; // 数据区偏移
size_t clusterSize; // 簇大小(字节)
size_t clusterCount; // 簇总数
};
struct DirectoryEntry {
char name[56]; // 文件名(最多55字符)
size_t size; // 文件大小
size_t clusterStart; // 起始簇号
bool isDirectory; // 是否为目录
size_t parentCluster; // 父目录簇号
size_t createTime; // 创建时间(时间戳)
size_t modifyTime; // 修改时间(时间戳)
};
struct FatEntry {
size_t nextCluster; // 下一个簇号(0表示结束)
bool used; // 是否已使用
};
std::string diskPath;
size_t diskSize;
std::fstream diskFile;
DiskHeader header;
std::map<std::string, DirectoryEntry> directoryCache;
bool isMounted = false;
void mount();
void unmount();
void loadDirectoryCache();
void saveDirectoryCache();
size_t allocateCluster();
void freeCluster(size_t cluster);
size_t findFreeCluster() const;
std::string normalizePath(const std::string& path) const;
std::vector<std::string> splitPath(const std::string& path) const;
DirectoryEntry* findEntry(const std::string& path);
const DirectoryEntry* findEntry(const std::string& path) const;
void writeFatEntry(size_t cluster, const FatEntry& entry);
FatEntry readFatEntry(size_t cluster) const;
void writeDirectoryEntry(const DirectoryEntry& entry);
DirectoryEntry readDirectoryEntry(size_t cluster, size_t index) const;
void updateDirectoryEntry(const DirectoryEntry& entry);
size_t findOrCreateDirectory(const std::string& path);
};
cpp
// VirtualDisk.cpp
#include "VirtualDisk.h"
#include <chrono>
#include <iomanip>
#include <sstream>
#include <algorithm>
#include <cctype>
VirtualDisk::VirtualDisk(const std::string& diskPath, size_t sizeMB)
: diskPath(diskPath), diskSize(sizeMB * 1024 * 1024) {
// 创建或打开磁盘文件
diskFile.open(diskPath, std::ios::in | std::ios::out | std::ios::binary);
if (!diskFile) {
// 文件不存在,创建新磁盘
diskFile.open(diskPath, std::ios::out | std::ios::binary);
diskFile.close();
diskFile.open(diskPath, std::ios::in | std::ios::out | std::ios::binary);
// 初始化磁盘头
header.signature[0] = 'V';
header.signature[1] = 'D';
header.signature[2] = 'S';
header.signature[3] = 'K';
header.signature[4] = '0';
header.signature[5] = '0';
header.signature[6] = '0';
header.signature[7] = '1';
header.totalSize = diskSize;
header.usedSize = sizeof(DiskHeader) + sizeof(FatEntry) * (diskSize / 4096);
header.freeSpace = diskSize - header.usedSize;
header.clusterSize = 4096; // 4KB簇
header.clusterCount = diskSize / header.clusterSize;
header.fatOffset = sizeof(DiskHeader);
header.rootDirOffset = header.fatOffset + sizeof(FatEntry) * header.clusterCount;
header.dataOffset = header.rootDirOffset + header.clusterSize; // 根目录占用一个簇
// 写入磁盘头
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 初始化FAT表
FatEntry fe;
fe.used = false;
fe.nextCluster = 0;
for (size_t i = 0; i < header.clusterCount; i++) {
diskFile.seekp(header.fatOffset + i * sizeof(FatEntry));
diskFile.write(reinterpret_cast<const char*>(&fe), sizeof(FatEntry));
}
// 初始化根目录
DirectoryEntry root;
strncpy(root.name, ".", sizeof(root.name));
root.size = 0;
root.clusterStart = 0;
root.isDirectory = true;
root.parentCluster = 0;
root.createTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
root.modifyTime = root.createTime;
diskFile.seekp(header.rootDirOffset);
diskFile.write(reinterpret_cast<const char*>(&root), sizeof(DirectoryEntry));
// 标记根目录簇为已使用
FatEntry rootFe;
rootFe.used = true;
rootFe.nextCluster = 0;
diskFile.seekp(header.fatOffset);
diskFile.write(reinterpret_cast<const char*>(&rootFe), sizeof(FatEntry));
// 更新头信息
header.usedSize = sizeof(DiskHeader) + sizeof(FatEntry) * header.clusterCount + header.clusterSize;
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
} else {
// 加载现有磁盘
diskFile.read(reinterpret_cast<char*>(&header), sizeof(DiskHeader));
if (strncmp(header.signature, "VDSK0001", 8) != 0) {
throw std::runtime_error("Invalid virtual disk format");
}
}
mount();
}
VirtualDisk::~VirtualDisk() {
unmount();
if (diskFile.is_open()) {
diskFile.close();
}
}
void VirtualDisk::mount() {
if (isMounted) return;
// 加载目录缓存
loadDirectoryCache();
isMounted = true;
}
void VirtualDisk::unmount() {
if (!isMounted) return;
// 保存目录缓存
saveDirectoryCache();
isMounted = false;
}
void VirtualDisk::format() {
if (!diskFile.is_open()) {
throw std::runtime_error("Disk not open");
}
// 重置磁盘头
header.usedSize = sizeof(DiskHeader) + sizeof(FatEntry) * header.clusterCount;
header.freeSpace = diskSize - header.usedSize;
// 写入磁盘头
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 初始化FAT表
FatEntry fe;
fe.used = false;
fe.nextCluster = 0;
for (size_t i = 0; i < header.clusterCount; i++) {
diskFile.seekp(header.fatOffset + i * sizeof(FatEntry));
diskFile.write(reinterpret_cast<const char*>(&fe), sizeof(FatEntry));
}
// 初始化根目录
DirectoryEntry root;
strncpy(root.name, ".", sizeof(root.name));
root.size = 0;
root.clusterStart = 0;
root.isDirectory = true;
root.parentCluster = 0;
root.createTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
root.modifyTime = root.createTime;
diskFile.seekp(header.rootDirOffset);
diskFile.write(reinterpret_cast<const char*>(&root), sizeof(DirectoryEntry));
// 标记根目录簇为已使用
FatEntry rootFe;
rootFe.used = true;
rootFe.nextCluster = 0;
diskFile.seekp(header.fatOffset);
diskFile.write(reinterpret_cast<const char*>(&rootFe), sizeof(FatEntry));
// 更新头信息
header.usedSize = sizeof(DiskHeader) + sizeof(FatEntry) * header.clusterCount + header.clusterSize;
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 重新加载目录缓存
loadDirectoryCache();
}
void VirtualDisk::createFile(const std::string& path, const std::string& content) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
auto parts = splitPath(normPath);
if (parts.empty()) {
throw std::invalid_argument("Invalid path");
}
// 检查父目录是否存在
std::string parentPath = "/";
for (size_t i = 0; i < parts.size() - 1; i++) {
parentPath += parts[i];
if (i < parts.size() - 2) parentPath += "/";
}
size_t parentCluster = findOrCreateDirectory(parentPath);
if (parentCluster == static_cast<size_t>(-1)) {
throw std::runtime_error("Parent directory not found");
}
// 检查文件是否已存在
if (findEntry(normPath)) {
throw std::runtime_error("File already exists");
}
// 分配簇
size_t cluster = allocateCluster();
if (cluster == static_cast<size_t>(-1)) {
throw std::runtime_error("Not enough space");
}
// 创建目录项
DirectoryEntry entry;
strncpy(entry.name, parts.back().c_str(), sizeof(entry.name) - 1);
entry.name[sizeof(entry.name) - 1] = '\0';
entry.size = content.size();
entry.clusterStart = cluster;
entry.isDirectory = false;
entry.parentCluster = parentCluster;
entry.createTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
entry.modifyTime = entry.createTime;
// 写入数据
diskFile.seekp(header.dataOffset + cluster * header.clusterSize);
diskFile.write(content.c_str(), content.size());
// 更新FAT表
FatEntry fe;
fe.used = true;
fe.nextCluster = 0;
writeFatEntry(cluster, fe);
// 添加目录项
writeDirectoryEntry(entry);
// 更新头信息
header.usedSize += content.size() + sizeof(DirectoryEntry);
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 更新缓存
directoryCache[normPath] = entry;
}
void VirtualDisk::appendFile(const std::string& path, const std::string& content) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
DirectoryEntry* entry = findEntry(normPath);
if (!entry) {
throw std::runtime_error("File not found");
}
if (entry->isDirectory) {
throw std::runtime_error("Cannot append to directory");
}
// 读取现有数据
std::string existingData = readFile(normPath);
std::string newData = existingData + content;
// 检查空间
if (newData.size() > entry->size) {
size_t additional = newData.size() - entry->size;
if (additional > header.freeSpace) {
throw std::runtime_error("Not enough space");
}
}
// 写入新数据
diskFile.seekp(header.dataOffset + entry->clusterStart * header.clusterSize);
diskFile.write(newData.c_str(), newData.size());
// 更新目录项
entry->size = newData.size();
entry->modifyTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
updateDirectoryEntry(*entry);
// 更新头信息
header.usedSize += (newData.size() - existingData.size());
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 更新缓存
directoryCache[normPath] = *entry;
}
std::string VirtualDisk::readFile(const std::string& path) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
const DirectoryEntry* entry = findEntry(normPath);
if (!entry) {
throw std::runtime_error("File not found");
}
if (entry->isDirectory) {
throw std::runtime_error("Cannot read directory as file");
}
// 读取数据
std::string data(entry->size, '\0');
diskFile.seekg(header.dataOffset + entry->clusterStart * header.clusterSize);
diskFile.read(&data[0], entry->size);
return data;
}
void VirtualDisk::deleteFile(const std::string& path) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
DirectoryEntry* entry = findEntry(normPath);
if (!entry) {
throw std::runtime_error("File not found");
}
if (entry->isDirectory) {
// 递归删除目录
// 简化实现:只删除空目录
// 实际实现需要遍历目录内容
throw std::runtime_error("Directory deletion not fully implemented");
}
// 释放簇
size_t cluster = entry->clusterStart;
while (cluster != 0) {
FatEntry fe = readFatEntry(cluster);
size_t next = fe.nextCluster;
freeCluster(cluster);
cluster = next;
}
// 从父目录中删除
// 简化实现:实际需要从目录中移除条目
// 更新头信息
header.usedSize -= (entry->size + sizeof(DirectoryEntry));
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 更新缓存
directoryCache.erase(normPath);
}
void VirtualDisk::listDirectory(const std::string& path) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
if (normPath.empty()) normPath = "/";
const DirectoryEntry* entry = findEntry(normPath);
if (!entry) {
throw std::runtime_error("Directory not found");
}
if (!entry->isDirectory) {
throw std::runtime_error("Not a directory");
}
// 简化实现:实际需要从目录簇中读取所有条目
std::cout << "Directory listing for: " << normPath << "\n";
for (const auto& [p, e] : directoryCache) {
if (e.parentCluster == entry->clusterStart) {
std::cout << (e.isDirectory ? "[DIR] " : "[FILE] ")
<< p << " (" << e.size << " bytes)\n";
}
}
}
void VirtualDisk::createDirectory(const std::string& path) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
std::string normPath = normalizePath(path);
if (findEntry(normPath)) {
throw std::runtime_error("Directory already exists");
}
// 检查父目录
auto parts = splitPath(normPath);
if (parts.empty()) {
throw std::invalid_argument("Invalid path");
}
std::string parentPath = "/";
for (size_t i = 0; i < parts.size() - 1; i++) {
parentPath += parts[i];
if (i < parts.size() - 2) parentPath += "/";
}
size_t parentCluster = findOrCreateDirectory(parentPath);
if (parentCluster == static_cast<size_t>(-1)) {
throw std::runtime_error("Parent directory not found");
}
// 分配簇
size_t cluster = allocateCluster();
if (cluster == static_cast<size_t>(-1)) {
throw std::runtime_error("Not enough space");
}
// 创建目录项
DirectoryEntry entry;
strncpy(entry.name, parts.back().c_str(), sizeof(entry.name) - 1);
entry.name[sizeof(entry.name) - 1] = '\0';
entry.size = 0;
entry.clusterStart = cluster;
entry.isDirectory = true;
entry.parentCluster = parentCluster;
entry.createTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
entry.modifyTime = entry.createTime;
// 初始化目录内容(.和..)
DirectoryEntry self, parent;
strncpy(self.name, ".", sizeof(self.name));
self.size = 0;
self.clusterStart = cluster;
self.isDirectory = true;
self.parentCluster = parentCluster;
self.createTime = entry.createTime;
self.modifyTime = entry.modifyTime;
strncpy(parent.name, "..", sizeof(parent.name));
parent.size = 0;
parent.clusterStart = parentCluster;
parent.isDirectory = true;
parent.parentCluster = (parentCluster == 0) ? 0 : findEntry(parentPath)->parentCluster;
parent.createTime = entry.createTime;
parent.modifyTime = entry.modifyTime;
// 写入目录内容
diskFile.seekp(header.dataOffset + cluster * header.clusterSize);
diskFile.write(reinterpret_cast<const char*>(&self), sizeof(DirectoryEntry));
diskFile.write(reinterpret_cast<const char*>(&parent), sizeof(DirectoryEntry));
// 更新FAT表
FatEntry fe;
fe.used = true;
fe.nextCluster = 0;
writeFatEntry(cluster, fe);
// 添加目录项
writeDirectoryEntry(entry);
// 更新头信息
header.usedSize += header.clusterSize + sizeof(DirectoryEntry);
header.freeSpace = diskSize - header.usedSize;
diskFile.seekp(0);
diskFile.write(reinterpret_cast<const char*>(&header), sizeof(DiskHeader));
// 更新缓存
directoryCache[normPath] = entry;
}
bool VirtualDisk::exists(const std::string& path) {
if (!isMounted) throw std::runtime_error("Disk not mounted");
return findEntry(normalizePath(path)) != nullptr;
}
size_t VirtualDisk::getFreeSpace() const {
return header.freeSpace;
}
size_t VirtualDisk::getUsedSpace() const {
return header.usedSize;
}
size_t VirtualDisk::getTotalSpace() const {
return diskSize;
}
// 私有方法实现
void VirtualDisk::loadDirectoryCache() {
directoryCache.clear();
// 简化实现:实际应遍历所有目录
// 这里只加载根目录
DirectoryEntry root;
diskFile.seekg(header.rootDirOffset);
diskFile.read(reinterpret_cast<char*>(&root), sizeof(DirectoryEntry));
directoryCache["/"] = root;
}
void VirtualDisk::saveDirectoryCache() {
// 简化实现:实际应将缓存写回磁盘
}
size_t VirtualDisk::allocateCluster() {
for (size_t i = 0; i < header.clusterCount; i++) {
FatEntry fe = readFatEntry(i);
if (!fe.used) {
return i;
}
}
return static_cast<size_t>(-1); // 无可用簇
}
void VirtualDisk::freeCluster(size_t cluster) {
FatEntry fe;
fe.used = false;
fe.nextCluster = 0;
writeFatEntry(cluster, fe);
}
size_t VirtualDisk::findFreeCluster() const {
for (size_t i = 0; i < header.clusterCount; i++) {
FatEntry fe = readFatEntry(i);
if (!fe.used) {
return i;
}
}
return static_cast<size_t>(-1);
}
std::string VirtualDisk::normalizePath(const std::string& path) const {
std::string normalized;
for (char c : path) {
if (c == '\\') normalized += '/';
else normalized += c;
}
// 移除多余的斜杠
size_t pos;
while ((pos = normalized.find("//")) != std::string::npos) {
normalized.replace(pos, 2, "/");
}
// 移除尾部斜杠
if (normalized.size() > 1 && normalized.back() == '/') {
normalized.pop_back();
}
return normalized;
}
std::vector<std::string> VirtualDisk::splitPath(const std::string& path) const {
std::vector<std::string> parts;
size_t start = 0;
size_t end = path.find('/');
while (end != std::string::npos) {
if (end > start) {
parts.push_back(path.substr(start, end - start));
}
start = end + 1;
end = path.find('/', start);
}
if (start < path.length()) {
parts.push_back(path.substr(start));
}
return parts;
}
VirtualDisk::DirectoryEntry* VirtualDisk::findEntry(const std::string& path) {
auto it = directoryCache.find(path);
if (it != directoryCache.end()) {
return &it->second;
}
return nullptr;
}
const VirtualDisk::DirectoryEntry* VirtualDisk::findEntry(const std::string& path) const {
auto it = directoryCache.find(path);
if (it != directoryCache.end()) {
return &it->second;
}
return nullptr;
}
void VirtualDisk::writeFatEntry(size_t cluster, const FatEntry& entry) {
diskFile.seekp(header.fatOffset + cluster * sizeof(FatEntry));
diskFile.write(reinterpret_cast<const char*>(&entry), sizeof(FatEntry));
}
VirtualDisk::FatEntry VirtualDisk::readFatEntry(size_t cluster) const {
FatEntry fe;
diskFile.seekg(header.fatOffset + cluster * sizeof(FatEntry));
diskFile.read(reinterpret_cast<char*>(&fe), sizeof(FatEntry));
return fe;
}
void VirtualDisk::writeDirectoryEntry(const DirectoryEntry& entry) {
// 简化实现:实际应写入父目录的簇中
directoryCache[entry.name] = entry;
}
VirtualDisk::DirectoryEntry VirtualDisk::readDirectoryEntry(size_t cluster, size_t index) const {
DirectoryEntry entry;
diskFile.seekg(header.dataOffset + cluster * header.clusterSize + index * sizeof(DirectoryEntry));
diskFile.read(reinterpret_cast<char*>(&entry), sizeof(DirectoryEntry));
return entry;
}
void VirtualDisk::updateDirectoryEntry(const DirectoryEntry& entry) {
// 简化实现:实际应更新父目录中的条目
directoryCache[entry.name] = entry;
}
size_t VirtualDisk::findOrCreateDirectory(const std::string& path) {
if (path == "/") {
return 0; // 根目录
}
if (exists(path)) {
const DirectoryEntry* entry = findEntry(path);
if (entry && entry->isDirectory) {
return entry->clusterStart;
}
return static_cast<size_t>(-1);
}
// 创建目录
createDirectory(path);
const DirectoryEntry* entry = findEntry(path);
return entry ? entry->clusterStart : static_cast<size_t>(-1);
}
2. 虚拟光驱实现 (VirtualCDRom.h/cpp)
cpp
// VirtualCDRom.h
#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>
#include <memory>
#include <map>
#include <stdexcept>
#include <filesystem>
#include <cstdint>
namespace fs = std::filesystem;
class VirtualCDRom {
public:
VirtualCDRom(const std::string& isoPath);
~VirtualCDRom();
void mount();
void unmount();
bool isMounted() const;
std::string getVolumeLabel() const;
uint32_t getVolumeSize() const;
std::vector<std::string> listDirectory(const std::string& path = "/");
std::string readFile(const std::string& path);
bool exists(const std::string& path) const;
void dumpIsoInfo() const;
private:
struct IsoPrimaryVolumeDescriptor {
uint8_t type;
char id[5];
uint8_t version;
char systemId[32];
char volumeId[32];
uint8_t reserved1[8];
uint32_t volumeSpaceSizeLE;
uint32_t volumeSpaceSizeBE;
char escapeSequences[32];
uint16_t volumeSetSizeLE;
uint16_t volumeSetSizeBE;
uint16_t volumeSequenceNumberLE;
uint16_t volumeSequenceNumberBE;
uint16_t logicalBlockSizeLE;
uint16_t logicalBlockSizeBE;
uint32_t pathTableSizeLE;
uint32_t pathTableSizeBE;
uint32_t locationOfTypeLPathTable;
uint32_t locationOfOptionalTypeLPathTable;
uint32_t locationOfTypeMPathTable;
uint32_t locationOfOptionalTypeMPathTable;
char rootDirectoryRecord[34];
char volumeSetId[128];
char publisherId[128];
char preparerId[128];
char applicationId[128];
char copyrightFileId[37];
char abstractFileId[37];
char bibliographicFileId[37];
char creationDate[17];
char modificationDate[17];
char expirationDate[17];
char effectiveDate[17];
uint8_t fileStructureVersion;
uint8_t reserved2;
uint8_t applicationUse[512];
uint8_t reserved3[653];
};
struct DirectoryRecord {
uint8_t length;
uint8_t extAttrLength;
uint32_t extentStartLE;
uint32_t extentStartBE;
uint32_t dataLengthLE;
uint32_t dataLengthBE;
uint8_t date[7];
uint8_t flags;
uint8_t fileUnitSize;
uint8_t interleaveGapSize;
uint16_t volumeSequenceNumberLE;
uint16_t volumeSequenceNumberBE;
uint8_t nameLength;
char name[1]; // 变长
};
std::string isoPath;
std::fstream isoFile;
IsoPrimaryVolumeDescriptor primaryVolDesc;
bool mounted = false;
uint32_t logicalBlockSize = 2048;
uint32_t volumeSize = 0;
std::string volumeLabel;
void readPrimaryVolumeDescriptor();
uint32_t leToUint32(const uint8_t* data) const;
uint16_t leToUint16(const uint8_t* data) const;
std::string extractFileName(const DirectoryRecord* record) const;
void parsePathTable(const std::string& path) const;
std::vector<std::string> listDirectoryInternal(uint32_t dirStart, uint32_t dirSize) const;
std::string readFileInternal(uint32_t start, uint32_t size) const;
const DirectoryRecord* findFileRecord(const std::string& path) const;
};
cpp
// VirtualCDRom.cpp
#include "VirtualCDRom.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <cstring>
#include <algorithm>
VirtualCDRom::VirtualCDRom(const std::string& isoPath)
: isoPath(isoPath) {
isoFile.open(isoPath, std::ios::in | std::ios::binary);
if (!isoFile) {
throw std::runtime_error("Could not open ISO file: " + isoPath);
}
// 读取主卷描述符
readPrimaryVolumeDescriptor();
}
VirtualCDRom::~VirtualCDRom() {
if (isoFile.is_open()) {
unmount();
isoFile.close();
}
}
void VirtualCDRom::mount() {
if (mounted) return;
mounted = true;
}
void VirtualCDRom::unmount() {
if (!mounted) return;
mounted = false;
}
bool VirtualCDRom::isMounted() const {
return mounted;
}
std::string VirtualCDRom::getVolumeLabel() const {
return volumeLabel;
}
uint32_t VirtualCDRom::getVolumeSize() const {
return volumeSize;
}
std::vector<std::string> VirtualCDRom::listDirectory(const std::string& path) {
if (!mounted) {
throw std::runtime_error("CD-ROM not mounted");
}
if (path.empty() || path == "/") {
// 根目录
return listDirectoryInternal(leToUint32(primaryVolDesc.rootDirectoryRecord + 2),
leToUint32(primaryVolDesc.rootDirectoryRecord + 10));
}
// 查找目录记录
const DirectoryRecord* record = findFileRecord(path);
if (!record) {
throw std::runtime_error("Directory not found: " + path);
}
if (!(record->flags & 0x02)) { // 不是目录
throw std::runtime_error("Not a directory: " + path);
}
return listDirectoryInternal(leToUint32(reinterpret_cast<const uint8_t*>(record) + 2),
leToUint32(reinterpret_cast<const uint8_t*>(record) + 10));
}
std::string VirtualCDRom::readFile(const std::string& path) {
if (!mounted) {
throw std::runtime_error("CD-ROM not mounted");
}
const DirectoryRecord* record = findFileRecord(path);
if (!record) {
throw std::runtime_error("File not found: " + path);
}
if (record->flags & 0x02) { // 是目录
throw std::runtime_error("Cannot read directory: " + path);
}
return readFileInternal(leToUint32(reinterpret_cast<const uint8_t*>(record) + 2),
leToUint32(reinterpret_cast<const uint8_t*>(record) + 10));
}
bool VirtualCDRom::exists(const std::string& path) const {
if (!mounted) return false;
return findFileRecord(path) != nullptr;
}
void VirtualCDRom::dumpIsoInfo() const {
if (!mounted) {
std::cout << "CD-ROM not mounted\n";
return;
}
std::cout << "ISO Information:\n";
std::cout << " Volume Label: " << volumeLabel << "\n";
std::cout << " Volume Size: " << volumeSize << " bytes\n";
std::cout << " Logical Block Size: " << logicalBlockSize << " bytes\n";
std::cout << " System ID: " << primaryVolDesc.systemId << "\n";
std::cout << " Publisher ID: " << primaryVolDesc.publisherId << "\n";
std::cout << " Preparer ID: " << primaryVolDesc.preparerId << "\n";
std::cout << " Creation Date: " << primaryVolDesc.creationDate << "\n";
std::cout << " Modification Date: " << primaryVolDesc.modificationDate << "\n";
}
// 私有方法实现
void VirtualCDRom::readPrimaryVolumeDescriptor() {
isoFile.seekg(16 * logicalBlockSize); // 主卷描述符通常在第16块
char buffer[2048];
isoFile.read(buffer, sizeof(buffer));
// 检查是否是主卷描述符
if (buffer[0] != 1) {
throw std::runtime_error("Invalid ISO file: Primary Volume Descriptor not found");
}
// 解析主卷描述符
memcpy(&primaryVolDesc, buffer, sizeof(IsoPrimaryVolumeDescriptor));
// 提取卷标
volumeLabel = std::string(primaryVolDesc.volumeId,
strnlen(primaryVolDesc.volumeId, 32));
// 设置卷大小
volumeSize = leToUint32(reinterpret_cast<uint8_t*>(&primaryVolDesc.volumeSpaceSizeLE));
logicalBlockSize = leToUint16(reinterpret_cast<uint8_t*>(&primaryVolDesc.logicalBlockSizeLE));
}
uint32_t VirtualCDRom::leToUint32(const uint8_t* data) const {
return static_cast<uint32_t>(data[0]) |
(static_cast<uint32_t>(data[1]) << 8) |
(static_cast<uint32_t>(data[2]) << 16) |
(static_cast<uint32_t>(data[3]) << 24);
}
uint16_t VirtualCDRom::leToUint16(const uint8_t* data) const {
return static_cast<uint16_t>(data[0]) |
(static_cast<uint16_t>(data[1]) << 8);
}
std::string VirtualCDRom::extractFileName(const DirectoryRecord* record) const {
if (record->nameLength == 1) {
if (record->name[0] == 0) return ".";
if (record->name[0] == 1) return "..";
}
return std::string(record->name, record->nameLength);
}
std::vector<std::string> VirtualCDRom::listDirectoryInternal(uint32_t dirStart, uint32_t dirSize) const {
std::vector<std::string> entries;
// 计算块数
uint32_t blockCount = (dirSize + logicalBlockSize - 1) / logicalBlockSize;
for (uint32_t i = 0; i < blockCount; i++) {
isoFile.seekg((dirStart + i) * logicalBlockSize);
uint32_t bytesRead = 0;
while (bytesRead < logicalBlockSize && bytesRead < dirSize) {
DirectoryRecord record;
isoFile.read(reinterpret_cast<char*>(&record), sizeof(DirectoryRecord));
if (record.length == 0) break;
// 提取文件名
std::string name = extractFileName(&record);
if (!name.empty() && name != "." && name != "..") {
entries.push_back(name);
}
// 移动到下一个记录
isoFile.seekg(record.length - sizeof(DirectoryRecord), std::ios::cur);
bytesRead += record.length;
}
}
return entries;
}
std::string VirtualCDRom::readFileInternal(uint32_t start, uint32_t size) const {
std::string data(size, '\0');
isoFile.seekg(start * logicalBlockSize);
isoFile.read(&data[0], size);
return data;
}
const VirtualCDRom::DirectoryRecord* VirtualCDRom::findFileRecord(const std::string& path) const {
// 简化实现:实际应解析路径表并递归查找
// 这里只实现根目录文件查找
if (path == "/" || path.empty()) {
return reinterpret_cast<const DirectoryRecord*>(primaryVolDesc.rootDirectoryRecord);
}
// 分割路径
std::vector<std::string> parts;
size_t start = 0;
size_t end = path.find('/');
while (end != std::string::npos) {
if (end > start) {
parts.push_back(path.substr(start, end - start));
}
start = end + 1;
end = path.find('/', start);
}
if (start < path.length()) {
parts.push_back(path.substr(start));
}
if (parts.empty()) {
return nullptr;
}
// 从根目录开始
uint32_t currentDirStart = leToUint32(primaryVolDesc.rootDirectoryRecord + 2);
uint32_t currentDirSize = leToUint32(primaryVolDesc.rootDirectoryRecord + 10);
for (const auto& part : parts) {
bool found = false;
std::vector<std::string> entries = listDirectoryInternal(currentDirStart, currentDirSize);
for (const auto& entry : entries) {
if (entry == part) {
// 找到文件/目录
// 简化:实际应读取目录记录
found = true;
break;
}
}
if (!found) {
return nullptr;
}
// 更新当前目录(简化:实际应进入子目录)
}
return nullptr; // 简化实现
}
3. 主程序 (main.cpp)
cpp
#include "VirtualDisk.h"
#include "VirtualCDRom.h"
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
#include <stdexcept>
void printMenu() {
std::cout << "\n===== 虚拟磁盘与光驱系统 =====\n";
std::cout << "1. 创建虚拟磁盘\n";
std::cout << "2. 格式化虚拟磁盘\n";
std::cout << "3. 在虚拟磁盘创建文件\n";
std::cout << "4. 在虚拟磁盘追加文件内容\n";
std::cout << "5. 读取虚拟磁盘文件\n";
std::cout << "6. 删除虚拟磁盘文件\n";
std::cout << "7. 创建虚拟磁盘目录\n";
std::cout << "8. 列出虚拟磁盘目录\n";
std::cout << "9. 挂载虚拟光驱\n";
std::cout << "10. 列出光驱目录\n";
std::cout << "11. 读取光驱文件\n";
std::cout << "12. 显示光驱信息\n";
std::cout << "13. 退出\n";
std::cout << "==============================\n";
std::cout << "请选择操作: ";
}
int main() {
std::vector<std::unique_ptr<VirtualDisk>> disks;
std::unique_ptr<VirtualCDRom> cdrom;
int currentDisk = -1;
while (true) {
printMenu();
int choice;
std::cin >> choice;
std::cin.ignore(); // 忽略换行符
try {
switch (choice) {
case 1: {
std::string path;
size_t sizeMB;
std::cout << "输入磁盘镜像路径: ";
std::getline(std::cin, path);
std::cout << "输入磁盘大小(MB): ";
std::cin >> sizeMB;
std::cin.ignore();
disks.push_back(std::make_unique<VirtualDisk>(path, sizeMB));
currentDisk = disks.size() - 1;
std::cout << "虚拟磁盘创建成功: " << path << " (" << sizeMB << "MB)\n";
break;
}
case 2: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
disks[currentDisk]->format();
std::cout << "虚拟磁盘已格式化\n";
break;
}
case 3: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path, content;
std::cout << "输入文件路径: ";
std::getline(std::cin, path);
std::cout << "输入文件内容: ";
std::getline(std::cin, content);
disks[currentDisk]->createFile(path, content);
std::cout << "文件创建成功: " << path << "\n";
break;
}
case 4: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path, content;
std::cout << "输入文件路径: ";
std::getline(std::cin, path);
std::cout << "输入追加内容: ";
std::getline(std::cin, content);
disks[currentDisk]->appendFile(path, content);
std::cout << "内容已追加到文件: " << path << "\n";
break;
}
case 5: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path;
std::cout << "输入文件路径: ";
std::getline(std::cin, path);
std::string content = disks[currentDisk]->readFile(path);
std::cout << "文件内容:\n" << content << "\n";
break;
}
case 6: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path;
std::cout << "输入文件路径: ";
std::getline(std::cin, path);
disks[currentDisk]->deleteFile(path);
std::cout << "文件已删除: " << path << "\n";
break;
}
case 7: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path;
std::cout << "输入目录路径: ";
std::getline(std::cin, path);
disks[currentDisk]->createDirectory(path);
std::cout << "目录创建成功: " << path << "\n";
break;
}
case 8: {
if (currentDisk == -1) {
std::cout << "请先创建或选择虚拟磁盘\n";
break;
}
std::string path;
std::cout << "输入目录路径(留空为根目录): ";
std::getline(std::cin, path);
if (path.empty()) path = "/";
disks[currentDisk]->listDirectory(path);
break;
}
case 9: {
std::string path;
std::cout << "输入ISO文件路径: ";
std::getline(std::cin, path);
cdrom = std::make_unique<VirtualCDRom>(path);
cdrom->mount();
std::cout << "虚拟光驱已挂载: " << path << "\n";
break;
}
case 10: {
if (!cdrom || !cdrom->isMounted()) {
std::cout << "请先挂载虚拟光驱\n";
break;
}
std::string path;
std::cout << "输入目录路径(留空为根目录): ";
std::getline(std::cin, path);
if (path.empty()) path = "/";
auto entries = cdrom->listDirectory(path);
std::cout << "目录内容 (" << path << "):\n";
for (const auto& entry : entries) {
std::cout << " " << entry << "\n";
}
break;
}
case 11: {
if (!cdrom || !cdrom->isMounted()) {
std::cout << "请先挂载虚拟光驱\n";
break;
}
std::string path;
std::cout << "输入文件路径: ";
std::getline(std::cin, path);
std::string content = cdrom->readFile(path);
std::cout << "文件内容:\n" << content << "\n";
break;
}
case 12: {
if (!cdrom || !cdrom->isMounted()) {
std::cout << "请先挂载虚拟光驱\n";
break;
}
cdrom->dumpIsoInfo();
break;
}
case 13:
std::cout << "正在退出...\n";
return 0;
default:
std::cout << "无效选择\n";
}
} catch (const std::exception& e) {
std::cerr << "错误: " << e.what() << "\n";
}
}
return 0;
}
系统功能说明
1. 虚拟磁盘功能
- 磁盘创建:创建指定大小的虚拟磁盘文件
- 格式化:初始化磁盘结构(FAT表、根目录等)
- 文件操作 :
- 创建/读取/追加/删除文件
- 创建/删除目录
- 列出目录内容
- 空间管理 :
- 显示总空间、已用空间和可用空间
- 自动分配/释放磁盘簇
- 持久化存储:所有操作保存在磁盘镜像文件中
2. 虚拟光驱功能
- ISO挂载:加载ISO文件并解析其结构
- 文件操作 :
- 读取文件内容
- 列出目录内容
- 信息查询 :
- 显示卷标、卷大小等信息
- 显示创建者、发布者等元数据
- ISO 9660支持:解析标准ISO文件系统
3. 用户界面
- 交互式菜单系统
- 清晰的错误提示
- 操作结果反馈
- 多虚拟磁盘管理
技术实现细节
1. 虚拟磁盘实现
- 磁盘结构 :
- 引导扇区:存储磁盘元数据
- FAT表:管理簇分配
- 根目录区:存储根目录项
- 数据区:存储文件和目录内容
- 文件分配 :
- 使用4KB簇大小
- 链式分配策略
- 目录结构 :
- 树形目录结构
- 支持长文件名(最多55字符)
- 缓存机制 :
- 目录项缓存提高性能
- 延迟写入优化
2. 虚拟光驱实现
- ISO解析 :
- 读取主卷描述符
- 解析目录记录
- 路径解析 :
- 支持绝对路径和相对路径
- 处理特殊目录项(.和...)
- 数据读取 :
- 按逻辑块读取数据
- 处理大文件(多块存储)
3. 跨平台支持
- 使用C++17标准库
- 文件系统抽象(std::filesystem)
- 平台无关的文件操作
- 可移植的字节序处理
参考代码 C++实现虚拟磁盘和虚拟光驱 www.youwenfan.com/contentcst/122342.html
使用说明
1. 编译程序
bash
# Linux/macOS
g++ -o vfs main.cpp VirtualDisk.cpp VirtualCDRom.cpp -std=c++17
# Windows (使用MinGW)
g++ -o vfs.exe main.cpp VirtualDisk.cpp VirtualCDRom.cpp -std=c++17
2. 运行程序
bash
./vfs
3. 操作示例
-
创建虚拟磁盘:
- 选择选项1
- 输入磁盘路径(如"mydisk.vdk")
- 输入磁盘大小(如100MB)
-
在虚拟磁盘创建文件:
- 选择选项3
- 输入文件路径(如"/docs/readme.txt")
- 输入文件内容
-
挂载虚拟光驱:
- 选择选项9
- 输入ISO文件路径(如"ubuntu.iso")
-
读取光驱文件:
- 选择选项11
- 输入文件路径(如"/README")
扩展功能建议
1. 增强虚拟磁盘功能
cpp
// 添加文件压缩支持
void compressFile(const std::string& path) {
std::string content = readFile(path);
// 使用zlib或lz4压缩
std::string compressed = compressData(content);
// 更新文件内容
writeFile(path, compressed);
// 设置压缩标志
setFileAttribute(path, COMPRESSED);
}
// 添加文件加密支持
void encryptFile(const std::string& path, const std::string& key) {
std::string content = readFile(path);
std::string encrypted = encryptData(content, key);
writeFile(path, encrypted);
setFileAttribute(path, ENCRYPTED);
}
2. 增强虚拟光驱功能
cpp
// 支持UDF文件系统
class UdfParser {
// 解析UDF文件系统
};
// 支持混合模式光盘
class HybridCD {
// 处理包含多种文件系统的光盘
};
// 添加刻录功能
void burnIso(const std::string& outputPath) {
// 将虚拟磁盘内容刻录为ISO
}
3. 添加图形界面
cpp
// 使用Qt实现GUI
class VfsGui : public QMainWindow {
Q_OBJECT
public:
VfsGui(QWidget* parent = nullptr);
private slots:
void createDisk();
void formatDisk();
void createFile();
void mountIso();
private:
QTreeView* fileTree;
QListWidget* logView;
VirtualDisk* currentDisk;
VirtualCDRom* currentCD;
};
应用场景
-
教育与研究:
- 操作系统课程实验
- 文件系统研究
- 数据恢复技术学习
-
软件开发:
- 测试文件系统相关应用
- 沙箱环境文件操作
- 离线文件处理
-
系统工具:
- 虚拟光驱软件
- 磁盘管理工具
- 数据备份与恢复
-
嵌入式系统:
- 资源受限环境文件存储
- 自定义文件系统实现
- 固件更新机制
项目总结
这个虚拟磁盘和虚拟光驱系统实现了以下核心功能:
-
虚拟磁盘系统:
- 创建和管理虚拟磁盘镜像
- 实现基本文件系统操作
- 支持文件/目录的增删改查
- 管理磁盘空间分配
-
虚拟光驱系统:
- 加载和解析ISO文件
- 实现文件读取和目录列表
- 提供卷信息查询功能
- 支持ISO 9660标准
-
统一接口:
- 提供一致的API操作虚拟存储
- 支持多虚拟磁盘管理
- 实现虚拟光驱挂载/卸载