Pregunta

estoy desarrollando una aplicación de base de datos similar que almacena un una estructura que contiene:

struct Dictionary
{
    char *key;
    char *value;

    struct Dictionary *next;
};

Como se puede ver, estoy usando una lista enlazada para almacenar la información. Pero el problema comienza cuando el usuario sale del programa. Quiero que la información que se almacena en alguna parte. Así que estaba pensando de almacenar la lista enlazada en un archivo permanente o temporal con fopen, a continuación, cuando el usuario inicia el programa, recuperar la lista enlazada. Este es el método que imprime la lista enlazada a la consola:

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;
    }
}

Así que estoy pensando en la modificación de este método para imprimir la información a través de fprintf en lugar de printf y luego el programa que acaba de obtener la infomación del archivo. Es posible que alguien me ayuda sobre cómo puedo leer y escribir en este archivo? ¿Qué tipo de archivo debe ser, temporal o regular? ¿Cómo debo formatear el archivo (como si estuviera pensando en sólo tener la llave en primer lugar, a continuación, el valor, entonces un carácter de nueva línea)?

¿Fue útil?

Solución

El archivo probablemente debe ser regular. Un archivo temporal no está garantizada para estar allí la próxima vez que inicie su aplicación. Además, su formato no se ve bien para los seres humanos, no tan bien para las máquinas. Me gustaría recomendar o bien crear su propio formato de archivo binario o el uso de XML (o tal vez JSON?). Probablemente se podría formatearlo con bastante facilidad como

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

voy a escribir un ejemplo rápido es el código 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;
}

Yo sé que es un mal ejemplo. Creo que scanf o similares pueden hacer el trabajo de una tonelada más fácil, pero mis conocimientos de C están recibiendo oxidada.

Otros consejos

El problema fundamental es que los punteros no se traducen en almacenamiento externo. No hay garantía de que cuando se ejecuta el programa de nuevo, que tendrá los mismos rangos de memoria (direcciones). Teniendo en cuenta este principio, existen métodos alternativos a almacenar sus datos.

Procesos para los datos persistentes:
1. Uso de una base de datos, pequeño o grande.
2. Convertir los datos en texto ASCII en un formato susceptible de ser analizada.
3. Uso fijado registros binarios de longitud
4. Uso de tamaño variable registros binarios
5. Implementar una estructura de datos utilizando el diccionario de desplazamientos de archivo en lugar de punteros.

Uso de una base de datos
Dejar que una aplicación profesional (que ha sido probado y funciona) administrar sus datos. Esto le permite concentrarse en el uso de los datos en lugar de almacenamiento y retreival.

Convertir a un formato susceptible de ser analizada
La idea aquí es escribir los datos en el archivo en un formato que es fácil de recuperar y mantener. Los ejemplos incluyen valores separados por comas (CSV), XML y INI. Esto requiere código de su parte para leer y escribir los datos. Hay bibliotecas para ayudar.

Uso fijado registros binarios de longitud
Con registros de longitud fija, los datos se leen desde el archivo y se inserta en su diccionario. Los archivos binarios son muy eficientes como los datos de la medida de lo transfieren, pero no es muy portátil, especialmente cuando se opera el cambio versiones de sistemas, plataformas cambian o cambio de versiones del compilador. Puede haber una pérdida de espacio para los registros de texto.

Uso de tamaño variable registros binarios
Esta técnica permite ahorrar espacio, pero aumenta el tiempo de procesamiento. Cada registro debe ser procesado con el fin de encontrar la ubicación de la siguiente. El acceso aleatorio a los registros es difícil. Por lo demás similares a los registros binarios de longitud fija.

Implementar una estructura de datos en el archivo de diccionario
Mismo algoritmo que la estructura de datos basada memoria excepto desplazamientos de archivo usos en lugar de punteros. Nuevos registros pueden ser añadidos al final del archivo. La recuperación de las entradas eliminadas es difícil y dará lugar a la fragmentación. La fragmentación puede ser resuelto por escribir un nuevo archivo. Si usted está pasando por este gran esfuerzo, que también podría utilizar también una aplicación de base de datos existente.

Una forma puede leer o escribir en el fichero está utilizando fReopen como esto: freopen ( "file.out", "peso", la salida estándar), entonces estás de printf irá al file.out y usted no tendrá que modificar el código mucho.

Se puede almacenar la información en texto plano, pero realmente creo que la mejor manera de hacer esto es guardar la información en un archivo binario. Puede ver más información acerca de esta búsqueda sobre fread y fwrite.

Aquí hay una manera de resolver el problema.

Crear una estructura de datos para la lista de este tipo de elementos:

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

tendrá que determinar los valores de MAX_KEY_LENGTH y MAX_VALUE_LENGTH acuerdo con los datos que se le esperaba.

Ahora, convertir su lista enlazada en una matriz de estas estructuras. En lugar de almacenar un puntero para localizar el siguiente punto, se va a almacenar el índice de matriz del siguiente elemento. Esto convierte su lista en un formato donde cada elemento es un tamaño predecible su lista entera es un tramo consecutivo de memoria. Ahora, puede fwrite esta matriz a un archivo binario para archivarlo, y fread de nuevo a restaurarlo.

Una alternativa mucho más eficiente con el espacio al uso de matrices de tamaño fijo char anterior es para definir su lugar un formato de archivo personalizado en lugar de utilizar las estructuras estáticas. Para su caso, se puede utilizar un formato de archivo como este para almacenar sus datos de forma recuperable:

  • La lista se escribe en el archivo en orden, empezando por la cabeza y siguiendo los punteros next a la cola
  • Cada elemento de la lista se almacena utilizando cuatro campos de datos en el siguiente orden:
    1. entero de 16 bits, key_length
    2. matriz de caracteres de 8 bits con elementos key_length, key_data
    3. entero de 16 bits, value_length
    4. matriz de caracteres de 8 bits con elementos value_length, value_data

Ahora, se puede caminar a la lista, el vertido de sus datos al nodo de archivos por nodo. Para volver a construir sus datos, leer el archivo binario, generar nuevos elementos struct Dictionary para cada entrada, y vincularlos juntos en el orden en que aparecen en el archivo.

Su código para escribir los datos en el archivo de datos se vería algo como esto (no probado, a modo de ilustración):

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);

Su código para leer la salida de datos sería muy similar (en lugar de leer escribir y crear un nuevo objeto struct Dictionary para cada iteración del bucle).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top