C言語関係掲示板

過去ログ

No.384.ファイルから該当範囲のデータを取得するには

[戻る] [ホームページ]
No.2570

ファイルから該当範囲のデータを取得するには
投稿者---つよし(2002/09/03 13:32:04)


----[2002年09月02日 10時00分00秒]----
aaa
bbb
.
----[2002年09月02日 11時00分00秒]----
aaa
.
----[2002年09月03日 10時00分00秒]----
111
222
.
----[2002年09月03日 12時00分00秒]----
111
ccc
.

上記データが格納されたファイルから日付の行から「.」までの行を
1つとして取得し、出力を行っています。
例えば、200.09.03ならは、「---[2002年09月03日 ・・・・]---」の日付を
含めて「.」までを取得し、ファイルへの出力または、printfでの出力を
しているのですが、どうすればよいのですか。
ただし、「.」は出力しません。代わりに、データとデータの終わりと
言うことで、改行を入れます。

「.」がデータとデータの終わりと判断なので、「.」をキーにすればできる
と思うのですがよい案が浮かびません。

よろしくお願いします。


No.2576

Re:ファイルから該当範囲のデータを取得するには
投稿者---大(2002/09/03 17:19:51)


「.」までが取得したい1つのかたまりだとすると、「.」が出てくるまで、
読み込んだデータを別の領域に待避します。そのとき、レコードに日付が
存在しているかチェックし、存在していたらフラグを1にします。
「.」が出てきたとき、フラグが1だったら出力。1でなかったら待避エリア
をクリアし、次の「.」までの塊を処理する。

読み込んで先頭が「.」が判断する。まあ、一番簡単な方法ですが、
読み込んだレコードに対して、毎回、「.」があるかチェックしているので、
効率が悪いと言えば悪いかも知れません。
他に、良い方法があるかも。

#include <stdio.h>
#include <string.h>

main()
{
FILE *fp ;
char buff[8196] ;
char data[1024] ;
char chk_str[15] ;

char recv_data[11] ;
int buff_len ;
int data_len ;
int yyyy,mm,dd,c ;
int flg ;
int n ;

fp = fopen("オープンするファイル名","r") ;
if(fp == NULL) {
printf("file open error\n") ;
exit(1) ;
}

strncpy(chk_str,"2002年09月03日",14) ;
chk_str[14] = '\0' ;

buff[0] = '\0' ;
data[0] = '\0' ;
buff_len = 0 ;

while(fgets(data,LINE_SIZE,fp)!=NULL) {
if(strcmp(data , ".\n") != 0) {
strcat(buff,data) ;

if (strstr(data,chk_str) != NULL) {
flg = 1 ;
}
} else {
if (flg == 1) {
printf("%s",buff);
printf("\n");
}
memset(buff,'\0',sizeof(buff)) ;
flg = 0 ;
}
memset(data,'\0',sizeof(data)) ;
}
fclose(fp) ;
}


No.2580

Re:ファイルから該当範囲のデータを取得するには「訂正」
投稿者---大(2002/09/03 18:17:09)


「.」までが取得したい1つのかたまりだとすると、「.」が出てくるまで、
読み込んだデータを別の領域に待避します。そのとき、レコードに日付が
存在しているかチェックし、存在していたらフラグを1にします。
「.」が出てきたとき、フラグが1だったら出力。1でなかったら待避エリア
をクリアし、次の「.」までの塊を処理する。

読み込んで先頭が「.」が判断する。まあ、一番簡単な方法ですが、
読み込んだレコードに対して、毎回、「.」があるかチェックしているので、
効率が悪いと言えば悪いかも知れません。
他に、良い方法があるかも。

サンプルで記述したコードが誤っていたので訂正します。

#include <stdio.h>
#include <string.h>

