C言語でファイル内の一致検索

このQ&Aのポイント
  • C言語でファイル内の一致検索を効率的に行う方法について考えています
  • fgetc関数とfread関数のどちらが効率的な検索方法かを知りたいです
  • また、C言語にはmemmoveやstrstrと同様な機能を持つ関数があるのか知りたいです
回答を見る
  • ベストアンサー

C言語でファイル内の一致検索

やりたい事は、ファイル(テキストに限らず画像等も含めて)をfopen関数で読み込んであらかじめ用意したバッファーに格納されているデータと一致する箇所をすべて検索して検索されたところをすべて列挙することです。 効率の良い(検索速度)方法で行いたいのですが、 fgetc関数を使って検索していくのとfread関数を使って一度すべてをメモリー内に読み込んで検索するのではどちらが効率がよいでしょうか? 他にも良い方法があったら教えてください。 私はFILE * ストリームポインタの仕組みがよくわかっていません。fopenをすると何が内部で行われるのでしょうか?ファイルの内容がメモリーに読み込まれるわけではないですよね?ファイル内にアクセスする時どのようにアクセスしているのかなど教えていただきたいです。そうすればどうするのが良いのかわかる気がするので。 あとこれとは別の話ですが 標準関数にあるmemmoveとstrstr関数ですが、これと同様な機能を持つstrmoveとmemmemといった関数がなかったのですが、この機能を持つ関数は用意されているのでしょうか?一般的に使われないので自分で作れということなのでしょうか?その場合どの様に実装すればよいか時間があれば参考にプログラムを書いていただけないでしょうか? よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • goosyu
  • ベストアンサー率58% (36/62)
回答No.4

>fgetc関数を使って検索していくのとfread関数を使って一度すべてをメモリー内に読み込んで検索するのではどちらが効率がよいでしょうか? →一番早い検索は全てメモリに読み込み,ファイルアクセス回数を減らすのが基本です。ファイルアクセスにはOSの処理時間が発生する為です。  ただ,ファイルが大きすぎてメモリに入りきらない場合もありますので,ファイルの大きさを見てファイルのアクセス方法を変えるしかないと考えます。  ちなみにパソコンのOS環境下では,fgetc関数を使っても毎回物理的にファイルを読み込んでいるわけではなく,ファイルバッファを読み込む事になりますので思ったほどは効率が悪くなりませんが,高速化を考えた場合はfread関数を使うことをおすすめします。 >私はFILE * ストリームポインタの仕組みがよくわかっていません。fopenをすると何が内部で行われるのでしょうか? →お使いの環境(OS)によってはfopenの内部動作は変わってくるかもしれませんが。手元の環境での動作についてまとめます。  ・ファイルオープン   OSが提供しているファイルオープン関数(createfile関数とか_open関数など)を使いファイルをオープンします。  ・ファイル読み込み用のバッファ構造の提供   これはfgetc関数,fread関数,fscanf関数などファイル読み込みをバッファ経由で行いファイル読み込み回数を減らす機能を提供します。  ・FILE型のリソース確保   ファイルオープン時にFILE型のリソースを確保し戻り値に確保したアドレスを返します。 >ファイルの内容がメモリーに読み込まれるわけではないですよね?ファイル内にアクセスする時どのようにアクセスしているのかなど教えていただきたいです。そうすればどうするのが良いのかわかる気がするので。 →普通fopen関数ではファイルの読み込みは行われません。fgetc関数なりfread関数がコールされた場合に,バッファが空の時に適当なサイズ分を低水準入出力(_read)関数などを使いバッファへ読み込みを行い,そこから結果を返しています。またバッファにデータがある場合はバッファから直接結果を返しています。 >標準関数にあるmemmoveとstrstr関数ですが、これと同様な機能を持つstrmoveとmemmemといった関数がなかったのですが、この機能を持つ関数は用意されているのでしょうか?一般的に使われないので自分で作れということなのでしょうか? →必要であれば必要に応じて作るという認識だと思います。 >その場合どの様に実装すればよいか時間があれば参考にプログラムを書いていただけないでしょうか? #define strmove(A, B) memmove((A), (B), (strlen(B) + 1) * sizeof(char)) // 引数 : strLen pStrのサイズ , pSrc 検索対象の先頭アドレス , searchLen pSearchのサイズ , pSearch 検索するデータの先頭アドレス char *memmem(int strLen, char *pStr, int searchLen, char *pSearch) { // 単純検索 世の中にはBM法とかKMV法など色々と検索するロジックが存在します。高速化をしたいのであればそちら検討して下さい。 int i; if (strLen < searchLen) return NULL; for ( i = 0; i < strLen - searchLen + 1; i++) { if ( memcmp(&pStr[i], pSearch, searchLen) == 0 ) { return &pStr[i]; } } return NULL; }

