これはおそらく、プログラミング時の最も一般的なタスク/問題の1つです。アプリケーションの構成をどこかに保存する必要があります。
私はウェブサーバーやその他のアプリケーションを作成しようとしていますが、プログラミングへの私の主な関心はアーキテクチャであるため、コードをできるだけクリーンに保ちたいと考えています。このため、ソフトウェアを再コンパイルせずに変更できるファイルに構成を保存したいと思っています。
ホイールなどを再発明するためにここにいるわけではないので、私がしたいことは、* nixのCで構成リーダーを作成することです。構成は、他のソフトウェアの構成とよく似ています。 Apache、vsftpd、MySQLなど.
基本的な質問は次のとおりです。テキストファイルからどのように読み取り、各行を(純粋なCで)効率的に処理しますか。 fgetc()
を使用して各文字を処理する必要がありますか?
よし、もう片方を叩いてみよう。 「言語」として何を持ちたいかを考える必要があります。 UNIXの世界では、正規バージョンの種類はおそらく空白で区切られたテキスト(/etc/hosts
と考える)または ":"で区切られたテキスト(/etc/passwd
など)です。
いくつかのオプションがありますが、ある意味で最も簡単なのはscanf(3)を使用することです。繰り返しますが、詳細についてはmanページを読んでください。ただし、行エントリが次のような場合
port 100
それからあなたはのようなものを探します
char inbuf[MAXLINE];
int val;
scanf("%s %d\n", &inbuf[0], &val);
単純なFSA解析を書くと、もう少し柔軟性が得られます。行から一度に1文字ずつ文字を読み取り、有限オートマトンを使用して何をすべきかを定義します。
さまざまな人々がかなり良いアドバイスをしてくれました-Pure-FTPの例は興味深いものです。
E S Raymondによる [〜#〜] taoup [〜#〜] (The Art of Unix Programming)もお読みください。たくさんの設定ファイルの例があります。また、構成ファイルの正規イディオムについても概説します。たとえば、「#」で行の終わりまでコメントを開始し、空白行を無視できるようにする必要があります。また、構成ファイルに理解できない行が含まれている場合に何をするかを決定する必要があります-無視して黙って続行するか、文句を言うか。 (私は文句を言うことを好みます。それから、追加したばかりのものが効果がない理由を知っています-サイレント無視は、追加したばかりのエントリが効果があるかどうかわからないことを意味します。)
もう1つの問題は、構成ファイルの場所です。それは、コンパイルされた場所、上書きする環境変数を使用したデフォルトのインストール場所、またはその他の魔法によって行われますか?構成ファイルを完全に指定できるようにするコマンドラインオプションがあることを確認してください。それを行う唯一の方法にすることも検討してください。
それ以外の場合は、広い制限の範囲内で、それを単純にしてください。
いくつかの方法があります。あなたはfgetcを使用する必要はありません。おそらくstdioのmanページを読むべきですが、標準的なことは、fopen(3)でファイルを開いてから、fgets(3)を使用して一度に1行ずつ読み取ることです。それは次のようになります:
#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 */
}
Sourceforgeで libini を確認することもできます。
さて、これが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.
なぜあなたはeverこのコードを最初から作成しますか、それはすでに行われていますso何度も;良いF/OSS実装を見つけてそれを使用するだけです。
テキストファイルからどのように読み取り、各行を効率的に処理しますか
効率について心配する必要はありません。構成ファイルの読み取りには関係ありません。代わりに、シンプルさと保守性を追求してください。
私がそれをしたであろう方法(疑似コード):
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;
}
コードの一部(変数の周りの空の行、コメント、スペースをチェックする)は、構成ファイルを作成するときに柔軟性を高めるためにあることに注意してください。たとえば、あちこちに余分なスペースを誤って残してプログラムをクラッシュさせることはありません。
これは、次のような構成ファイルがあることを前提としています。
# comment for option 1
option1 = value1
# comment for option 2
option2 = value2
...
GNU LibCには getline()function and friends もあります。
クリーンで依存性のない、イベント駆動型のINIファイルパーサーをCで少し前に書いた。それを public Hgリポジトリ に入れることにした。 MITライセンスなので、好きな場所で自由に使用できます。
環境変数として構成値を保存することを検討しましたか? :)そして設定ファイルはあなたがプログラムの前に実行するシェルスクリプトになります。 (実際には、シェルスクリプトが変数を保存するためにそれを実行します)。このように、シェルを構成パーサーとして使用しています:)
http://www.google.com/codesearch を使用し、「設定を読み取る」
参照 httpdの例