main()
{
FILE *fp ;
FILE *ofp ;
char buff[8196] ;
char data[1024] ;
char chk_str[15] ;

fp = fopen("オープンするファイル名","r") ;
if(fp == NULL) {
printf("file open error\n") ;
exit(1) ;
}
ofp = fopen("出力ファイル名","r") ;
if(ofp == NULL) {
printf("file open error\n") ;
exit(1) ;
}

strncpy(chk_str,"2002年09月03日",14) ;
chk_str[14] = '\0' ;

buff[0] = '\0' ;
data[0] = '\0' ;

while(fgets(data,1024,fp)!=NULL) {
if(strcmp(data , ".\n") != 0) {
strcat(buff,data) ;

if (strstr(data,chk_str) != NULL) {
flg = 1 ;
}
} else {
if (flg == 1) {
/* 画面への出力 */
printf("%s",buff);
printf("\n");
/* ファイルへの出力 */
fprintf(ofp,"%s\n",buff) ;
}
memset(buff,'\0',sizeof(buff)) ;
flg = 0 ;
}
memset(data,'\0',sizeof(data)) ;
}
fclose(fp) ;
fclose(ofp) ;
}


ここに書き込むを行うとき、半角スペースだと、左に詰めてしまうのですね。

No.2579

Re:ファイルから該当範囲のデータを取得するには
投稿者---通りすがりのもの(2002/09/03 17:59:54)


下記のようなソースでどうでしょうか
#include <stdio.h>
#define UNMATCH 0
#define MATCH 1

int main(int argc,char *argv[])
{
char line[256];
FILE *in_fp,*out_fp;
char *p;
char startPart[5+1];
char strDate[14+1];
int matchFlag = UNMATCH;

/*引数チェック*/
/*if(argc != 2){
fprintf(stderr,"使用法:実行exe yyyymmddhhmmss\n");
exit(1);
}*/

/*入力ファイルオープン*/
in_fp = fopen("./test.txt","r");
if(in_fp == NULL){
fprintf(stderr,"入力ファイルをオープンできません。\n");
exit(1);
}

/*出力ファイルオープン*/
out_fp = fopen("./out.txt","w");
if(out_fp == NULL){
fprintf(stderr,"出力ファイルをオープンできません。\n");
exit(1);
}

/*ファイルエンドまで一行ずつ読み込む*/
while( (p=fgets(line,256,in_fp)) != NULL ){
/*先頭5文字を取得*/
memmove(startPart,line,5);
printf("(1)\n");
printf("startPart = %s",startPart);

/*日付行かどうかの判断*/
if(strncmp(startPart,"----[",5) == 0){
printf("(2)\n");
memset(strDate,0x00,sizeof(strDate));
/*年月日時分秒取得*/
memmove(strDate,p+5,14);
printf("strDate=%s\n",strDate);

/*ファイルから取得した年月日時分秒と実行時で指定した日付が一致したとき*/
if(strncmp(strDate,argv[1],14) == 0 ){
matchFlag=MATCH;
printf("(3)\n");
/*まず、日付行を出力*/
fprintf(out_fp,"%s",p);

/*実際のデータを出力*/
while( (p=fgets(line,256,in_fp)) != NULL ){
/* .でない間、行出力を行う*/
if(strncmp(p,".",1) != 0){
fprintf(out_fp,"%s",p);
}
/*ピリオドなら、終了*/
else{
goto owari;
}
}

}
else{
/*次の行を読みに行く*/
printf("(4)\n");
continue;
}
}
else{
/*次の行を読みに行く*/
printf("(5)\n");
continue;
}

printf("(6)\n");
}

owari:

/*マッチするものが存在しなかったとき*/
if(matchFlag == UNMATCH){
printf("日付[%s]は存在しません。\n",argv[1]);
}

/*ファイルクローズ*/
fclose(in_fp);
fclose(out_fp);

return 0;
}




No.2581

Re:ファイルから該当範囲のデータを取得するには
投稿者---かずま(2002/09/03 18:51:47)


