Pregunta

Estoy usando fwrite() y fread() por primera vez a escribir algunas estructuras de datos en el disco y tengo un par de preguntas sobre las mejores prácticas y formas correctas de hacer las cosas.

Lo que estoy escribiendo en el disco (lo que más tarde pueda leer de nuevo) es todos los perfiles de usuario insertados en una estructura gráfico. Cada vértice gráfica es del tipo siguiente:

typedef struct sUserProfile {
    char name[NAME_SZ];
    char address[ADDRESS_SZ];
    int socialNumber;
    char password[PASSWORD_SZ];

    HashTable *mailbox;
    short msgCount;
} UserProfile;

Y esta es la forma en que estoy escribiendo actualmente todos los perfiles en el disco:

void ioWriteNetworkState(SocialNetwork *social) {
    Vertex *currPtr = social->usersNetwork->vertices;
    UserProfile *user;

    FILE *fp = fopen("save/profiles.dat", "w");

    if(!fp) {
        perror("fopen");
        exit(EXIT_FAILURE);
    }

    fwrite(&(social->usersCount), sizeof(int), 1, fp);

    while(currPtr) {
        user = (UserProfile*)currPtr->value;

        fwrite(&(user->socialNumber), sizeof(int), 1, fp);
        fwrite(user->name, sizeof(char)*strlen(user->name), 1, fp);
        fwrite(user->address, sizeof(char)*strlen(user->address), 1, fp);
        fwrite(user->password, sizeof(char)*strlen(user->password), 1, fp);
        fwrite(&(user->msgCount), sizeof(short), 1, fp);

        break;

        currPtr = currPtr->next;
    }

    fclose(fp);
}

Notas:

  • La primera fwrite() ves escribirá el recuento total de usuarios en el gráfico, así que sé la cantidad de datos que necesito para leer de nuevo.
  • El break está ahí para propósitos de prueba. Hay miles de usuarios y todavía estoy experimentando con el código.

Mis preguntas:

  • decidí fwrite() utilizar en cada elemento en lugar de escribir toda la estructura. También evito escribir el puntero al buzón de correo, ya que no necesito para salvar a ese puntero. Por lo tanto, es este el camino a seguir? fwrite() múltiple es en lugar de una global para toda la estructura? ¿No es más lento?
  • ¿Cómo se lee hacia atrás este contenido? Yo sé que tengo que usar fread() pero no sé el tamaño de las cuerdas, porque yo solía strlen() escribirlas. Podría escribir la salida de strlen() antes de escribir la cadena, pero ¿hay alguna manera mejor sin las escrituras de más?
¿Fue útil?

Solución

Si sus necesidades de programa que se va en absoluto portátil, entonces no debería estar escribiendo enteros y pantalones cortos en el disco como bloques de memoria: se corromperá los datos cuando intenta leerlos en un equipo con un tamaño diferente de palabras (por ejemplo, 32 bits -> 64 bits) o diferente orden de bytes

.

Para las cadenas, puede escribir la primera longitud, o incluir un terminador al final.

La mejor manera es por lo general para utilizar un formato basado en texto. Por ejemplo, podría escribir cada registro en una línea separada, con campos separados por una pestaña o dos puntos. (Como beneficio adicional, ya no hay necesidad de escribir un recuento del número de registros en el inicio del archivo --- acaba de leer en los registros hasta llegar al final del archivo.)

Editar Pero si se trata de una asignación de clase se te ha dado, es probable que no necesita preocuparse acerca de la portabilidad. terminadores '\0' escritura de las cuerdas en el disco para delimitar ellos. No se preocupe por la eficiencia al leerlo de nuevo, el bit más lento es el acceso al disco.

O fwrite() incluso fuera de toda la estructura y fread() todo de nuevo. Preocupado por eso puntero? Sobrescribirlo con un valor seguro cuando lo lea en. No se preocupe por el espacio perdido en el disco (a menos que le han pedido para minimizar el uso del disco).

Si lo hace necesidad de escribir enteros no negativos en el disco en un formato binario portátil, puede hacerlo de esta manera:

  • primer byte es el número de bytes siguientes
  • segundo byte es el byte más significativo no es cero en el int
  • ...
  • último byte es el byte menos significativo en el int

Así que:

  • 0 codifica como 00
  • 1 codifica como 01 01
  • 2 codifica como 01 02
  • 255 -> 01 ff
  • 256 -> 02 01 00
  • 65535 -> 02 ff ff
  • 65536 -> 03 01 00 00
  • etc.

Si necesita codificar los números negativos, así, tendrá que reservar un poco para la señal de alguna parte.

Otros consejos

Tienes razón:. Como lo está haciendo ahora, no hay manera de volver a leer el contenido, porque no se puede saber dónde termina una cuerda y comienza la siguiente

El consejo usted cita a evitar el uso de fwrite () para datos estructurados es bueno, pero la interpretación de que el consejo en el sentido de que se debe fwrite () cada elemento individual puede no ser la mejor solución.

creo que debería considerar el uso de un formato diferente para su archivo, en lugar de escribir valores en bruto con fwrite (). (Por ejemplo, los archivos no serán portátil para una máquina con diferente orden de bytes.)

Dado que parece que la mayor parte de sus elementos son cadenas y números enteros, ¿ha considerado un formato basado en texto utilizando fprintf () para escribir y fscanf () para leer? Una gran ventaja de un formato basado en texto en lugar de un formato binario de la aplicación específica es que se puede ver con herramientas estándar (para pruebas, etc.)

Además, el formato que elija, asegúrese de considerar la posibilidad de que puede que tenga que añadir más campos en el futuro. Como mínimo, eso significa que deben incluir un número de versión en una especie de cabecera, ya sea para el propio archivo o para cada entrada individual. Aún mejor, la etiqueta de los campos individuales (para tener en cuenta los atributos opcionales), por ejemplo:

name: user1
address: 1600 pennsylvania ave
favorite color: blue

name: user2
address: 1 infinite loop
last login: 12th of never
  • es más lento. Llamar a una función x veces es más lento de lo que calificó una vez que x> 1. Si el rendimiento resulta ser una preocupación, puede utilizar fwrite / fread con sizeof (estructura) para el uso regular y escribir una versión serializada portátil para la importación / exportación. Pero comprobar si realmente es un problema en primer lugar. La mayoría de los formatos no utilizan datos binarios más, así que se puede decir que al menos el rendimiento fread que no es su principal preocupación.

  • No, no hay. la alternativa está haciendo un fgetc(3) basado strlen.

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