实验五:文件管理(8学时)
目录
实验要点:
Linux系统文件调用的使用
设计一个二级目录的树形文件系统程序
实验要求:
利用C语言实现一个简单的文件系统,能完成目录和文件的创建、删除、空间分配,能实现两级目录。 要求设计一个 5个用户的文件系统,每次用户可保存5个文件,用户在一次运行中只能打开一个文件,对文件必须设置保护措施,且至少有Create、delete、open、close、read、write等命令。
提交内容:
流程图
源程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define MAX_USERS 5
#define MAX_FILES_PER_USER 5
#define MAX_FILENAME_LEN 20
#define MAX_CONTENT_LEN 100
#define FILE_SYSTEM_FILE "filesystem.dat"
enum ProtectionLevel {
PRIVATE,
PUBLIC
};
struct File {
char filename[MAX_FILENAME_LEN];
char content[MAX_CONTENT_LEN];
enum ProtectionLevel protection;
int isOpen; // 用于标记文件是否已经被打开
int ownerId; // 保存创建文件的用户 ID
};
struct Directory {
char dirname[MAX_FILENAME_LEN];
struct File files[MAX_FILES_PER_USER];
int fileCount;
};
struct User {
char username[MAX_FILENAME_LEN];
int userId;
};
struct FileSystem {
struct Directory userDirs[MAX_USERS];
struct File* openedFile; // 用于记录当前打开的文件
};
void createDirectory(struct Directory* parentDir, char* dirname) {
struct Directory newDir;
strcpy(newDir.dirname, dirname);
newDir.fileCount = 0;
*parentDir = newDir;
}
void deleteDirectory(struct Directory* parentDir, char* dirname) {
// 删除目录的逻辑
}
void createFile(struct FileSystem* fs, struct Directory* dir, char* filename, enum ProtectionLevel protection, int ownerId) {
if (dir->fileCount < MAX_FILES_PER_USER) {
struct File newFile;
strcpy(newFile.filename, filename);
newFile.protection = protection;
newFile.isOpen = 0; // 文件创建时默认未打开
// 设置 ownerId 为无效值,表示文件的拥有者是所有用户
newFile.ownerId = (protection == PUBLIC) ? -1 : ownerId;
dir->files[dir->fileCount++] = newFile;
// 如果是公共文件,将其添加到所有用户的目录中
if (protection == PUBLIC) {
for (int i = 0; i < MAX_USERS; ++i) {
if (i != ownerId - 1) {
struct Directory* otherDir = &fs->userDirs[i];
otherDir->files[otherDir->fileCount++] = newFile;
}
}
}
printf("File '%s' created with protection level %s.\n", filename, (protection == PRIVATE) ? "PRIVATE" : "PUBLIC");
} else {
printf("Cannot create more files in this directory.\n");
}
}
void deleteFile(struct Directory* dir, char* filename) {
int i;
for (i = 0; i < dir->fileCount; ++i) {
if (strcmp(dir->files[i].filename, filename) == 0) {
// 如果文件是共享文件,将 ownerId 设置为无效值
if (dir->files[i].protection == PUBLIC) {
dir->files[i].ownerId = -1;
}
memmove(&dir->files[i], &dir->files[i + 1], (dir->fileCount - i - 1) * sizeof(struct File));
dir->fileCount--;
printf("File '%s' deleted.\n", filename);
return;
}
}
printf("File '%s' not found.\n", filename);
}
struct File* openFile(struct Directory* dir, char* filename, int userId, struct FileSystem* fs) {
// 检查是否已经有文件打开
if (fs->openedFile != NULL) {
printf("Another file is already open. Close it before opening a new one.\n");
return NULL;
}
// 寻找文件并进行相关操作
for (int i = 0; i < dir->fileCount; ++i) {
if (strcmp(dir->files[i].filename, filename) == 0) {
// 检查权限
if ((dir->files[i].protection == PRIVATE && dir->files[i].ownerId == userId) ||
(dir->files[i].protection == PUBLIC)) {
// 私有文件只能被所有者打开,公共文件可以被任何用户打开
if (!dir->files[i].isOpen) {
dir->files[i].isOpen = 1;
printf("File '%s' opened with protection level %s.\n", filename, (dir->files[i].protection == PRIVATE) ? "PRIVATE" : "PUBLIC");
return &dir->files[i];
} else {
printf("File '%s' is already open.\n", filename);
return NULL;
}
} else {
printf("Invalid protection level for file '%s'.\n", filename);
return NULL;
}
}
}
printf("File '%s' not found.\n", filename);
return NULL;
}
void closeFile(struct File* file, struct FileSystem* fs) {
file->isOpen = 0;
fs->openedFile = NULL; // 清除当前打开的文件
printf("File '%s' closed.\n", file->filename);
}
void readFile(struct File* file) {
printf("File content:\n%s\n", file->content);
}
void writeFile(struct File* file, char* content) {
strcpy(file->content, content);
printf("File '%s' written.\n", file->filename);
}
void saveUserDirectory(struct Directory* userDir, FILE* file) {
// 写入用户目录信息
fwrite(userDir, sizeof(struct Directory), 1, file);
// 写入用户目录中每个文件的信息
fwrite(userDir->files, sizeof(struct File), userDir->fileCount, file);
}
// 在保存文件系统时添加调试输出
void saveFileSystem(struct FileSystem* fs) {
FILE* file = fopen(FILE_SYSTEM_FILE, "wb");
if (file == NULL) {
perror("Error opening file for writing");
exit(EXIT_FAILURE);
}
// 写入文件系统信息
fwrite(fs, sizeof(struct FileSystem), 1, file);
// 写入每个用户的文件信息
for (int i = 0; i < MAX_USERS; ++i) {
// 写入用户目录信息
fwrite(&fs->userDirs[i], sizeof(struct Directory), 1, file);
// 写入用户目录中每个文件的信息
fwrite(fs->userDirs[i].files, sizeof(struct File), fs->userDirs[i].fileCount, file);
}
// 调试输出
printf("Saved file system:\n");
for (int i = 0; i < MAX_USERS; ++i) {
printf("User %d files:\n", i + 1);
for (int j = 0; j < fs->userDirs[i].fileCount; ++j) {
printf("File %d: %s\n", j + 1, fs->userDirs[i].files[j].filename);
}
}
fclose(file);
}
void loadFileSystem(struct FileSystem* fs) {
system("pwd"); // 输出当前工作目录
FILE* file = fopen(FILE_SYSTEM_FILE, "rb");
if (file == NULL) {
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
// 读取文件系统信息
fread(fs, sizeof(struct FileSystem), 1, file);
// 读取每个用户的文件信息
for (int i = 0; i < MAX_USERS; ++i) {
fread(&fs->userDirs[i], sizeof(struct Directory), 1, file);
// 读取用户目录中每个文件的信息
fread(fs->userDirs[i].files, sizeof(struct File), fs->userDirs[i].fileCount, file);
// 处理无效的 ownerId(-1)并设置为当前用户 ID
for (int j = 0; j < fs->userDirs[i].fileCount; ++j) {
if (fs->userDirs[i].files[j].ownerId == -1) {
fs->userDirs[i].files[j].ownerId = i + 1;
}
}
}
fclose(file);
// 调试输出
printf("Loaded file system:\n");
//for (int i = 0; i < MAX_USERS; ++i) {
//printf("User %d files:\n", i + 1);
//for (int j = 0; j < fs->userDirs[i].fileCount; ++j) {
//printf("File %d: %s\n", j + 1, fs->userDirs[i].files[j].filename);
//}
//}
}
void parseCommand(struct FileSystem* fs, struct User* user, char* command) {
char cmd[10];
char arg[20];
if (sscanf(command, "%9s %19[^\n]", cmd, arg) != 2) {
printf("Invalid command format.\n");
return;
}
if (strcmp(cmd, "exit") == 0) {
saveFileSystem(fs); // 用户退出时保存文件系统状态
printf("User %s exited.\n", user->username);
exit(EXIT_SUCCESS); // 确保退出程序
}
if (strcmp(cmd, "create") == 0) {
if (strlen(arg) > 0) {
char protectionStr[10];
printf("Enter protection level (private/public): ");
scanf("%s", protectionStr);
int protection;
if (strcmp(protectionStr, "private") == 0) {
protection = PRIVATE;
} else if (strcmp(protectionStr, "public") == 0) {
protection = PUBLIC;
} else {
printf("Invalid protection level. Defaulting to PRIVATE.\n");
protection = PRIVATE;
}
createFile(fs, &fs->userDirs[user->userId - 1], arg, protection, user->userId);
} else {
printf("Usage: create <filename>\n");
}
} else if (strcmp(cmd, "delete") == 0) {
deleteFile(&fs->userDirs[user->userId - 1], arg);
} else if (strcmp(cmd, "open") == 0) {
openFile(&fs->userDirs[user->userId - 1], arg, user->userId, fs);
} else if (strcmp(cmd, "close") == 0) {
int index = atoi(arg) - 1; // 获取索引
if (index >= 0 && index < fs->userDirs[user->userId - 1].fileCount) {
closeFile(&fs->userDirs[user->userId - 1].files[index], fs);
} else {
printf("Invalid file index.\n");
}
} else if (strcmp(cmd, "read") == 0) {
int index = atoi(arg) - 1; // 获取索引
if (index >= 0 && index < fs->userDirs[user->userId - 1].fileCount) {
readFile(&fs->userDirs[user->userId - 1].files[index]);
} else {
printf("Invalid file index.\n");
}
} else if (strcmp(cmd, "write") == 0) {
int index = atoi(arg) - 1; // 获取索引
if (index >= 0 && index < fs->userDirs[user->userId - 1].fileCount) {
char content[MAX_CONTENT_LEN];
printf("Enter content:\n");
scanf(" %[^\n]", content);
writeFile(&fs->userDirs[user->userId - 1].files[index], content);
} else {
printf("Invalid file index.\n");
}
} else {
printf("Invalid command.\n");
}
}
void initFileSystem(struct FileSystem* fs) {
FILE* file = fopen(FILE_SYSTEM_FILE, "rb");
if (file == NULL) {
// 文件不存在,创建一个新文件
printf("Error opening file for reading: %s\n", strerror(errno));
// 创建一个新的文件系统
for (int i = 0; i < MAX_USERS; ++i) {
strcpy(fs->userDirs[i].dirname, "home");
fs->userDirs[i].fileCount = 0;
}
// 保存新的文件系统状态
saveFileSystem(fs);
} else {
// 文件存在,加载文件系统状态
fclose(file); // 关闭文件描述符
loadFileSystem(fs);
}
}
void userInterface(struct FileSystem* fs, struct User* user) {
char command[100];
printf("Welcome, %s!\n", user->username);
loadFileSystem(fs); // 在用户登录时加载文件系统状态
while (1) {
printf("Enter command (create/delete/open/close/read/write/exit): ");
scanf(" %[^\n]", command);
if (strcmp(command, "exit") == 0) {
saveFileSystem(fs); // 在用户退出时保存文件系统状态
printf("User %s exited.\n", user->username);
break;
}
parseCommand(fs, user, command);
}
// 用户退出时,确保关闭所有用户打开的文件
int i;
for (i = 0; i < MAX_FILES_PER_USER; ++i) {
if (fs->userDirs[user->userId - 1].files[i].isOpen) {
closeFile(&fs->userDirs[user->userId - 1].files[i], fs);
}
}
}
int main() {
struct FileSystem fs;
initFileSystem(&fs);
struct User users[MAX_USERS];
for (int i = 0; i < MAX_USERS; ++i) {
sprintf(users[i].username, "User%d", i + 1);
users[i].userId = i + 1;
}
int userId;
do {
printf("Enter user ID (1 to %d, 0 to exit): ", MAX_USERS);
scanf("%d", &userId);
if (userId < 0 || userId > MAX_USERS) {
printf("Invalid user ID.\n");
continue;
}
if (userId == 0) {
printf("Exiting the file system.\n");
break; // 退出主程序循环
}
userInterface(&fs, &users[userId - 1]);
} while (1); // 主程序循环
return 0;
}
用户1创建一个个人文件
其他用户无法对其进行打开和其他操作
用户1创建一个共享文件
其他用户可以对其进行任意操作
一次只能打开一个文件