分布式冗余存储系统,Microsoft visual studio 2022,C语言版
主函数
#include<stdio.h>
#include<stdlib.h>
void main() {
printf("这是一个文件分布式冗余存储的程序:\n存文件输入1,取文件输入2,查看输入3,删除输入4,退出程序输入0\n");
int a = 0;
while (1) {
printf("\n\n\n");
printf("您想进行什么操作?");
scanf_s("%d", &a);
if (a == 0) { printf("下次再见!"); break; }
switch (a)
{
case 1:
storage();
continue;
case 2:
read();
continue;
case 3:
look();
continue;
case 4:
dismiss();
continue;
default:
printf("不是哥们\n");
printf("存文件输入1,取文件输入2,查看输入3,删除输入4,退出程序输入0\n");
}
}
}
存储模块
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <sys/stat.h>
#include "cJSON.h"
#define kid 16777216
char* generate_unique_random(cJSON* root);
char* getFileName();
void confirmlocation(const char* inputStr, const char* disk0, const char* disk1, const char* disk2, char** c, char** d);
char* get_file_suffix(const char* filename, char* suffix, size_t suffix_size);
int is_random_in_filenames(cJSON* root, const char* random_str);
void got_filename(const char* filepath, char* filename, size_t max_len);
int storage(void)
{
cJSON* root = NULL;
// 打开文件
FILE* save = NULL;
fopen_s(&save,"save.json", "a+");
// 获得文件大小
struct stat statbuf;
stat("save.json", &statbuf);
int sizeJ = statbuf.st_size;
if (sizeJ == 0) { root = cJSON_CreateObject(); }
else {
// 分配符合文件大小的内存
char* jsonStr = (char*)malloc(sizeof(char) * sizeJ + 1);
memset(jsonStr, 0, sizeJ + 1);//初始化内存,全部写入0
fread(jsonStr, sizeof(char), sizeJ, save);
root = cJSON_Parse(jsonStr);// 获得json根对象
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
}
fclose(save);
FILE* fp = NULL;
FILE* fp1 = NULL;
FILE* fp2 = NULL;
char* c = NULL;
char* d = NULL;
char Location0[1024];
char Location1[1024];
char Location2[1024];
char fileLocation[1024];
printf("输入第一个存储位置,以双斜杠结尾:");
scanf_s("%1023s", Location0, _countof(Location0)); // 使用_countof宏确保安全
printf("输入第二个存储位置,以双斜杠结尾:");
scanf_s("%1023s", Location1, _countof(Location1)); // 使用_countof宏确保安全
printf("输入第三个存储位置,以双斜杠结尾:");
scanf_s("%1023s", Location2, _countof(Location2)); // 使用_countof宏确保安全
const char* diskLocation0 = Location0;
const char* diskLocation1 = Location1;
const char* diskLocation2 = Location2;
errno_t err;
long int size;
char* Buffer = NULL;
while (1) {
printf("输入文件位置(不含空格,使用双斜杠分隔符,不要重复存储同一个文件),输入#表示结束存储操作:\n");
scanf_s("%1023s", fileLocation, _countof(fileLocation)); // 使用_countof宏确保安全
if (fileLocation[0] == '#') { break; }
cJSON* bigFile = cJSON_CreateObject();
char suffix[10]; // 一般后缀名不会超过10个字符,吧(包括点)
char* sp = get_file_suffix(fileLocation, suffix, sizeof(suffix));
if (sp != NULL) {
printf("文件后缀名是:%s\n", suffix);
}
else {
printf("未找到文件后缀名,请重试\n");
continue;
}
// 以二进制方式打开文件
err = fopen_s(&fp, fileLocation, "rb");
if (err != 0 || fp == NULL) {
perror("文件不存在,请重试");
continue;
}
// 获取文件大小
fseek(fp, 0, SEEK_END);
size = ftell(fp);
rewind(fp);
printf("文件大小是:%ld 字节\n", size);
Buffer = (char*)malloc(kid * sizeof(char));
if (Buffer == NULL) {
perror("Memory allocation failed");
fclose(fp);
return EXIT_FAILURE;
}
int circle = size / kid;
if (size % kid != 0) { circle++; }
for (int i = 0; i < circle; i++) {
size_t bytesToRead = kid;
char key[10]; // 使用数组而不是指针,以便可以修改
sprintf_s(key, sizeof(key), "%d", i); // 生成键,如"0", "1", "2", ... //把数字转化为字符
if (i == circle - 1 && size % kid != 0) {
bytesToRead = size % kid; // 最后一个块的大小可能小于child
}
if (fread(Buffer, 1, bytesToRead, fp) != bytesToRead) {
perror("Failed to read file");
free(Buffer);
fclose(fp);
continue;
}
cJSON* address = cJSON_CreateArray();
confirmlocation(suffix, diskLocation0, diskLocation1, diskLocation2, &c, &d);
cJSON_AddItemToArray(address, cJSON_CreateString(c));
cJSON_AddItemToArray(address, cJSON_CreateString(d));
cJSON_AddItemToObject(bigFile, key, address); // 使用生成的键
if(i==0){ cJSON_AddItemToObject(root, fileLocation, bigFile); }
else {
cJSON_ReplaceItemInObject(root, fileLocation, bigFile);
}
char* cPrint = cJSON_Print(root); // 格式化的 JSON 字符串
if (cPrint == NULL) {
printf("Failed to print cJSON.\n");
cJSON_Delete(root);
return EXIT_FAILURE;
}
// 打开文件覆写 JSON 数据
FILE* file = NULL;
errno_t erro = fopen_s(&file, "save.json", "w"); // "w" 模式表示覆写
if (erro != 0 || file == NULL) {
printf("Failed to open file: save.json\n");
free(cPrint); // 释放打印缓冲区
cJSON_Delete(root); // 删除 JSON 根对象
return EXIT_FAILURE;
}
// 写入 JSON 数据到文件
if (fputs(cPrint, file) == EOF) {
printf("Failed to write JSON data to file.\n");
fclose(file);
free(cPrint);
cJSON_Delete(root);
return EXIT_FAILURE;
}
fclose(file); // 关闭文件
free(cPrint); // 释放打印缓冲区
// 写入第一个文件
err = fopen_s(&fp1, c, "wb");
if (err != 0 || fp1 == NULL) {
perror("Output file opening failed");
free(Buffer);
continue;
}
if (fwrite(Buffer, 1, bytesToRead, fp1) != bytesToRead) {
perror("Failed to write to file");
free(Buffer);
fclose(fp1);
continue;
}
// 写入第二个文件
err = fopen_s(&fp2, d, "wb");
if (err != 0 || fp2 == NULL) {
perror("Output file opening failed");
free(Buffer);
continue;
}
if (fwrite(Buffer, 1, bytesToRead, fp2) != bytesToRead) {
perror("Failed to write to file");
free(Buffer);
fclose(fp2);
continue;
}
//printf("%s\n", c);
free(c);
free(d);
fclose(fp1);
fclose(fp2);
}
printf("文件存储成功\n");
fclose(fp);
free(Buffer);
}
/* 打印 JSON 内容到控制台
char* cPrint = cJSON_Print(root); // 格式化的 JSON 字符串
if (cPrint == NULL) {
printf("Failed to print cJSON.\n");
cJSON_Delete(root);
return EXIT_FAILURE;
}
printf("cJSON_Print:\n%s\n", cPrint); // 打印格式化的 JSON 到控制台*/
cJSON_Delete(root); // 删除 JSON 根对象
return 0;
}
// 函数用于获取文件后缀名
char* get_file_suffix(const char* filename, char* suffix, size_t suffix_size) {
const char* dot = strrchr(filename, '.');
if (dot == NULL || dot == filename || *(dot - 1) == '\\' || *(dot - 1) == '/') {
return NULL;
}
size_t len = strlen(dot);
if (len >= suffix_size) {
return NULL;
}
strncpy_s(suffix, suffix_size, dot, len);
suffix[len] = '\0';
return suffix;
}
// 字符串操作确定存储位置
void confirmlocation(const char* inputStr, const char* disk0, const char* disk1, const char* disk2, char** c, char** d) {
char locationStr1[1024];
char locationStr2[1024];
const char* Name = getFileName();
int a = rand() % 3;
int b = rand() % 3;
while (a == b) {
b = rand() % 3;
}
switch (a) {
case 0:
strcpy_s(locationStr1, sizeof(locationStr1), disk0);
break;
case 1:
strcpy_s(locationStr1, sizeof(locationStr1), disk1);
break;
case 2:
strcpy_s(locationStr1, sizeof(locationStr1), disk2);
break;
}
strcat_s(locationStr1, sizeof(locationStr1), Name);
strcat_s(locationStr1, sizeof(locationStr1), inputStr);
switch (b) {
case 0:
strcpy_s(locationStr2, sizeof(locationStr2), disk0);
break;
case 1:
strcpy_s(locationStr2, sizeof(locationStr2), disk1);
break;
case 2:
strcpy_s(locationStr2, sizeof(locationStr2), disk2);
break;
}
strcat_s(locationStr2, sizeof(locationStr2), Name);
strcat_s(locationStr2, sizeof(locationStr2), inputStr);
*c = _strdup(locationStr1);
*d = _strdup(locationStr2);
if (*c == NULL || *d == NULL) {
fprintf(stderr, "Memory allocation failed\n");
exit(EXIT_FAILURE);
}
}
// 从完整路径中提取文件名
void got_filename(const char* filepath, char* filename, size_t max_len) {
const char* start = strrchr(filepath, '\\'); //找最后一个双斜杠
if (start == NULL) {
start = filepath; // 无
}
else {
start++; // 跳过此双斜杠
}
const char* end = strrchr(start, '.'); // 找点
size_t len = (end != NULL) ? (size_t)(end - start) : strlen(start);
if (len >= max_len) {
len = max_len - 1; //限长
}
strncpy_s(filename, max_len, start, len);
filename[len] = '\0'; //结束加杠0
}
// 检查是否重复
int is_random_in_filenames(cJSON* root, const char* random_str) {
cJSON* file = NULL;
cJSON* fileData = NULL;
char filename[256];
// 遍历每个文件(根对象中的键值对)
cJSON_ArrayForEach(file, root) {
// 遍历文件的关联对象
cJSON_ArrayForEach(fileData, file) {
//获取已有文件名
if (!cJSON_IsArray(fileData)) {
continue; // Skip if it's not an array
}
// 遍历数组中的文件路径
cJSON* pathItem = NULL;
cJSON_ArrayForEach(pathItem, fileData) {
// 获取文件路径并提取不带扩展名的文件名
got_filename(pathItem->valuestring, filename, sizeof(filename));
// 比较
if (strcmp(filename, random_str) == 0) {
return 1; // Found a match
}
}
}
}
return 0; // No match found
}
// 产生不重复的随机数
char* generate_unique_random(cJSON* root) {
static char random_str[10]; // Buffer to store the random number as a string
srand((unsigned int)time(NULL)); // Seed the random number generator
while (1) {
int random_num1 = rand() % 1000; // Generate a random number (0-999)
int random_num2 = rand() % 1000; // Generate a random number (0-999)
long long int random_num = random_num1* random_num2;
sprintf_s(random_str, sizeof(random_str), "%lld", random_num); // Convert the number to a string
// Check if this random number matches any file names
if (!is_random_in_filenames(root, random_str)) {
break; // No match, so it's a valid random number
}
}
return random_str; // Return the random number as a string
}
//确定文件名
char* getFileName() {
char* random_str = "123456";
// Load JSON file content
FILE* file = fopen("save.json", "r");
if (!file) {
return random_str;
}
fseek(file, 0, SEEK_END);
long length = ftell(file);
fseek(file, 0, SEEK_SET);
char* data = (char*)malloc(length + 1);
if (!data) {
fclose(file);
return random_str;
}
fread(data, 1, length, file);
data[length] = '\0'; // Null-terminate the JSON string
fclose(file);
// Parse the JSON content
cJSON* root = cJSON_Parse(data);
if (root == NULL) {
free(data);
return random_str;
}
// Generate a unique random number
random_str = generate_unique_random(root);
return random_str;
}
恢复模块
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <sys/stat.h>
#include "cJSON.h"
char* get_fileName(const char* filename, char* name, size_t name_size);
void write(cJSON* root, FILE* bigFile,char a[]);
int read() {
cJSON* root = NULL;
// 打开文件
FILE* save = NULL;
fopen_s(&save, "save.json", "a+");
// 获得文件大小
struct stat statbuf;
stat("save.json", &statbuf);
int sizeJ = statbuf.st_size;
if (sizeJ == 0||sizeJ == 4) {
printf("这里什么也没有\n");
fclose(save);
return 0;
}
else {
// 分配符合文件大小的内存
char* jsonStr = (char*)malloc(sizeof(char) * sizeJ + 1);
memset(jsonStr, 0, sizeJ + 1);
fread(jsonStr, sizeof(char), sizeJ, save);
root = cJSON_Parse(jsonStr);// 获得json根对象
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
}
fclose(save);
char fileLocation[1024];
char saveLocation[1024];
char fullLocation[1024];
const char* fullName= saveLocation;
while (1) {
printf("请输入要恢复的文件原始地址(不含空格,使用双斜杠分隔符),输入#表示结束恢复操作:\n");
scanf_s("%1023s", fileLocation, _countof(fileLocation)); // 使用_countof宏确保安全
if (fileLocation[0] == '#') { break; }
char name[1024];
char* sp = get_fileName(fileLocation, name, sizeof(name));
if (sp == NULL) {
printf("文件名不合法");
continue;
}
printf("输入恢复文件存储位置,以双斜杠结尾:");
scanf_s("%1023s", saveLocation, _countof(saveLocation)); // 使用_countof宏确保安全
strcpy_s(fullLocation, sizeof(fullLocation), fullName);
strcat_s(fullLocation, sizeof(fullLocation), sp);
FILE* fp = NULL;
errno_t erro = fopen_s(&fp,fullLocation, "ab");
if (erro != 0 || fp== NULL) {
printf("Failed to open file\n");
cJSON_Delete(root); // 删除 JSON 根对象
return EXIT_FAILURE;
}
write(root, fp,fileLocation);
fclose(fp);
}
cJSON_Delete(root);
return 0;
}
char* get_fileName(const char* filename, char* name, size_t name_size) {
const char* slashes = strrchr(filename, '\\');
size_t len = strlen(slashes);
if (len >= name_size) {
return NULL;
}
strncpy_s(name, name_size, slashes, len);
name[len] = '\0';
return name;
}
void write(cJSON* root,FILE* bigFile,char a[]) {
cJSON* fileData = NULL;
cJSON* item = NULL;
char filename1[256];
char filename2[256];
FILE* fp = NULL;
char* Buffer = (char*)malloc(16777216 * sizeof(char));
// 遍历每个文件(根对象中的键值对)
item = cJSON_GetObjectItem(root, a);
// 遍历文件的关联对象
cJSON_ArrayForEach(fileData, item) {
//获取已有文件名
if (!cJSON_IsArray(fileData)) {
continue; // Skip if it's not an array
}
// 遍历数组中的文件路径
cJSON* pathItem = NULL;
cJSON_ArrayForEach(pathItem, fileData) {
errno_t erro = fopen_s(&fp, pathItem->valuestring, "rb");
if (erro != 0 || fp == NULL) {
continue;
}
got_filename(pathItem->valuestring, filename1, sizeof(filename1));
struct stat statbuf;
stat(pathItem->valuestring, &statbuf);
int size = statbuf.st_size;
if (fread(Buffer, 1, size, fp) != size) {
fclose(fp);
continue;
}
if (strcmp(filename1,filename2) == 0) {
fclose(fp);
continue; // match
}
fwrite(Buffer, 1, size, bigFile);
strcpy_s(filename2, sizeof(filename2),filename1);
fclose(fp);
}
}
}
查看模块
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <sys/stat.h>
#include "cJSON.h"
int look() {
cJSON* file = NULL;
cJSON* fileArray = NULL;
cJSON* root = NULL;
// 打开文件
FILE* save = NULL;
fopen_s(&save, "save.json", "a+");
// 获得文件大小
struct stat statbuf;
stat("save.json", &statbuf);
int sizeJ = statbuf.st_size;
if (sizeJ == 0||sizeJ == 4) {
printf("这里什么也没有\n");
fclose(save);
return 0;
}
else {
// 分配符合文件大小的内存
char* jsonStr = (char*)malloc(sizeof(char) * sizeJ + 1);
memset(jsonStr, 0, sizeJ + 1);
fread(jsonStr, sizeof(char), sizeJ, save);
root = cJSON_Parse(jsonStr);// 获得json根对象
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
}
fclose(save);
printf("已存储的文件有:\n");
// Iterate through each key-value pair in the JSON object
cJSON_ArrayForEach(file, root) {
// Get the array of file paths associated with this key
fileArray = cJSON_GetObjectItem(root, file->string);
printf("%s\n", file->string);
/* Iterate through the file paths in the array
cJSON* pathItem = NULL;
cJSON_ArrayForEach(pathItem, fileArray) {
printf("%s\n", *(pathItem->valuestring));
}*/
}
cJSON_Delete(root); // 删除 JSON 根对象
return 0;
}
删除模块
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <sys/stat.h>
#include "cJSON.h"
int dismiss() {
cJSON* root = NULL;
// 打开文件
FILE* save = NULL;
fopen_s(&save, "save.json", "a+");
// 获得文件大小
struct stat statbuf;
stat("save.json", &statbuf);
int sizeJ = statbuf.st_size;
if (sizeJ == 0 || sizeJ == 4) {
printf("这里什么也没有\n");
fclose(save);
return 0;
}
else {
// 分配符合文件大小的内存
char* jsonStr = (char*)malloc(sizeof(char) * sizeJ + 1);
memset(jsonStr, 0, sizeJ + 1);
fread(jsonStr, sizeof(char), sizeJ, save);
root = cJSON_Parse(jsonStr);// 获得json根对象
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
}
fclose(save);
cJSON* fileData = NULL;
cJSON* item = NULL;
char filename[1024];
FILE* fp = NULL;
while (1) {
printf("请输入要删除的文件原始地址(不含空格,使用双斜杠分隔符),输入#表示结束删除操作:\n");
scanf_s("%1023s", filename, _countof(filename)); // 使用_countof宏确保安全
if (filename[0] == '#') { break; }
// 找到根对象中的键值对
item = cJSON_GetObjectItem(root, filename);
// 遍历文件的关联对象并删除
cJSON_ArrayForEach(fileData, item) {
//获取已有文件名
// 遍历数组中的文件路径
cJSON* pathItem = NULL;
cJSON_ArrayForEach(pathItem, fileData) {
remove(pathItem->valuestring);
}
}
cJSON_DeleteItemFromObject(root, filename);
// 打开文件
errno_t erro = fopen_s(&fp, "save.json", "w");
if (fp == NULL) {
printf("Open file fail!\n");
// 释放指针内存
cJSON_Delete(root);
return;
}
char* cjValue = cJSON_Print(root);
// 写入文件
int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), fp);
if (ret == 0) {
printf("写入文件失败!\n");
}
fclose(fp);
free(cjValue);
}
return 0;
}
注意,需要自行弄好cjson的问题,大概就这样: