C言語関係掲示板

過去ログ

No.1185 ファイルの指定行に文字列を書き出す方法

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

ファイルの指定行に文字列を書き出す方法
投稿者---ぜろ(2004/07/14 15:02:45)


初めて質問致します。
よろしくお願い致します。

ファイルをオープンして、決められた行番号に文字列を格納する
という処理を行いたいのです。
例えば、「5行目にりんごという文字列を書き出す」ためには、
どのようにしたらよいのでしょうか。
私は、改行が4個読み込めたら、そこにりんごと書き出す方法を
考えました。
しかし、4行読み込んでその後に書き込むことはできるのでしょうか。
やはり、文字列を配列に格納し、1回ファイルをクローズして、
またオープンして追加する?のような処理になるのでしょうか。

質問ばかりで申し訳ありません。
ぜひご助言を賜りたいです。


No.15522

Re:ファイルの指定行に文字列を書き出す方法
投稿者---ZAQ(2004/07/14 20:58:19)


fseek を使ってみてはどうですか?


No.15525

Re:ファイルの指定行に文字列を書き出す方法
投稿者---NykR(2004/07/14 22:18:13)


>私は、改行が4個読み込めたら、そこにりんごと書き出す方法を
>考えました。
>しかし、4行読み込んでその後に書き込むことはできるのでしょうか。
>やはり、文字列を配列に格納し、1回ファイルをクローズして、
>またオープンして追加する?のような処理になるのでしょうか。

ファイルをもう一つ、書き込みモードで開いてそっちに書き込んでから、元のファイルにrenameするのが簡単だと思います。

「もう一つのファイル」と同名のファイルがすでに存在していたら、上書きされてしまうので気をつけなければいけませんが。

そういう事態は、こういう関数を使うことである程度は防げるかも知れません。
#include <stdio.h>

#define LOWER "abcdefghijklmnopqrstuvwxyz"

char * getUniqueFile(char * dest, size_t size)
{
    int         i, j;
    FILE        *fp;

    for (i = 0; i < size - 1; i++) {
        dest[i+1] = '\0';

        for (j = 0; j < sizeof(LOWER) - 1; i++) {
            dest[i] = LOWER[j];

            // 読みとりモードで開けなかったら
            // destに格納されている文字列と同名のファイルは存在しない(多分)
            if ((fp = fopen(dest, "r")) == NULL) {

                // ファイルをとりあえず作って、
                // 次の呼び出し時に同じ名前を返すのを防ぐ
                fclose(fopen(dest, "w"));
                return dest;
            }
            fclose(fp);
        }
    }

    return NULL;
}



No.15543

Re:ファイルの指定行に文字列を書き出す方法
投稿者---ぜろ(2004/07/15 11:06:50)


早速回答ありがとうございます。

fseek関数を使用する場合を考えてみました。
fseek関数は、ファイルポインタの参照位置をoriginで指定された位置を
基点にoffsetバイトの位置に移動させるということですが、バイトだと行
をかえることはできないのでは、と思いました。改行文字がある場合は、
offsetを1に指定するとファイルポインタの参照位置は次の行になるので
しょうか。

回答して頂いたのに、その意味を理解できなくて申し訳ありません。
よろしくお願いいたします。


No.15545

Re:ファイルの指定行に文字列を書き出す方法
投稿者---REE(2004/07/15 13:11:18)


>ファイルをオープンして、決められた行番号に文字列を格納する
>という処理を行いたいのです。
>例えば、「5行目にりんごという文字列を書き出す」ためには、
>どのようにしたらよいのでしょうか。
>私は、改行が4個読み込めたら、そこにりんごと書き出す方法を
>考えました。
>しかし、4行読み込んでその後に書き込むことはできるのでしょうか。

できます。
但し、挿入ではなく上書きになってしまいます。

>やはり、文字列を配列に格納し、1回ファイルをクローズして、
>またオープンして追加する?のような処理になるのでしょうか。

そういう方法もありますが、安全性から別のファイルに一度出力した方がいいと思います。
そうすれば、全ての文字列を記憶する必要もなくなります。

1.入出力の両ファイルを開く
2.入力ファイルから、挿入位置まで出力ファイルにコピーする
3.追加する文字を出力ファイルに書き込む
4.入力ファイルの、残りを出力ファイルにコピーする

# ここでのコピーは読み込んだデータをそのまま書くことを表しています。

ちなみにfseekではお望みのことは出来ません。



No.15555

Re:ファイルの指定行に文字列を書き出す方法
投稿者---円零(2004/07/15 18:52:06)


>ちなみにfseekではお望みのことは出来ません。

fseekでも行けるみたいです。効率は知りませんが…
#include <stdio.h>

int main(void){
    FILE *fp;
    int i, ins;
    unsigned char m = 0, n;
    char c, filename[256], buf[256];
    long getpos, putpos;

    printf("ファイル名:");
    gets(filename);
    printf("何行目に挿入しますか:");
    scanf("%d", &ins);
    ins--;
    rewind(stdin);
    printf("挿入文字列:");
    fgets(buf, 256, stdin);
    n = strlen(buf);
    if( (fp = fopen(filename, "r+")) == NULL )exit(1);

    /*** ins行目まで改行を読み飛ばす ***/
    for(i = 0; i < ins; i++){
        while( (c = fgetc(fp)) != '\n'){
            if(c == EOF){
                fputc('\n', fp);
                fseek(fp, 0, SEEK_END);
                break;
            }
        }
    }

    /*** 一文字削っては一文字足す ***/
    getpos = putpos = ftell(fp);
    while( buf[m] != EOF ){
        fseek(fp, getpos, SEEK_SET);
        buf[n++] = fgetc(fp);
        getpos = ftell(fp);
        fseek(fp, putpos, SEEK_SET);
        fputc(buf[m++], fp);
        putpos = ftell(fp);
    }
    fclose(fp);
    return 0;
}



No.15556

Re:ファイルの指定行に文字列を書き出す方法
投稿者---REE(2004/07/15 19:21:29)


>>ちなみにfseekではお望みのことは出来ません。
>
>fseekでも行けるみたいです。効率は知りませんが…

なるほど、挿入処理のために使うのですね。
バッファをオーバーフローしないようにリングバッファにして、
1バイト単位ではなく数kbyte単位で行えば、実用レベルの速度にはなりそうですね。



No.15572

ありがとうございました!!
投稿者---ぜろ(2004/07/16 10:41:11)


ZAQさん、NykRさん、REEさん、円零さん、
質問に答えていただいてありがとうございました!
皆さんのアドバイスを参考に解決することが出来ました。

ありがとうございました。