在C中删除文件的一部分

时间:2018-06-22 23:34:45

标签: c file delete-file overwrite

如何创建删除文件某些部分的功能?例如,文件为:

  

-。
  椅子:A23
  编号:123
  姓名:约书亚
  -。
  椅子:B12
  编号:512
  姓名:马库斯
  -。
  主席:C2
  编号:1
  名字:德雷克

如果输入为

  

B12

然后文件将变为

  

-。
  椅子:A23
  编号:123
  姓名:约书亚
  -。
  主席:C2
  编号:1
  名字:德雷克

我需要此功能才能使程序正常工作,但是我不知道该怎么做。

3 个答案:

答案 0 :(得分:2)

在与原始文件相同的目录中打开一个新文件。将要替换原始文件内容的内容写入该文件。关闭新文件。在原始文件的顶部重命名新文件。

但是也许您应该考虑使用数据库而不是文本文件。

答案 1 :(得分:1)

从面值考虑问题,请考虑使用以下组合:

  1. Write in the middle of a binary file without overwriting any existing content的相反语
  2. How to truncate a file in C?

您将使用步骤1的相反步骤,将文件末尾(要删除的部分之后)的资料复制到要删除的部分上,然后使用步骤2将文件大小设置为新的值。

或者,也许更简单地说,将要删除的零件之前和之后的材料复制到新文件中,然后将新文件(的内容)替换旧文件。

答案 2 :(得分:1)

您可以先将文件内容读入缓冲区。然后,您可以解析该缓冲区中的数据并将其插入到某些数据结构中,例如结构数组。一旦有了,就可以将过滤的内容重新写回到文件中。

下面是我之前写的一些示例代码(经过调整),它执行的操作与您想要的类似。它接受2个命令行争论作为输入。第一个是要读取的文件,第二个是不包括的数据(在您的情况下为chair值)。如果需要,您可以将其修改为从stdin读取。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define START_SIZE 10;
#define BASE 10

typedef struct {
    char *chair;
    int number;
    char *name;
} data_t;

typedef struct {
    data_t *data;
    size_t n;
} file_data_t;

char *get_file_contents(const char *);
file_data_t *insert_data(char *, const char *);

int main(int argc, char *argv[]) {

    // Check arguments
    if (argc != 3) {
        fprintf(stderr, "Usage: ./deletefile [file] [chair]\n");
        exit(EXIT_FAILURE);
    }

    // Get buffer
    char *buffer = get_file_contents(argv[1]);

    // Get structure holding data
    file_data_t *file_data = insert_data(buffer, argv[2]);

    // Free buffer
    free(buffer);

    // Open file to write to
    FILE *fp = fopen(argv[1], "w");
    if (fp == NULL) {
        fprintf(stderr, "Count not open file\n");
        exit(EXIT_FAILURE);
    }

    // Write to file, and free contents
    for (size_t i = 0; i < file_data->n; i++) {
        fprintf(fp, "-.\nChair: %s\nNumber: %d\nName: %s\n",
                    file_data->data[i].chair,
                    file_data->data[i].number,
                    file_data->data[i].name);

        free(file_data->data[i].chair);
        free(file_data->data[i].name);
    }

    // Free everything else
    free(file_data->data);
    free(file_data);

    fclose(fp);

    return EXIT_SUCCESS;
}