yozakura20
質問者

お礼

回答ありがとうございます。 やはり一度すべて読み込んだ方が速かったです。 説明を読んで納得できました。 検索アルゴリズムをいままで書いたこと無かったのでネットで検索してBM法とBMH法とquick search法をでそれぞれ作ってみました。 単純検索より速く検索でき驚きました。 memmem関数を自力で作ることができました。助かりました。

その他の回答 (3)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

先にfreadで全部読み込む方法の場合、メモリ管理がやや面倒になります。事前にファイルサイズを調べておけばよいのですが、標準の範囲ではいったん最後まで読むしかないので、あまりうれしくありません。 アルゴリズムにもよりますが、ごく単純なものであればfgetcを使って1バイトずつ読み込みながら検索するほうが、作るのも簡単ですし、実行効率もよくなる可能性があります(実行効率に付いては実装方法次第です)。 memmoveというのは、領域の重なり方に応じて、前から後ろに向かってコピーするか、後ろから前に向かってコピーするかを切り替えています。これを実現するには、領域のサイズが分かっていなければなりません。 したがって、strmoveのようなものを作ろうとすると、いったんstrlenで文字列の長さを調べてからmemmoveすることになります。 具体的には、 memmove(s1, s2, strlen(s2)); のような感じです。これだけで済みますので、特別な関数は不要でしょう。

yozakura20
質問者

お礼

回答ありがとうございます。 いろいろアルゴリズムを考えようとおもい一度すべてメモリに読み込むことにしました。確かに単純なものならgetcが手っ取り早いです。

  • salsberry
  • ベストアンサー率69% (495/711)
回答No.2

memmoveの文字列版はstrcpyまたはstrncpyでは足りませんか?

yozakura20
質問者

お礼

意外と簡単にmemmoveを作れることを知りました。 ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

可能なら「fread で全部読み込む」方が簡単になる. 「効率の良しあし」以前に「明らかにプログラムが単純化される」のは明白. ちなみに検索アルゴリズムは何を使うつもりですか?

yozakura20
質問者

お礼

回答ありがとうございます。 はじめ単純法で検索することを頭に入れていてfgetcで順に検索していけばできるのではと思っていたのですが、検索アルゴリズムで高速化を考えて一度全てメモリに読み込んで検索することにしました。 うまくできそうです。

