我正在开发一个类似数据库的应用程序,它存储一个包含以下内容的结构:

struct Dictionary
{
    char *key;
    char *value;

    struct Dictionary *next;
};

如您所见,我使用链接列表来存储信息。但当用户退出程序时问题就开始了。我希望将信息存储在某个地方。所以我正在考虑使用 fopen 将链表存储在永久或临时文件中,然后,当用户启动程序时,检索链表。以下是将链表打印到控制台的方法:

void PrintList()
{
    int count = 0;
    struct Dictionary *current;

    current = head;

    if (current == NULL)
    {
            printf("\nThe list is empty!");
        return;
    }

    printf("    Key \t  Value\n");
    printf("  ======== \t ========\n");

    while (current != NULL)
    {
        count++;
        printf("%d.  %s \t %s\n", count, current->key, current->value);
        current = current->next;
    }
}

所以我正在考虑修改这个方法,通过 fprintf 而不是 printf 打印信息,然后程序就从文件中获取信息。有人可以帮助我如何读取和写入该文件吗?它应该是什么类型的文件,临时文件还是常规文件?我应该如何格式化文件(就像我想先有键,然后是值,然后是换行符)?

有帮助吗?

解决方案

在文件也许应该是有规律的。一个临时文件不能保证下一次你启动应用程序在那里。此外,您的格式有看起来很好的人,没有那么精细的机器。我建议无论是创建自己的二进制文件格式,或使用XML(或者JSON?)。你也许可以很容易地像格式化

key1\0value1\0key2\0value2\0....

我会写一个简单的例子是psuedoish代码:

//To write...
Dictionary *this=begin_list;
while(this!=null){
  for(i=0;i<strlen(this->key);i++){
    write_byte(this->key[i]);
  }
  for(i=0;i<strlen(this->value);i++){
    write_byte(this->value[i]);
  }
  this=this->next;
}

//to read...
Dictionary *prev;
Dictionary *this;
char *buffer;
while(!eof){
  buffer=malloc(MAX_STRING_LEN);
  int i=0;
  this=malloc(sizeof(Dictionary)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break;
    }
  }
  this->key=buffer;
  buffer=malloc(MAX_STRING_LEN)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break; 
    }
  }
  this->value=buffer;
  if(prev!=null){
    prev->next=this;
  }
  this->next=null;
  prev=this;
}

我知道这是一个坏榜样。我认为,scanf或类似可以使工作一吨更容易,但我的C技能生锈。

其他提示

在根本问题是指向没有转换到外部存储。谁也不能保证,当你的程序再次执行,将具有相同的内存范围(地址)。鉴于这一原则上,有可替代的方法来存储数据。

作为持续性数据的过程:结果 1.使用一个数据库,或大或小。结果 2.将您的数据放入一个可扫描格式的ASCII文本。点击 3.使用固定长度二进制记录结果 4.使用大小可变的二进制记录结果 5.使用文件偏移量,而不是指针实现一个字典的数据结构。

是一个数据库结果 让专业的应用程序(即已经过测试和工程)管理您的数据。这让您专注于使用数据,而不是存储与retreival。

<强>转换为可扫描格式结果 这里的想法是将数据写入到文件中的格式,可以方便地检索和维护。实例包括逗号分隔值(CSV),XML和INI。这需要你的一部分代码读取和写入数据。有库,以协助。

使用固定长度的二进制记录结果 对于固定长度的记录,该数据从文件中读取并插入到你的字典。二进制文件是尽可能将数据传输效率很高,但不是很便携,尤其是操作系统版本变化时,平台更改或编译器版本的变化。可以存在的浪费空间的文本记录。

使用可变大小的二进制记录结果 这种技术可以节省空间,但会增加处理时间。每个记录必须以寻找下一个位置进行处理。记载随机访问是困难的。否则,类似的固定长度二进制记录。

<强>文件中实现一个字典的数据结构结果 同样的算法,只是使用文件偏移量,而不是指针,你的记忆为基础的数据结构。新的记录可以附加到文件的末尾。回收删除的条目是困难的,会导致碎片。碎片可以通过写一个新的文件来解决。如果你正在经历这么多的努力,你还不如用现有的数据库应用程序。

您可以读取或写入该文件的方法是使用freopen函数是这样的: freopen函数(“file.out”,“重量”,标准输出),那么你的printf的必去的file.out,你不需要修改代码了很多东西。

您可以明文存储的信息,但我真的认为,要做到这一点,最好的办法是保存在一个二进制文件的信息。 您可以更检查出约约FREAD和fwrite这个搜索信息。

这是解决问题的一种方法。

为列表项创建一个数据结构,如下所示:

struct DictionaryArchive {
    char key[MAX_KEY_LENGTH];
    char value[MAX_VALUE_LENGTH];
    int next;
};

您需要确定以下值 MAX_KEY_LENGTHMAX_VALUE_LENGTH 根据您预期的数据。

现在,将链接列表转换为这些结构的数组。您将存储下一项的数组索引,而不是存储用于定位下一项的指针。这会将您的列表转换为一种格式,其中每个元素的大小都是可预测的,您的整个列表是一个连续的内存范围。现在你可以 fwrite 将此数组保存为二进制文件以将其存档,并且 fread 它退出以恢复它。

比使用固定大小更节省空间的替代方案 char 上面的数组是定义自定义文件格式而不是使用静态结构。对于您的情况,您可以使用如下文件格式以可检索的方式存储数据:

  • 该列表按顺序写入文件,从头开始,然后是 next 指向尾部的指针
  • 每个列表项将使用四个数据字段按以下顺序存储:
    1. 16位整数, key_length
    2. 8 位字符数组 key_length 元素, key_data
    3. 16位整数, value_length
    4. 8 位字符数组 value_length 元素, value_data

现在,您可以遍历列表,将数据逐个节点转储到文件中。要重新构建数据,请通读二进制文件,生成新的 struct Dictionary 每个条目的元素,并按照它们在文件中出现的顺序将它们链接在一起。

将数据写入数据文件的代码将如下所示(未经测试,仅用于说明目的):

FILE* fd;
size_t len;
struct Dictionary* pDict = list_head;
fd = fopen("output_file.dat", "w");

// Walk through the list, storing each node
while (pDict != NULL) {
    // Store key
    len = strlen(pDict->key);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->key, len, sizeof(char), fd);

    // Store value
    len = strlen(pDict->value);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->value, len, sizeof(char), fd);

    // Move to next list node
    pDict = pDict->next;
};

fclose(fd);

您读取数据的代码将非常相似(读取而不是写入,并创建一个新的 struct Dictionary 每次循环迭代的对象)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top