#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char buf[1024], date[15];

    if (argc != 2) 
        return printf("usage: %s yyyymmddhhmmss <file\n", argv[0]), 1;
    while (fgets(buf, sizeof buf, stdin)) {
                if (sscanf(buf, "----[%4s%*2c%2s%*2c%2s%*2c %2s%*2c%2s%*2c%2s",
            date, date+4, date+6, date+8, date+10, date+12) != 6) continue;
        if (strcmp(date, argv[1])) continue;
        do {
            fputs(buf, stdout);
        } while (fgets(buf, sizeof buf, stdin) && buf[0] != '.');
        fputs("\n", stdout);
        break;
    }
    return 0;
}


No.2590

Re:ファイルから該当範囲のデータを取得するには
投稿者---かずま(2002/09/04 10:53:59)


インデントがおかしかったのを修正するついでに機能を追加してみました。

常に、年月日時分秒を指定するのは面倒なので、どこで切ってもいいように
しました。年月日だけを指定してもよいということです。したがって、出力
データも複数になることがあります。

また、すべての行を sscanf で調べるのは効率が悪いので、"----[" を先に
チェックするようにしました。
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char buf[1024], date[15];  int len;

    if (argc != 2) 
        return printf("usage: %s yyyy[mm[dd[hh[mm[ss]]]]] <file\n", *argv), 1;
    len = strlen(argv[1]);
    while (fgets(buf, sizeof buf, stdin)) {
        if (strncmp(buf, "----[", 5)) continue;
        if (sscanf(buf+5, "%4s%*2c%2s%*2c%2s%*2c %2s%*2c%2s%*2c%2s",
            date, date+4, date+6, date+8, date+10, date+12) != 6) continue;
        if (strncmp(date, argv[1], len)) continue;
        do {
            fputs(buf, stdout);
        } while (fgets(buf, sizeof buf, stdin) && buf[0] != '.');
        fputs("\n", stdout);
    }
    return 0;
}


No.2591

Re:ファイルから該当範囲のデータを取得するには
投稿者---katou(2002/09/04 11:25:50)


>インデントがおかしかったのを修正するついでに機能を追加してみました。
>
>常に、年月日時分秒を指定するのは面倒なので、どこで切ってもいいように
>しました。年月日だけを指定してもよいということです。したがって、出力
>データも複数になることがあります。
>
>また、すべての行を sscanf で調べるのは効率が悪いので、"----[" を先に
>チェックするようにしました。
><pre>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
char buf[1024], date[15]; int len;

if (argc != 2)
return printf("usage: %s yyyy[mm[dd[hh[mm[ss]]]]] <file\n", *argv), 1;
len = strlen(argv[1]);
while (fgets(buf, sizeof buf, stdin)) {
if (strncmp(buf, "----[", 5)) continue;
if (sscanf(buf+5, "%4s%*2c%2s%*2c%2s%*2c %2s%*2c%2s%*2c%2s",
date, date+4, date+6, date+8, date+10, date+12) != 6) continue;
if (strncmp(date, argv[1], len)) continue;
do {
fputs(buf, stdout);
} while (fgets(buf, sizeof buf, stdin) && buf[0] != '.');
fputs("\n", stdout);
}
return 0;
}
</pre>

年月日だけの指定では20020902100000と20020902110000と同じ年月日の
ものが複数あるときは先頭の年月日のデータを取り出すことになってしまうのではないのでしょうか。
あくまで年月日時分秒で一意と解釈したほうがいいのでは?



No.2593

ソースコードへの質問
投稿者---はじめ(2002/09/04 11:39:24)



便乗で申し訳ありませんが、コードについて教えて下さい。

初心者的な質問ですが、
stdin,stdoutを使用するとfopenやfcloseを使用しなくても
ファイルへの読み書きができるのですか。



No.2605

Re:ソースコードへの質問
投稿者---かずま(2002/09/05 11:19:32)


> stdin,stdoutを使用するとfopenやfcloseを使用しなくても
> ファイルへの読み書きができるのですか。

コマンドラインからプログラムを起動するときに、

 プログラム名 引数1 引数2 <入力ファイル名 >出力ファイル名

と打ち込むと、標準入力と標準出力がファイルに切り替えられます。
main(int argc, char *argv[]) には、この名前は渡されません。

 argc = 3
 argv[0] = "プログラム名"
 argv[1] = "引数1"
 argv[2] = "引数2"
 argv[3] = NULL

となります。標準入出力は、ファイルに切り替えないと、キーボードと
ディスプレイのままです。

No.2594

ファイルの形式が変更
投稿者---つよし(2002/09/04 12:16:58)


ファイルの形式が少し変わってしまい、以下の様になりました。
このような場合どうすればよいのですか。

---- [AAA.AAA.] PRG1 START [2002年09月01日 10時01分00秒] ----
111
222
---- [BB.CC] PRG2 START [2002年09月01日 10時02分20秒] ----
aaa
---- [ABCD.12345] PRG3 START [2002年09月01日 10時03分30秒] ----
bbb
.


No.2597

Re:ファイルの形式が変更
投稿者---かずま(2002/09/04 15:27:27)


> ファイルの形式が少し変わってしまい、以下の様になりました。

ひとつのデータは、
(1) "---- [" から、次の "---- [" の直前まで、または、
(2) "---- [" から、次の "." の直前まで、または、
(3) "---- [" から、EOF まで、
ということでしょうか。仕様をはっきり示してくださいね。
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char buf[1024], date[15];  int len, found;

    if (argc != 2) 
        return printf("usage: %s yyyy[mm[dd[hh[mm[ss]]]]] <file\n", *argv), 1;
    len = strlen(argv[1]);
    fgets(buf, sizeof buf, stdin);
    while (!feof(stdin)) {
        found = sscanf(buf, "---- [%*[^[][%4s%*2c%2s%*2c%2s%*2c%2s%*2c%2s%*2c%2s",
                        date, date+4, date+6, date+8, date+10, date+12) == 6
                && strncmp(date, argv[1], len) == 0;
        do {
            if (found) fputs(buf, stdout);
            if (fgets(buf, sizeof buf, stdin) == NULL) break;
            if (buf[0] == '.') { fgets(buf, sizeof buf, stdin); break; }
        } while (strncmp(buf, "---- [", 6));
        if (found) fputs("\n", stdout);
    }
    return 0;
}


No.2599

Re:ファイルの形式が変更
投稿者---つよし(2002/09/04 18:17:10)


>> ファイルの形式が少し変わってしまい、以下の様になりました。
>
>ひとつのデータは、
>(1) "---- [" から、次の "---- [" の直前まで、または、
>(2) "---- [" から、次の "." の直前まで、または、
>(3) "---- [" から、EOF まで、
>ということでしょうか。仕様をはっきり示してくださいね。
>
申し訳ありません。
仕様をはっきりと示していなくて申し訳ありません。
ひとつのデータは、
"---- [" から、次の "." の直前までです。
その間に、"---- [" が何回でててきてもひつのデータです。
つまりは、"."以降から"."直前までをひつのデータとして扱います。


No.2601

Re:ファイルの形式が変更
投稿者---かずま(2002/09/04 18:43:19)


> ひとつのデータは、
> "---- [" から、次の "." の直前までです。
> その間に、"---- [" が何回でててきてもひつのデータです。
> つまりは、"."以降から"."直前までをひつのデータとして扱います。
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char buf[1024], date[15];  int len, found;

    if (argc != 2) 
        return printf("usage: %s yyyy[mm[dd[hh[mm[ss]]]]] <file\n", *argv), 1;
    len = strlen(argv[1]);
    while (fgets(buf, sizeof buf, stdin)) {
        found = sscanf(buf, "---- [%*[^[][%4s%*2c%2s%*2c%2s%*2c%2s%*2c%2s%*2c%2s",
                    date, date+4, date+6, date+8, date+10, date+12) == 6
                && strncmp(date, argv[1], len) == 0;
        do {
            if (found) fputs(buf, stdout);
        } while (fgets(buf, sizeof buf, stdin) && buf[0] != '.');
        if (found) fputs("\n", stdout);
    }
    return 0;
}
このプログラムは、"." で始まる行が連続しないことを仮定しています。