関連するQ&A

  • バイナリファイルの検索について

    いつもお世話になります。 今、検索について学習しているのですが、 文字列検索の場合はstrstrなどを使用すれば 検索できることは理解できました。 しかし、バイナリファイルの検索について理解できていません。 もし、バイナリ(画像や動画etc)ファイルの 中身を解析したい場合、 (1)JPEGなどのバイナリファイルを開く場合、fopen()でひらいてもいいのでしょうか?その他の方法ありますか? (2)バイナリファイルを開いた後、バイナリファイルの 0xfffeなど指定する値の検索がしたい場合は どのように検索したらいいのでしょうか? 関数や方法などありましたら教えてください。 どうぞよろしくお願い致します。

  • C言語でクロマキー合成をする方法

    input.bmpとbackground.bmpとoutput.bmpを作りで好きな絵を用意して、input.bmpというビットマップファイル(色数は24ビット)とbackground.bmpというファイルを開き,クロマキー合成をし,ビットマップファイルoutput.bmpに出力させる。 上記の物をC言語でするにはどうすればいいのでしょうか? 下記のものは自分でやったのですがやり方が分かりません。どなたか知恵を貸してください。 (ほとんど間違っていると思いますが・・・) #include<stdio.h> int main() { FILE *fp; int i; char data[2]; short s; fp1=fopen("input.bmp","rb"); fp2=fopen("background.bmp","rb"); fp3=fopen("output.bmp","wb") int k; for(k=0;k<10000;k++){ fputc(0,fp); fputc(0,fp); fputc(0,fp); } fclose(fp); fread(&data[0],1,2,fp1); fread(&data[0],1,2,fp2); fwrite(&data[0],1,2,fp3); int fs; fread(&fs,f1); fread(&fs,f2); fwrite(&fs,f3); fp=fopen("aka.bmp","wb"); fread(moji,1,2,fp); i=30054; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=54; fread(&i,4,1,fp); i=40; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); s=1; fread(&s,2,1,fp); s=24; fread(&s,2,1,fp); i=0; fread(&i,4,1,fp); i=30000; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); for(k=0;k<10000;k++){ fputc(0,fp); fputc(0,fp); fputc(70,fp); } fclose(fp); fp=fopen("midori.bmp","wb"); fread(moji,1,2,fp); i=30054; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=54; fread(&i,4,1,fp); i=40; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); s=1; fread(&s,2,1,fp); s=24; fread(&s,2,1,fp); i=0; fread(&i,4,1,fp); i=30000; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); for(k=0;k<10000;k++){ fputc(0,fp); fputc(150,fp); fputc(0,fp); } fclose(fp); fp=fopen("ao.bmp","wb"); fread(moji,1,2,fp); i=30054; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=54; fread(&i,4,1,fp); i=40; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); i=100; fread(&i,4,1,fp); s=1; fread(&s,2,1,fp); s=24; fread(&s,2,1,fp); i=0; fread(&i,4,1,fp); i=30000; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=120; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); i=0; fread(&i,4,1,fp); for(k=0;k<10000;k++){ fputc(255,fp); fputc(0,fp); fputc(0,fp); } fclose(fp); return(0); }

  • C言語、fgetcを利用しファイルの内容を変数に

    C言語について質問です C言語のfgetcを利用しファイルの内容を変数にいれてそれを返す関数を作っているのですがうまくいきません <!--以下ソース--> char *file_get_contents(char *filename){ FILE *fp; int c; char *return_str; if((fp=fopen(filename,"r"))==NULL) return NULL; while((c=fgetc(fp))!=EOF ){ sprintf(return_str,"%c",c); } fclose(fp); return return_str; } 誰か理由と改善方法を教えてください!

  • C言語でファイルから特定の文字を抽出

    現在C言語でプログラム開発しています。 文字列が並んだテキストファイルから特定の部分のみを抽出したいのですが、うまくいきません。 お力を貸していただけないでしょうか。 テキストファイルの構造はこんな感じです。 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 文字列 文字列 文字列badresult=*****文字列badresult=*****文字列badresult=*****文字列result=***** ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー これが10セット程記述されたファイルです。 ここから全てのbadresultの数値とresultの数値を抽出したいのです。 私が現段階で作成したプログラムがこちらです。 #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXLINE 2084 int main(void){ FILE *fp; char line[MAXLINE]; char s1[]="badresult"; char s2[]="result="; char *r; if ((fp = fopen( "テキストファイルへのダイレクトパス", "r" )) == NULL){ printf("エラーメッセージB\n"); exit(1); } while (fgets(line, MAXLINE, fp) != NULL){ if(strstr(line,s1)!=NULL){ printf("%.27s",strstr(line, s1),"\n"); printf(" "); printf(strstr(line, s2)); } } } ですがこれだと1行に全てのbadresultが含まれているため、結果は ----------------------------- badresult=***** result=****** ----------------------------- とbadresultは1つしか出てきません。 strstrのポインタをどうにかできないかと考えたのですが、 私のC言語の知識も浅いためなかなかうまくできません。 Cプログラミングに精通している方、どうか改善策を教えていただけないでしょうか。 できればなるべく簡単な方法ですと助かります。

  • FILE オープンについて

    いつもお世話になります。 今ファイルデータ検索処理を検討しております。 今、search.txtには、 検索対象となるファイルパスが記載されています。 [search.txt] /home/hoge/SAMPLE1.jpg /home/hoge/SAMPLE2.jpg search.txtをfopen()し、1行ずつfgets()して、 得られるファイルパスより、そのファイルを fopen()して解析する処理がしたいですが、 fgets()より得られたファイルパスをfopen()し、 fread()するとセグメンテーションエラーになります。 どのようにしたらいいのでしょうか? 現状のコードを下記します。 FILE *fp; char *com1 = "/home/hoge/search.txt"; FILE *confp; char buf1[1024]; char buf2[1024]; int i =0; fp = fopen(com1, "r"); while( fgets(buf1, sizeof(buf1), fp )){ confp = fopen(buf1, "rb"); //*.JPGファイルをオープン //下記fread()でセグメンテーションエラー size_t size = fread( buf2, sizeof(char), 1024, confp ); for( i = 0; i<1024; i++ ){ if( (buf2[i] == 0xff) && (buf2[i+1] == 0xe0) ){ printf("%02x\n",buf[i+5]); } } } fclose(fp); fclose(confp); 上記のように、search.txtをfopen()し、読み込んだファイルパスを fopen()して、fread()読み込みをする方法を 教えて下さい。 どうぞよろしくお願い致します。

  • ファイルの読み込み方法について

    サーバファイルなどを読み込む際、PHPではバッファを設けたfopen()、file_get_contents()という2つの方法のどちらかが採用されると思います。 しかし、ファイル内容などを全て取得したい場合、どちらも同じ動作をし、かつfile_get_contents()の方が簡潔な記述になります。 よく何かのサンプルだとfopen()を利用してバッファ指定で全ての内容を取得しているのですが、それに意図はあるのでしょうか? 明確な答えが知りたいです。

    • ベストアンサー
    • PHP
  • ファイルの読み込みについて

    いつも大変お世話になっています。 例えば以下のような関数があったとします。 function out_file($file_path) { $_handle = @fopen($file_path, "r"); $_dat = @fread($_handle, @filesize($file_path)); @fclose($_handle); return $_dat; } 【質問1】 $file_path の示すファイルが 10M のファイルだとして、10人のクライアントがアクセスしてきたとしたら、サーバーのメモリは 100M 食われてしまうのでしょうか?それとも10M?(まさか、0M?) 【質問2】 ファイルは読み取り専用で開いていますが、大量のクライアントが同時アクセスしてくるとしても flock など無くて正常に動くのでしょうか? それとも、やはり排他制御する必要はあるでしょうか? 10人同時アクセス時のこの関数の挙動がイマイチイメージできません。 以上です。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • C言語 複数ファイル操作について

    Cプログラミング初心者です。 論文などの何行も文章があるようなテキストファイル(ここでは1.txtとします)と、他に予め単語をいくつか登録しているテキストファイル(2.txt)を開き、1.txtを最初の行から一行ごとに読み込み、2.txtの中にある単語が1つでもその一行の文章中に含まれていたらその一行の文章を出力し、また次の行においても2.txtの中にある単語のいずれかが含まれているかどうかを調べて含まれている場合は出力…含まれていない場合は出力せずに次の行へ…といったようにこれを1.txt内の最後の行まで繰り返し行うプログラムを作りたいのですが、自分が作ったプログラムでは含む・含まない関係なく1.txt内の文章全てが出力されてしまいます。おそらく最初のwhile文あたりがおかしいのだろうという予想はつくのですがどのように直せばよいのかわからず悩んでいます。どなたか教えていただければ嬉しいです(;_:) #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1056 void delkaigyo(char *s1,char *s2){ char *p = s1; p=strstr(s1,s2); if(p!=NULL){ strcpy(p,p+strlen(s2)); delkaigyo(p+1,s2); } } int main(void){ FILE *fp; char *filename = "2.txt"; char str1[N]; char str2[N]; char kaigyo[] = "\n"; int i; int a=0; char fname[64]; printf("file:"); scanf("%s", fname);   ←ここで1.txtを入力するとします fp = fopen(fname, "r"); while(fgets(str1, N, fp) != NULL){ delkaigyo(str1, kaigyo); memset(str1, 0, N); fread(str1, 1, N-1, fp); if((fp = fopen(filename, "r")) == NULL){ fprintf(stderr, "%serror.\n", filename); exit(EXIT_FAILURE); } while(fgets(str2, N, fp) != NULL){ delkaigyo(str2,kaigyo); if(strstr(str1,str2)!=NULL){ a = 1; printf("%s\n", str1); break; } } if(a==0){ return 0; } fclose(fp); } return EXIT_SUCCESS; }

  • C言語 クイックソートの使い方&検索関数について

    現在私は、ファイルから読み込んで、リストナンバー・名前・年令の三つの要素で管理する簡単なデータベースのプログラムを作っています。 その中で、検索機能をつけようとしています。 しかし、検索条件を選ぶことが出来るようにしたいのですが、書き方が今イチ分かりません。関数の書き方をどなたか教えて下さい。 それと、並び替え機能も付けようをしているのですが、その並び替える項目を指定できるようにしようと思うのですが、上手くいきません。私としてはクイックソートを使いたいのですが、使い方がよく分かりません、分かり易い使い方の説明をして頂けるとありがたいです。

  • 【C言語】大文字小文字に関わらず文字列を検索したい

    C言語で文字列を検索処理があるものですが、 以下のようなことがうまくできず困っています。 1.検索対象はファイルから読み込んだメモリ内の文字列。 2.対象の文字列は大文字小文字に関わらずに抽出する。 例えば、「abc」を検索するとして、文字列内が aaaaBccccdefgだとすると… aaa「aBc」cccdefg かっこ内を検索します。 strstrだと、完全な一致しかヒットしないので… 長い文字列が対象になることもあるので、 すべての組み合わせを見るのも性能的に難しいです。 何か方法ご存知の方いらっしゃいましたら、よろしくお願いします。

専門家に質問してみよう