lenguaje - Manejo de la configuración basada en archivos en C(Unix)
manejo de archivos en c pdf (11)
¿Has pensado en almacenar los valores de configuración como variables de entorno? :) Y el archivo de configuración será un script de shell que ejecute antes de su programa. (en realidad, el script de shell lo ejecutará para guardar variables). De esa forma estás usando shell como config parser :)
Use http://www.google.com/codesearch y "read config"
Esta es probablemente una de las tareas / problemas más comunes al programar; Necesita almacenar la configuración de su aplicación en algún lugar.
Mientras trato de crear un servidor web y / u otras aplicaciones, me gustaría mantener el código lo más limpio posible ya que mi principal interés en la programación es la Arquitectura. Esto me lleva a querer almacenar configuraciones en un archivo que puede modificarse sin tener que volver a compilar el software.
No estoy aquí para reinventar la rueda ni nada de eso, así que lo que me gustaría hacer es crear un lector de configuración en C on * nix. La configuración puede parecerse mucho a cualquier otra configuración de software; Apache, vsftpd, mysql, etc.
La pregunta básica es: ¿cómo se lee en un archivo de texto y se procesa cada línea de manera eficiente (en Pure C)? ¿Debo usar fgetc () y procesar cada char?
¿Por qué escribirías este código desde cero, se ha hecho tantas veces; solo encuentre una buena implementación de F / OSS y úselo.
¿Cómo se lee en un archivo de texto y procesa cada línea de manera eficiente?
No se preocupe por la eficiencia, no importa leer los archivos de configuración. Vaya por simplicidad y mantenibilidad en su lugar.
De acuerdo, aquí hay un ejemplo real de código C:
/* demo-fgets -- read a "demo.text", copy to stdout with line
numbers. */
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 100
FILE * fp;
char bufr[MAXLINE];
extern int errno ;
int main(int argc, char ** argv){
int count = 0 ;
if((fp = fopen("demo.text","r")) != NULL){
/* then file opened successfully. */
while(fgets(bufr,MAXLINE,fp)!=NULL){
/* then no read error */
count +=1;
printf("%d: %s", /* no "/n", why? */
count, bufr);
}
/* fgets returned null */
if(errno != 0){
perror(argv[0]); /* argv[0]? Why that? */
exit(1);
}
exit(0); /* EOF found, normal exit */
} else { /* there was an error on open */
perror(argv[0]);
exit(1);
}
}
Lo ejecuto con este archivo de entrada:
520 $ cat demo.text
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum
aliquet augue id quam. Sed a metus. Quisque sit amet quam. Sed id
ante. In egestas est non mi. Sed vel velit non elit vehicula
viverra. Curabitur eget tortor in ipsum vulputate
faucibus. Suspendisse imperdiet mauris at nibh. Sed interdum. Maecenas
vulputate, massa vel placerat mattis, ante est tincidunt sem, in
sollicitudin velit lacus non tortor. Etiam sagittis consequat nisl.
Vestibulum id leo quis mauris gravida placerat. Donec aliquet justo a
tortor. Etiam nisi nibh, auctor non, luctus et, aliquam vitae,
metus. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Nunc lacinia quam a ligula. Nulla quis nisi eu
nunc imperdiet cursus. Nunc vitae nisi vitae tellus posuere
sollicitudin. Nunc suscipit, dui ac interdum euismod, pede nisl varius
dui, sed mattis libero mauris eu felis. Nam mattis dui eget
nunc. Suspendisse malesuada, pede eget posuere pellentesque, neque
eros pretium nibh, ut blandit dui leo dapibus orci. Etiam lacinia
lectus at orci. Donec ligula lacus, sagittis nec, sodales et,
fringilla lobortis, eros. Etiam sit amet nulla. Aliquam mollis pede id
enim. Etiam ligula felis, pulvinar nec, vestibulum molestie, interdum
ut, urna. Ut porta ullamcorper diam. Nullam interdum arcu.
Pellentesque habitant morbi tristique senectus et netus et malesuada
fames ac turpis egestas. Etiam eu enim quis sem accumsan
tristique. Proin non sem. Etiam quis ante. Aenean ornare pellentesque
dolor. Praesent sodales. Cras dui velit, scelerisque a, accumsan a,
vestibulum in, dui. Pellentesque sed sapien. Etiam augue est,
convallis eget, egestas vel, molestie id, turpis. Cum sociis natoque
penatibus et magnis dis parturient montes, nascetur ridiculus
mus. Cras posuere lorem eu diam. Ut ultricies velit. Nunc imperdiet
suscipit mauris. Vestibulum molestie elit id risus. Phasellus et
purus. Vestibulum id mauris. Fusce gravida elit quis turpis. Aliquam
ut est.
Sed in mauris eu nulla rhoncus suscipit. Nam id dolor sit amet turpis
placerat sodales. Nunc ipsum. Quisque diam tellus, dapibus non,
interdum at, aliquam sit amet, tellus. Donec non pede eget massa
aliquam semper. Quisque dictum lacinia ipsum. Fusce magna purus,
mattis id, commodo et, lobortis eu, arcu. Vestibulum viverra neque a
nulla. Cum sociis natoque penatibus et magnis dis parturient montes,
nascetur ridiculus mus. Pellentesque vel felis in ligula blandit
auctor. Quisque quam. Curabitur turpis. Morbi molestie augue a
nisi. Nulla sollicitudin sagittis elit. Suspendisse in odio sed magna
dictum vestibulum. Duis facilisis lorem eget neque. Proin sit amet
urna eget velit scelerisque aliquam. Pellentesque imperdiet. Nullam
sapien. Nullam placerat ipsum eget metus.
Mauris ornare risus eu velit. Morbi bibendum diam in sem. Morbi
aliquet nisl sit amet quam. Donec ornare sagittis nibh. Fusce ac
lectus. Sed sit amet risus. Integer facilisis commodo
sem. Pellentesque facilisis. Donec libero. Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Hay diferentes maneras. No necesita usar fgetc. Probablemente deberías leer la página man de stdio, pero lo canónico sería abrir el archivo con fopen (3), luego leer usando fgets (3) para leer una línea a la vez. Eso se vería algo así como:
#include <stdio.h>
FILE * fp ;
char bufr[MAXLINE];
if((fp = fopen(filename, "r") != NULL){
while(! feof(fp)){
fgets(bufr, MAXLINE, fp);
/* Do stuff */
}
} else {
/* error processing, couldn''t open file */
}
También puedes ver libini en Sourceforge.
La forma en que lo habría hecho (pseudo-código):
while(there is input) {
get one line;
if (it is empty line || it beings with spaces followed by a ''#'') {
skip this line, either empty or it''s a comment;
}
find the position of the token that splits option name and its value;
copy the option name and its value to separate variables;
removing spaces before and after these variables if necessary;
if (option == option1) {
parse value for option 1;
} else if (option == option2) {
parse value for option 2;
} else {
handle unknown option name;
}
check consistency of options if necessary;
}
Tenga en cuenta que parte del código (verificando si hay líneas vacías, comentarios y espacios alrededor de las variables) está ahí para darle más flexibilidad al escribir el archivo de configuración. Por ejemplo, no bloqueará su programa dejando accidentalmente un espacio extra aquí y allá.
Esto supone que tienes archivos de configuración que se parecen a los siguientes:
# comment for option 1
option1 = value1
# comment for option 2
option2 = value2
...
Otra solución más: Pure-ftpd
A diferencia de muchos daemons, Pure-FTPd no lee ningún archivo de configuración. En cambio, usa opciones de línea de comandos. ... Agregar un analizador para los archivos de configuración en el servidor es una mala idea. Se ralentiza todo y necesita recursos para nada.
Y para las opciones hay getopt
También hay función getline () y amigos en GNU LibC
Varias personas han dado consejos razonablemente buenos: el ejemplo de Pure-FTP es interesante.
También debe leer TAOUP (The Art of Unix Programming) de ES Raymond. Tiene ejemplos de muchos archivos de configuración. También describe expresiones idiomáticas canónicas para los archivos de configuración. Por ejemplo, probablemente debería permitir que ''#'' comience un comentario al final de la línea e ignore las líneas en blanco. También debe decidir qué hará si el archivo de configuración contiene una línea que no comprende: ignorar y continuar en silencio, o si debe presentar una queja. (Prefiero las cosas que se quejan, entonces sé por qué lo que acabo de agregar no está teniendo ningún efecto, mientras que silenciar silenciosamente significa que no sé si la entrada que acabo de añadir tiene algún efecto).
Otro problema es ubicar el archivo de configuración. ¿Lo hace por ubicación compilada, por una ubicación de instalación predeterminada con una variable de entorno para anular, o por alguna otra pieza de magia? Asegúrate de que haya una opción de línea de comando para permitir que el archivo de configuración se especifique por completo, incluso considera que es la única forma de hacerlo.
De lo contrario, dentro de amplios límites, manténgalo simple y todos serán más felices.
Escribí un analizador de archivos INI limpio, sin dependencias e impulsado por eventos en C hace un tiempo. Decidí lanzarlo a un repositorio público de Hg . Está licenciado por MIT, por lo que puede usarlo en cualquier lugar que desee.
Está bien, así que vamos a la otra parte. Debes pensar en lo que te gustaría tener como tu "idioma". En el mundo de UNIX, el tipo de versión canónica es, probablemente, texto delimitado en blanco (think /etc/hosts
) o texto delimitado por ":" (como /etc/passwd
).
Tienes un par de opciones, la más simple en algún sentido es usar scanf (3). De nuevo, lea la página de manual para obtener más detalles, pero si una entrada de línea es algo así como
port 100
entonces estarás buscando algo así como
char inbuf[MAXLINE];
int val;
scanf("%s %d/n", &inbuf[0], &val);
Puede obtener un poco más de flexibilidad si escribe un análisis simple de FSA: lea los caracteres uno a la vez de la línea y use un autómata finito para definir qué hacer.