从 mmaped 结构数组中删除结构

Remove struct from mmaped array of structs

问题:我有一个名为 "med" 的结构来保存有关药物的信息(密钥、名称、最小数量和数量),每个药物都有一个唯一的密钥。我使用 mmap 将这些结构的数组存储在内存映射文件中。现在我想从数组中删除特定的 med(结构),但它不起作用...

代码:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#define NUM_MEDS 1000 
#define FILESIZE (NUM_MEDS * sizeof(struct med))

struct med
{
   int key;
   char name[25];
   int quant_min;
   int quant;
};

int main(void)
{
    int fd;
    int result;
    struct med *map;  /* mmapped array of structs */

    fd = open("meds.dat", O_RDWR | O_CREAT, (mode_t)0600);
    if (fd == -1)
    {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }

    result = ftruncate(fd, FILESIZE); 
    if (result == -1)
    {
        close(fd);
        perror("Error calling lseek() to 'stretch' the file");
        exit(EXIT_FAILURE);
    }

    /* Now the file is ready to be mmapped.  */
    map = (struct med *)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED)
    {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    struct med m;

    printf("Please enter the code of med: ");
    scanf("%d",&m.key);

    int j;
    for (j = 0; j < NUM_MEDS; j++)
    {
        if (m.key == map[j].key)
        {
            for(j; j < NUM_MEDS - 1; j++)
            {
            map[j] = map[j+1];
            }
            printf("Med %d removed with success\n",m.key);
            break;
        }
     }

     if (munmap(map, FILESIZE) == -1)
     {
         perror("Error un-mmapping the file");
     }

      close(fd);
      return 0;
}

有人可以帮忙吗?

功能上的实际变化?有一对。首先,在将数据复制到列表中后,必须使数据中的最后一个条目无效。其次,您必须在删除一些条目后重新计算条目数。

目前,除了 EOF 之外,您没有其他好的方法来停止输入。那意味着我用一个 运行 的程序添加了数据;然后我不得不 运行 程序第二次删除一些数据。但是,它似乎工作正常。我添加了键 1、2、3、4,然后删除了 2、4,剩下的列表是 1、3,这对我来说似乎是正确的。

我在回答相关问题 mmap and struct in C 后通过电子邮件询问了这个问题。

#define _XOPEN_SOURCE 800
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#define FILEPATH "/tmp/mmapped.bin"
#define NUM_MEDS 1000
#define FILESIZE (NUM_MEDS * sizeof(struct med))

struct med
{
    int key;
    char name[25];
    int quant_min;
    int quant;
};

static int find_num_entries(struct med *map, int max_meds);
static int get_new_key(struct med *map, int num_meds, int *key);
static int med_in_map(struct med *map, int num_meds, int key);
static int remove_key_med(struct med *map, int num_meds, int *key);
static int remove_med(struct med *map, int num_meds, int key);
static void insert_med_mmap(void);
static void interface(void);
static void list_meds_mmap(void);
static void load_meds_mmap(void);
static void print_med(char *tag, const struct med *med);
static void remove_med_mmap(void);
static void search_med_mmap(void);

int main(void)
{
    interface();
    return 0;
}

// interface
void interface(void)
{
    printf("\n");
    printf("=> Management and administration of Meds \n");
    printf("\n");
    printf("=> Mmap version \n");
    printf("\n");
    printf("Choose your operation \n");
    printf("1- Insert med \n");
    printf("2- Remove med \n");
    printf("3- Search med \n");
    printf("4- List meds ordered by name \n");
    printf("5- Load meds \n");
    printf("6- Exit \n");

    int a;
    scanf("%d", &a);
    switch (a)
    {
    case 1:
        printf("\n");
        printf("Insert med \n");
        insert_med_mmap();
        break;
    case 2:
        printf("\n");
        printf("Remove med \n");
        remove_med_mmap();
        break;
    case 3:
        printf("\n");
        printf("Search med \n");
        search_med_mmap();
        break;
    case 4:
        printf("\n");
        printf("List meds ordered by name \n");
        list_meds_mmap();
        break;
    case 5:
        printf("\n");
        load_meds_mmap();
        break;
    case 6:
        return;
    }
}

static void print_med(char *tag, const struct med *med)
{
    printf("%s: %4d: Q(%2d, min %2d): %s\n",
           tag, med->key, med->quant, med->quant_min, med->name);
}

static int med_in_map(struct med *map, int num_meds, int key)
{
    int i;
    for (i = 0; i < num_meds; i++)
    {
        if (key == map[i].key)
        {
            printf("The med with key %d already exists in the file. \n", key);
            return 1;
        }
    }
    return 0;
}

static int get_new_key(struct med *map, int num_meds, int *key)
{
    while (printf("Type the key of med: ") > 0 && scanf("%d", key) == 1)
    {
        if (med_in_map(map, num_meds, *key) == 0)
            return 0;
    }
    return EOF;
}

