一、前言
大家好!今天我们来系统梳理《计算机操作系统》第七章 “文件管理” 的核心知识点,从基础概念到代码实现,力求通俗易懂,每个核心知识点都会搭配实战案例和架构图 / 流程图,帮助大家彻底吃透文件管理的底层逻辑。所有代码均采用C++98 标准编写,可直接编译运行,注释详尽,方便动手实操。
二、核心知识点讲解
7.1 文件和文件系统
1. 核心概念
文件:是操作系统中存储信息的基本单位,由一系列字符 / 字节组成,具有唯一文件名,存储在外部存储介质(磁盘、U 盘等)上。文件系统:是操作系统中负责管理和存储文件信息的软件集合,核心功能包括文件创建 / 删除、读写、目录管理、权限控制等。
2. 架构图
3. 实战案例:模拟文件系统基础结构(C++98)
#include <iostream> #include <string> #include <ctime> using namespace std; // 遵循C++98标准,模拟文件的基本属性和操作 // 文件属性结构体(对应文件系统中文件的元数据) struct FileAttribute { string fileName; // 文件名 int fileSize; // 文件大小(字节) time_t createTime; // 创建时间 time_t modifyTime; // 修改时间 string fileType; // 文件类型(文本/二进制等) }; // 文件系统基础类 class FileSystem { public: // 构造函数:初始化文件系统 FileSystem() { cout << "文件系统初始化完成!" << endl; } // 创建文件:初始化文件属性 void createFile(const string& name, const string& type, int size) { FileAttribute file; file.fileName = name; file.fileSize = size; file.fileType = type; // 获取当前时间作为创建/修改时间(先赋值给变量,再取地址) file.createTime = time(NULL); file.modifyTime = file.createTime; cout << "文件创建成功!" << endl; cout << "文件名:" << file.fileName << endl; cout << "文件大小:" << file.fileSize << " 字节" << endl; cout << "文件类型:" << file.fileType << endl; cout << "创建时间:" << ctime(&file.createTime); } // 删除文件 void deleteFile(const string& name) { cout << "文件 " << name << " 删除成功!" << endl; } // 读取文件(模拟) void readFile(const string& name) { cout << "正在读取文件:" << name << endl; cout << "文件内容(模拟):Hello, File System!" << endl; } // 写入文件(模拟)- 修复临时值取地址问题 void writeFile(const string& name, const string& content) { cout << "向文件 " << name << " 写入内容:" << content << endl; // 修复点:先将time(NULL)的结果赋值给变量(左值),再取地址 time_t currentTime = time(NULL); cout << "文件修改时间更新为:" << ctime(¤tTime); } }; // 主函数:测试文件系统基础操作 int main() { // 创建文件系统实例 FileSystem fs; // 创建文本文件 fs.createFile("test.txt", "文本文件", 1024); // 读取文件 fs.readFile("test.txt"); // 写入文件 fs.writeFile("test.txt", "这是测试文件的内容!"); // 删除文件 fs.deleteFile("test.txt"); return 0; }4. 代码说明
- 定义
FileAttribute结构体模拟文件元数据(文件名、大小、时间等),对应文件系统中存储的文件属性; FileSystem类封装文件系统核心操作(创建、删除、读写),符合 C++98 语法规范;- 主函数中完成完整的文件操作流程,可直接编译运行(g++ -std=c++98 文件名.cpp -o 可执行文件)。
7.2 文件的逻辑结构
1. 核心概念
文件的逻辑结构是用户视角下文件的组织形式,分为两类:
- 流式文件:无结构,由字符 / 字节流组成(如.txt 文件);
- 记录式文件:有结构,由多条记录组成(如数据库表、CSV 文件)。
2. 流程图
3. 实战案例:模拟流式文件和记录式文件(C++98)
#include <iostream> #include <string> #include <vector> #include <iomanip> using namespace std; // 遵循C++98标准,模拟两种文件逻辑结构 // 1. 流式文件类(无结构,字节流) class StreamFile { private: string fileName; string content; // 字节流形式存储内容 public: StreamFile(const string& name) : fileName(name) {} // 写入字节流(流式文件核心操作) void writeStream(const string& data) { content += data; // 直接追加,无结构限制 cout << "流式文件 " << fileName << " 写入成功,当前内容长度:" << content.size() << " 字节" << endl; } // 读取字节流 string readStream() { cout << "读取流式文件 " << fileName << " 内容:" << endl; return content; } }; // 2. 记录式文件:单条记录结构体 struct Record { int id; // 记录ID string name; // 姓名 int age; // 年龄 }; // 记录式文件类 class RecordFile { private: string fileName; vector<Record> records; // 按记录组织内容(C++98支持vector) public: RecordFile(const string& name) : fileName(name) {} // 添加记录(记录式文件核心操作,有固定结构) void addRecord(int id, const string& name, int age) { Record r; r.id = id; r.name = name; r.age = age; records.push_back(r); cout << "记录式文件 " << fileName << " 添加记录成功,当前记录数:" << records.size() << endl; } // 读取指定记录 Record readRecord(int id) { for (vector<Record>::iterator it = records.begin(); it != records.end(); ++it) { // C++98迭代器写法 if (it->id == id) { cout << "找到记录 ID=" << id << ":" << endl; return *it; } } cout << "未找到记录 ID=" << id << endl; return Record(); // 返回空记录 } // 打印所有记录 void printAllRecords() { cout << "记录式文件 " << fileName << " 所有记录:" << endl; cout << setw(5) << "ID" << setw(10) << "姓名" << setw(5) << "年龄" << endl; for (vector<Record>::iterator it = records.begin(); it != records.end(); ++it) { cout << setw(5) << it->id << setw(10) << it->name << setw(5) << it->age << endl; } } }; // 主函数:测试两种文件逻辑结构 int main() { // 1. 测试流式文件 StreamFile sFile("stream.txt"); sFile.writeStream("Hello, Stream File!"); sFile.writeStream("这是流式文件的追加内容,无结构限制。"); cout << sFile.readStream() << endl << endl; // 2. 测试记录式文件 RecordFile rFile("record.csv"); rFile.addRecord(1, "张三", 20); rFile.addRecord(2, "李四", 22); rFile.printAllRecords(); Record r = rFile.readRecord(1); cout << "读取到的记录:ID=" << r.id << ",姓名=" << r.name << ",年龄=" << r.age << endl; return 0; }4. 代码说明
- 流式文件类
StreamFile:通过字符串直接存储字节流,写入时无结构限制,模拟.txt 等无结构文件; - 记录式文件类
RecordFile:通过vector存储固定结构的Record结构体,模拟 CSV / 数据库表等有结构文件; - 全部采用 C++98 语法(如迭代器写法、无 C++11 的 auto 关键字),可直接编译运行。
7.3 文件目录
1. 核心概念
文件目录(文件夹)是操作系统为管理文件而建立的索引结构,核心作用是映射文件名和文件物理存储地址,常见结构:
- 单级目录:所有文件存于一个目录,无层级;
- 两级目录:分为用户目录和文件目录;
- 树形目录(最常用):多级层级结构(如 Windows 的 C:\Users\XXX)。
2. 思维导图
3. 实战案例:模拟树形文件目录(C++98)
#include <iostream> #include <string> #include <vector> using namespace std; // 遵循C++98标准,模拟树形文件目录结构 // 目录节点类(可包含文件或子目录) class DirNode { private: string name; // 目录/文件名 bool isDir; // 是否为目录(true=目录,false=文件) DirNode* parent; // 父目录指针 vector<DirNode*> children; // 子节点(文件/子目录) public: // 构造函数:初始化节点 DirNode(const string& name, bool isDir, DirNode* parent) : name(name), isDir(isDir), parent(parent) {} // 析构函数:释放子节点内存(C++98手动管理内存) ~DirNode() { for (vector<DirNode*>::iterator it = children.begin(); it != children.end(); ++it) { delete *it; } } // 添加子节点(文件/子目录) void addChild(const string& childName, bool isChildDir) { DirNode* child = new DirNode(childName, isChildDir, this); children.push_back(child); cout << (isChildDir ? "目录" : "文件") << " " << childName << " 创建成功!" << endl; } // 遍历当前目录下的所有节点 void listChildren() { cout << "当前目录 " << name << " 下的内容:" << endl; for (vector<DirNode*>::iterator it = children.begin(); it != children.end(); ++it) { cout << ((*it)->isDir ? "[目录] " : "[文件] ") << (*it)->name << endl; } } // 查找子节点(返回指针,用于进入子目录) DirNode* findChild(const string& childName) { for (vector<DirNode*>::iterator it = children.begin(); it != children.end(); ++it) { if ((*it)->name == childName && (*it)->isDir) { return *it; } } cout << "未找到目录 " << childName << endl; return NULL; } // 获取当前节点名称 string getName() { return name; } }; // 主函数:模拟树形目录操作(如Linux/macOS的cd、ls、mkdir、touch) int main() { // 1. 创建根目录(/) DirNode* root = new DirNode("/", true, NULL); DirNode* currentDir = root; // 当前工作目录 // 2. 在根目录创建子目录和文件 currentDir->addChild("home", true); // 创建home目录 currentDir->addChild("etc", true); // 创建etc目录 currentDir->addChild("readme.txt", false); // 创建readme.txt文件 currentDir->listChildren(); cout << "------------------------" << endl; // 3. 进入home目录 currentDir = currentDir->findChild("home"); cout << "当前目录切换到:" << currentDir->getName() << endl; // 4. 在home目录创建用户目录和文件 currentDir->addChild("user1", true); // 创建user1目录 currentDir->addChild("user2", true); // 创建user2目录 currentDir->addChild("profile.cfg", false); // 创建配置文件 currentDir->listChildren(); // 5. 释放内存 delete root; return 0; }4. 代码说明
DirNode类模拟目录节点,包含名称、类型(目录 / 文件)、父节点、子节点列表;- 实现添加子节点、遍历目录、切换目录等核心操作,模拟树形目录的层级管理;
- 手动管理内存(析构函数释放子节点),符合 C++98 的内存管理规范。
7.4 文件共享
1. 核心概念
文件共享是指多个用户 / 进程同时访问同一个文件,常见实现方式:
- 基于索引节点(i 节点):多个目录项指向同一个 i 节点(存储文件元数据);
- 符号链接(软链接):创建指向原文件的快捷方式;
- 硬链接:多个文件名指向同一物理存储。
2. 流程图
3. 实战案例:模拟文件共享(C++98)
#include <iostream> #include <string> #include <map> using namespace std; // 遵循C++98标准,模拟文件共享(i节点+硬链接+软链接) // 模拟i节点(存储文件元数据,不存储文件名) struct INode { string fileData; // 文件实际内容 int linkCount; // 硬链接计数 string filePath; // 文件物理路径 }; // 文件共享管理器 class FileShareManager { private: map<int, INode> inodeMap; // i节点表(i节点ID→i节点) map<string, int> fileNameToInode;// 文件名→i节点ID(硬链接) map<string, string> symLinkMap; // 软链接表(链接名→原文件名) int nextInodeId; // 下一个可用i节点ID public: FileShareManager() : nextInodeId(1) {} // 创建文件,初始化i节点 void createFile(const string& fileName, const string& data) { INode inode; inode.fileData = data; inode.linkCount = 1; inode.filePath = "/disk/" + fileName; int inodeId = nextInodeId++; inodeMap[inodeId] = inode; fileNameToInode[fileName] = inodeId; cout << "文件 " << fileName << " 创建成功,i节点ID:" << inodeId << endl; } // 创建硬链接:新增文件名→同一i节点 void createHardLink(const string& linkName, const string& origName) { if (fileNameToInode.find(origName) == fileNameToInode.end()) { cout << "原文件 " << origName << " 不存在!" << endl; return; } int inodeId = fileNameToInode[origName]; fileNameToInode[linkName] = inodeId; inodeMap[inodeId].linkCount++; // 硬链接计数+1 cout << "硬链接 " << linkName << " 指向 " << origName << " 创建成功!" << endl; cout << "当前i节点 " << inodeId << " 硬链接数:" << inodeMap[inodeId].linkCount << endl; } // 创建软链接:存储原文件路径(不关联i节点) void createSymLink(const string& linkName, const string& origName) { if (fileNameToInode.find(origName) == fileNameToInode.end()) { cout << "原文件 " << origName << " 不存在!" << endl; return; } symLinkMap[linkName] = origName; cout << "软链接 " << linkName << " 指向 " << origName << " 创建成功!" << endl; } // 读取文件(支持硬链接/软链接)- 修复const参数修改问题 void readFile(const string& fileName) { // 修复点:创建临时变量存储文件名,避免修改const参数 string actualFileName = fileName; // 1. 先判断是否是软链接 if (symLinkMap.find(actualFileName) != symLinkMap.end()) { string origName = symLinkMap[actualFileName]; cout << "软链接 " << actualFileName << " 指向原文件:" << origName << endl; actualFileName = origName; // 修改临时变量,而非const参数 } // 2. 判断是否是硬链接/原文件 if (fileNameToInode.find(actualFileName) == fileNameToInode.end()) { cout << "文件 " << actualFileName << " 不存在!" << endl; return; } int inodeId = fileNameToInode[actualFileName]; cout << "读取文件 " << actualFileName << "(i节点ID:" << inodeId << ")内容:" << endl; cout << inodeMap[inodeId].fileData << endl; } // 删除文件(硬链接计数为0时才真正删除i节点) void deleteFile(const string& fileName) { if (fileNameToInode.find(fileName) == fileNameToInode.end()) { cout << "文件 " << fileName << " 不存在!" << endl; return; } int inodeId = fileNameToInode[fileName]; fileNameToInode.erase(fileName); // 删除文件名映射 inodeMap[inodeId].linkCount--; // 硬链接计数-1 cout << "文件 " << fileName << " 已删除,当前i节点 " << inodeId << " 硬链接数:" << inodeMap[inodeId].linkCount << endl; // 硬链接计数为0,删除i节点 if (inodeMap[inodeId].linkCount == 0) { inodeMap.erase(inodeId); cout << "i节点 " << inodeId << " 已释放!" << endl; } } }; // 主函数:测试文件共享 int main() { FileShareManager fsm; // 1. 创建原文件 fsm.createFile("data.txt", "这是共享文件的内容!"); // 2. 创建硬链接 fsm.createHardLink("data_hardlink.txt", "data.txt"); // 3. 创建软链接 fsm.createSymLink("data_symlink.txt", "data.txt"); // 4. 读取硬链接/软链接 cout << "------------------------" << endl; fsm.readFile("data_hardlink.txt"); cout << "------------------------" << endl; fsm.readFile("data_symlink.txt"); // 5. 删除原文件(硬链接仍可用) cout << "------------------------" << endl; fsm.deleteFile("data.txt"); fsm.readFile("data_hardlink.txt"); // 硬链接仍可读取 // 6. 删除硬链接(i节点释放) cout << "------------------------" << endl; fsm.deleteFile("data_hardlink.txt"); // 7. 软链接失效 cout << "------------------------" << endl; fsm.readFile("data_symlink.txt"); return 0; }4. 代码说明
- 用
INode结构体模拟 i 节点,存储文件实际内容和硬链接计数; - 硬链接:多个文件名映射到同一 i 节点 ID,计数 > 0 时文件不真正删除;
- 软链接:单独存储链接名→原文件名,原文件删除则链接失效;
- 全部操作符合 C++98 标准,模拟 Linux 系统的文件共享逻辑。
7.5 文件保护
1. 核心概念
文件保护是防止文件被未授权访问 / 修改,常见方式:
- 访问控制列表(ACL):为每个文件指定用户 / 组的访问权限(读 R、写 W、执行 X);
- 口令保护:访问文件需输入口令;
- 加密保护:文件内容加密存储,只有解密后才能访问。
2. 架构图
3. 实战案例:模拟文件权限保护(C++98)
#include <iostream> #include <string> #include <map> using namespace std; // 遵循C++98标准,模拟文件访问权限保护(ACL) // 用户类型枚举(C++98支持enum) enum UserType { OWNER, // 文件所有者 GROUP, // 同组用户 OTHER // 其他用户 }; // 文件权限结构体 struct FilePermission { bool read; // 读权限 bool write; // 写权限 bool exec; // 执行权限 // C++98兼容:添加默认构造函数(避免初始化问题) FilePermission() : read(false), write(false), exec(false) {} // 带参数的构造函数(方便初始化) FilePermission(bool r, bool w, bool e) : read(r), write(w), exec(e) {} }; // 文件保护管理器 class FileProtectManager { private: // 修复点1:C++98要求嵌套模板的>>必须分开写为> > map<string, map<UserType, FilePermission> > permMap; // 用户-文件所有者映射 map<string, string> userFileOwnerMap; // 模拟用户口令 map<string, string> userPwdMap; public: // 初始化:添加测试用户和口令 FileProtectManager() { userPwdMap["user1"] = "123456"; // 文件所有者 userPwdMap["user2"] = "654321"; // 同组用户 userPwdMap["user3"] = "000000"; // 其他用户 } // 创建文件并设置权限(所有者默认拥有全部权限) void createFileWithPerm(const string& fileName, const string& owner) { // 记录文件所有者 userFileOwnerMap[fileName] = owner; // 设置所有者权限(R/W/X)- 使用C++98的构造函数初始化 FilePermission ownerPerm(true, true, true); // 设置同组用户权限(R/X) FilePermission groupPerm(true, false, true); // 设置其他用户权限(仅R) FilePermission otherPerm(true, false, false); permMap[fileName][OWNER] = ownerPerm; permMap[fileName][GROUP] = groupPerm; permMap[fileName][OTHER] = otherPerm; cout << "文件 " << fileName << " 创建成功!" << endl; cout << "所有者:" << owner << endl; cout << "权限设置:" << endl; cout << " 所有者:读(R)=是,写(W)=是,执行(X)=是" << endl; cout << " 同组用户:读(R)=是,写(W)=否,执行(X)=是" << endl; cout << " 其他用户:读(R)=是,写(W)=否,执行(X)=否" << endl; } // 用户登录验证 bool userLogin(const string& userName, const string& pwd) { if (userPwdMap.find(userName) == userPwdMap.end()) { cout << "用户 " << userName << " 不存在!" << endl; return false; } if (userPwdMap[userName] != pwd) { cout << "口令错误!" << endl; return false; } cout << "用户 " << userName << " 登录成功!" << endl; return true; } // 判断用户对文件的权限 FilePermission checkPerm(const string& userName, const string& fileName) { if (permMap.find(fileName) == permMap.end()) { cout << "文件 " << fileName << " 不存在!" << endl; // 修复点2:使用C++98的构造函数返回空权限,而非列表初始化 return FilePermission(false, false, false); } // 判断用户类型 string owner = userFileOwnerMap[fileName]; UserType ut; if (userName == owner) { ut = OWNER; } else if (userName == "user2") { // 模拟同组用户 ut = GROUP; } else { ut = OTHER; } cout << "用户 " << userName << " 对文件 " << fileName << " 的权限类型:" << (ut == OWNER ? "所有者" : (ut == GROUP ? "同组用户" : "其他用户")) << endl; return permMap[fileName][ut]; } // 执行文件操作(检查权限) void doFileOperation(const string& userName, const string& fileName, const string& op) { FilePermission perm = checkPerm(userName, fileName); bool allowed = false; if (op == "read" && perm.read) { allowed = true; } else if (op == "write" && perm.write) { allowed = true; } else if (op == "exec" && perm.exec) { allowed = true; } if (allowed) { cout << "允许执行 " << op << " 操作!" << endl; } else { cout << "拒绝执行 " << op << " 操作:权限不足!" << endl; } } }; // 主函数:测试文件保护 int main() { FileProtectManager fpm; // 1. 创建文件,指定所有者为user1 fpm.createFileWithPerm("app.exe", "user1"); cout << "------------------------" << endl; // 2. 用户1登录,测试所有操作 if (fpm.userLogin("user1", "123456")) { fpm.doFileOperation("user1", "app.exe", "read"); fpm.doFileOperation("user1", "app.exe", "write"); fpm.doFileOperation("user1", "app.exe", "exec"); } cout << "------------------------" << endl; // 3. 用户2(同组)登录,测试操作 if (fpm.userLogin("user2", "654321")) { fpm.doFileOperation("user2", "app.exe", "read"); fpm.doFileOperation("user2", "app.exe", "write"); // 无写权限 fpm.doFileOperation("user2", "app.exe", "exec"); } cout << "------------------------" << endl; // 4. 用户3(其他)登录,测试操作 if (fpm.userLogin("user3", "000000")) { fpm.doFileOperation("user3", "app.exe", "read"); fpm.doFileOperation("user3", "app.exe", "write"); // 无写权限 fpm.doFileOperation("user3", "app.exe", "exec"); // 无执行权限 } return 0; }4. 代码说明
- 用
UserType枚举区分用户类型(所有者 / 同组 / 其他),FilePermission存储 R/W/X 权限; FileProtectManager实现用户登录、权限检查、操作鉴权核心逻辑;- 模拟不同用户的权限差异,符合操作系统中文件权限管理的核心思想。
三、习题
基础题
- 简述文件的逻辑结构分类及各自特点,结合 7.2 的代码说明流式文件和记录式文件的实现差异。
- 解释硬链接和软链接的区别,结合 7.4 的代码说明为何硬链接删除原文件后仍可访问,而软链接不行。
- 操作系统中文件目录的核心作用是什么?树形目录相比单级目录有哪些优势?
编程题
基于 7.5 的文件保护代码,扩展功能:
- 添加 “修改文件权限” 的函数,允许文件所有者修改同组 / 其他用户的 R/W/X 权限;
- 增加 “用户组管理” 功能,支持将用户加入 / 移出指定组,动态判断用户权限类型。
四、代码运行说明
- 编译命令(确保编译器支持 C++98):
g++ -std=c++98 文件名.cpp -o 可执行文件名- 运行命令:
./可执行文件名 # Linux/macOS # 或 可执行文件名.exe # Windows- 所有代码无第三方依赖,仅依赖 C++98 标准库,可直接编译运行。
总结
- 文件管理核心包括文件 / 文件系统基础、逻辑结构、目录管理、共享、保护五大模块,每个模块均对应操作系统的核心功能;
- 实战代码基于 C++98 标准实现,模拟了各模块的核心逻辑(如树形目录、i 节点共享、ACL 权限控制),可直接编译运行;
- 各知识点配套架构图 / 流程图(Mermaid 格式),可直接复制到 Mermaid 编辑器生成可视化图形,辅助理解概念。