Подтвердить что ты не робот

Обработка на основе файлов в C (Unix)

Это, вероятно, одна из самых распространенных задач/проблем при программировании; Вам нужно сохранить конфигурацию своего приложения где-нибудь.

Пока я пытаюсь создать веб-сервер и/или другие приложения, я хотел бы сохранить код как можно более чистым, так как мой основной интерес к программированию - это архитектура. Это приводит к тому, что я хочу сохранить конфигурации в файле, который можно изменить, не перекомпилируя программное обеспечение.

Я здесь не для того, чтобы изобретать колесо или что-то в этом роде, поэтому я хотел бы создать устройство конфигурации в C on * nix. Конфигурация может быть похожа на любую другую конфигурацию программного обеспечения; Apache, vsftpd, mysql и т.д.

Основной вопрос: как вы читаете из текстового файла и обрабатываете каждую строку эффективно (In Pure C)? Нужно ли использовать fgetc() и обрабатывать каждый char?

4b9b3361

Ответ 1

Хорошо, так что пусть попадет в другую часть. Вам нужно подумать о том, что вы хотели бы иметь в качестве своего "языка". В мире UNIX вид канонической версии - это, вероятно, текст с разделителями пробелов (think /etc/hosts) или текст с разделителем:: (например, /etc/passwd).

У вас есть пара опций, самым простым в некотором смысле будет использование scanf (3). Снова прочитайте man-страницу для получения подробной информации, но если запись строки похожа на

port    100

тогда вы будете искать что-то вроде

char inbuf[MAXLINE];
int  val;

scanf("%s %d\n", &inbuf[0], &val);

Вы можете получить немного большую гибкость, если напишите простой синтаксический анализ FSA: прочитайте символы по одному из строки и используйте конечный автомат, чтобы определить, что делать.

Ответ 3

Различные люди дали достаточно хорошие советы - пример Pure-FTP интересен.

Вы также должны прочитать TAOUP (Искусство программирования Unix) от E S Raymond. В нем есть примеры большого количества конфигурационных файлов. Он также описывает канонические идиомы для файлов конфигурации. Например, вы должны, вероятно, разрешить "#" начинать комментарий до конца строки и игнорировать пустые строки. Вы также должны решить, что вы будете делать, если файл конфигурации содержит строку, которую вы не понимаете, - игнорировать и продолжать молча, или жаловаться. (Я предпочитаю то, что жалуется, тогда я знаю, почему то, что я только что добавил, не имеет никакого эффекта, - в то время как молчание игнорирует означает, что я не знаю, имеет ли смысл добавленная запись.)

Другой проблемой является поиск файла конфигурации. Вы делаете это путем скомпилированного местоположения по месту установки по умолчанию с переменной окружения, чтобы переопределить или какой-либо другой магией? Убедитесь, что имеется опция командной строки, позволяющая указать конфигурационный файл абсолютно - даже подумайте о том, чтобы сделать это единственным способом.

В противном случае, в широких пределах, держите его простым и все будут счастливее.

Ответ 4

Существует несколько способов. Вам не нужно использовать fgetc. Вероятно, вам стоит прочитать страницу stdio man, но каноническим было бы открыть файл с fopen (3), а затем прочитать с помощью fgets (3), чтобы читать строку за раз. Это выглядит примерно так:

#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 */
}

Вы также можете посмотреть libini в Sourceforge.

Ответ 5

Хорошо, вот настоящий пример кода 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);
    }
}

Я запускаю его с этим входным файлом:

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.

Ответ 6

Зачем вам писать этот код с нуля, это было сделано много раз; просто найдите хорошую реализацию F/OSS и используйте ее.

Как вы читаете из текстового файла и обрабатываете каждую строку эффективно

Не беспокойтесь об эффективности, это не важно для чтения файлов конфигурации. Идем для простоты и ремонтопригодности.

Ответ 7

Еще одно решение - Pure-ftpd

В отличие от многих демонов, Pure-FTPd не считывает конфигурационный файл. Вместо этого он использует параметры командной строки.... Добавление парсера для файлов конфигурации на сервере является плохим идея. Это замедляет все и требует ресурсов для ничего.

И для опций есть getopt

Ответ 8

Как бы я это сделал (псевдокод):

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

Обратите внимание, что часть кода (проверка пустых строк, комментариев и пробелов вокруг переменных) дает вам дополнительную гибкость при написании файла конфигурации. Например, вы не будете разбивать свою программу, случайно оставив лишнее место здесь и там.

Предполагается, что у вас есть файлы конфигурации, которые выглядят следующим образом:

# comment for option 1
option1 = value1

# comment for option 2
option2 = value2

...

Ответ 10

Рассматриваете ли вы сохранение значений конфигурации в качестве переменных среды?:) И файл конфигурации будет оболочкой script, которую вы запускаете перед вашей программой. (на самом деле оболочка script выполнит ее для сохранения переменных). Таким образом, вы используете оболочку как конфигурационный парсер:)

Используйте http://www.google.com/codesearch и "read config"

См. Пример для httpd

Ответ 11

Я написал чистую, независимую от событий, управляемую событиями INI файл парсера в C некоторое время назад. Я решил бросить его в общедоступный репозиторий Hg. Это лицензия MIT, поэтому вы можете использовать ее там, где хотите.