static int find_num_entries(struct med *map, int max_meds)
{
    int i;
    for (i = 0; i < max_meds; i++)
    {
        if (map[i].key == 0)
            break;
    }
    return i;
}

static int remove_med(struct med *map, int num_meds, int key)
{
    int i;
    for (i = 0; i < num_meds; i++)
    {
        if (key == map[i].key)
        {
            for ( ; i < num_meds - 1; i++)
            {
                map[i] = map[i + 1];
            }
            printf("Med %d removed with sucess\n", key);
            map[i].key = 0;
            map[i].name[0] = '[=10=]';
            map[i].quant = 0;
            map[i].quant_min = 0;
            return 0;
        }
    }
    return 1;
}

static int remove_key_med(struct med *map, int num_meds, int *key)
{
    while (printf("Type the key of med: ") > 0 && scanf("%d", key) == 1)
    {
        if (remove_med(map, num_meds, *key) == 0)
            return 0;
    }
    return EOF;
}

// load meds
void load_meds_mmap(void)
{
    printf("Test \n");
}

// insert med with mmap
void insert_med_mmap(void)
{
    int fd;
    int result;
    struct med *map;  /* mmapped array of structs */

    fd = open(FILEPATH, O_RDWR | O_CREAT, (mode_t)0600);
    if (fd == -1)
    {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }

    result = ftruncate(fd, FILESIZE);
    if (result == -1)
    {
        close(fd);
        perror("Error calling lseek() to 'stretch' the file");
        exit(EXIT_FAILURE);
    }

    map = (struct med *)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED)
    {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    /* Input loop */
    int num_meds;
    for (num_meds = find_num_entries(map, NUM_MEDS); num_meds < NUM_MEDS; num_meds++)
    {
        struct med m;
        memset(&m, '[=10=]', sizeof(m));

        if (get_new_key(map, num_meds, &m.key) == EOF)
            break;

        printf("Name of med: ");
        if (scanf("%s", m.name) != 1)
            break;
        printf("Quant. min. of med: ");
        if (scanf("%d", &m.quant_min) != 1)
            break;
        printf("Quant. of med: ");
        if (scanf("%d", &m.quant) != 1)
            break;

        map[num_meds] = m;

        printf("Med %d saved.\n", m.key);
    }

    /* Output loop */
    printf("\nRecorded meds:\n");
    int i;
    for (i = 0; i < num_meds; i++)
    {
        char buffer[32];
        snprintf(buffer, sizeof(buffer), "M%.4d", i);
        print_med(buffer, &map[i]);
    }

    /* Don't forget to free the mmapped memory */
    if (munmap(map, FILESIZE) == -1)
    {
        perror("Error un-mmapping the file");
        /* Decide here whether to close(fd) and exit() or not. Depends... */
    }

    /* Un-mmapping doesn't close the file, so we still need to do that.  */
    close(fd);
}

// remove med with mmap
void remove_med_mmap(void)
{
    int fd;
    int result;
    struct med *map;  /* mmapped array of structs */

    fd = open(FILEPATH, O_RDWR | O_CREAT, (mode_t)0600);
    if (fd == -1)
    {
        perror("Error opening file for writing");
        exit(EXIT_FAILURE);
    }

    result = ftruncate(fd, FILESIZE);
    if (result == -1)
    {
        close(fd);
        perror("Error calling lseek() to 'stretch' the file");
        exit(EXIT_FAILURE);
    }

    /* Now the file is ready to be mmapped.  */
    map = (struct med *)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (map == MAP_FAILED)
    {
        close(fd);
        perror("Error mmapping the file");
        exit(EXIT_FAILURE);
    }

    /* Input loop */
    int num_meds;
    for (num_meds = find_num_entries(map, NUM_MEDS); num_meds < NUM_MEDS; num_meds++)
    {
        struct med m;
        memset(&m, '[=10=]', sizeof(m));

        if (remove_key_med(map, num_meds, &m.key) == EOF)
            break;
    }

    /* Partial bug fix */
    num_meds = find_num_entries(map, NUM_MEDS);


    /* Output loop */
    printf("\nRecorded meds:\n");
    int i;
    for (i = 0; i < num_meds; i++)
    {
        char buffer[32];
        snprintf(buffer, sizeof(buffer), "M%.4d", i);
        print_med(buffer, &map[i]);
    }

    /* Don't forget to free the mmapped memory */
    if (munmap(map, FILESIZE) == -1)
    {
        perror("Error un-mmapping the file");
        /* Decide here whether to close(fd) and exit() or not. Depends... */
    }

    /* Un-mmapping doesn't close the file, so we still need to do that.  */
    close(fd);
    return;
}

void search_med_mmap(void)
{
    printf("Test \n");
}

void list_meds_mmap(void)
{
    printf("Test \n");
}