file_data_t *insert_data(char *buffer, const char *dont_keep) {
    size_t buffsize = START_SIZE;
    const char *delim_section = "-.", *delim_line = "\n";
    const char delim_colon = ':';
    char *token = NULL;
    char *rest = buffer;
    size_t count = 0;

    // Create main structure
    file_data_t *file_data = malloc(sizeof *file_data);
    if (file_data == NULL) {
        fprintf(stderr, "Could not allocate file data\n");
        exit(EXIT_FAILURE);
    }

    // Allocate data elements
    file_data->data = malloc(buffsize * sizeof *file_data->data);
    if (file_data->data == NULL) {
        fprintf(stderr, "Could not allocate %zu bytes for data\n", buffsize);
        exit(EXIT_FAILURE);
    }

    while ((token = strtok_r(rest, delim_section, &rest)) != NULL) {

        // Reallocate data if necessary
        if (count == buffsize) {
            buffsize *= 2;
            void *ptr = realloc(file_data->data, buffsize * sizeof *file_data->data);
            if (ptr == NULL) {
                fprintf(stderr, "Could not reallocate %zu bytes for buffer\n", buffsize);
                exit(EXIT_FAILURE);
            }

            file_data->data = ptr;
        }

        char *saveptr = NULL, *endptr = NULL;

        // Parse chair
        char *chair = strtok_r(token, delim_line, &saveptr);
        char *chair_value = strchr(chair, delim_colon);
        chair_value += 2;

        // If chair value is not the same as dont_keep, proceed
        if (strcmp(chair_value, dont_keep) != 0) {

            // Copy chair value over
            file_data->data[count].chair = strdup(chair_value);
            if (file_data->data[count].chair == NULL) {
                fprintf(stderr, "Could not copy chair buffer\n");
                exit(EXIT_FAILURE);
            }

            // Parse number
            char *number = strtok_r(NULL, delim_line, &saveptr);
            char *number_value = strchr(number, delim_colon);
            number_value += 2;

            // Convert number to integer
            long val = strtol(number_value, &endptr, BASE);

            // Didnt find a value number
            if (endptr == number_value || *endptr  != '\0') {
                fprintf(stderr, "Count not parse number\n");
                exit(EXIT_FAILURE);
            }

            // Add number value
            file_data->data[count].number = val;

            // Parse name
            char *name = strtok_r(NULL, delim_line, &saveptr);
            char *name_value = strchr(name, delim_colon);
            name_value += 2;

            // Copy name over
            file_data->data[count].name = strdup(name_value);
            if (file_data->data[count].name == NULL) {
                fprintf(stderr, "Coul not copy name buffer\n");
                exit(EXIT_FAILURE);
            }

            // Increment count
            count++;
        }
    }

    file_data->n = count;

    return file_data;
}

char *get_file_contents(const char *path) {

    // Open file
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        fprintf(stderr, "Failed to open %s\n", path);
        exit(EXIT_FAILURE);
    }

    // Go to end of file
    int end = fseek(fp, 0L, SEEK_END);
    if (end != 0) {
        fprintf(stderr, "Could not go to end of file\n");
        exit(EXIT_FAILURE);
    }

    // Get size of file
    long buffsize = ftell(fp);
    if (buffsize == -1) {
        fprintf(stderr, "Count not get size of file\n");
        exit(EXIT_FAILURE);
    }

    // Allocate buffer
    char *buffer = malloc(buffsize + 1);
    if (buffer == NULL) {
        fprintf(stderr, "Could not allocate %ld bytes for buffer\n", buffsize);
        exit(EXIT_FAILURE);
    }

    // Go back to start of file
    int start = fseek(fp, 0L, SEEK_SET);
    if (start != 0) {
        fprintf(stderr, "Could not go to start of file\n");
        exit(EXIT_FAILURE);
    }

    // Read contents of file
    size_t newlen = fread(buffer, 1, buffsize, fp);
    if (ferror(fp) != 0) {
        fprintf(stderr, "Error reading contents of file into buffer\n");
        exit(EXIT_FAILURE);
    }

    fclose(fp);

    // Null terminate buffer
    buffer[newlen++] = '\0';

    return buffer;
}

输出:

$ cat file.txt
-.
Chair: A23
Number: 123
Name: Joshua
-.
Chair: B12
Number: 512
Name: Marcus
-.
Chair: C2
Number: 1
Name: Drake
$ gcc -Wall -Wextra -o deletefile deletefile.c
$ ./deletefile file.txt B12
$ cat file.txt
-.
Chair: A23
Number: 123
Name: Joshua
-.
Chair: C2
Number: 1
Name: Drake

注意:上面的代码并不是执行此任务的最佳方法,当然可以进行改进。您可以以此为基础,并加以改进。