# 分布式冗余存储系统,Microsoft visual studio 2022,C语言版

分布式冗余存储系统,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的问题,大概就这样:
使用示例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值