ショッピングモール  Personal Health / Men's Health ( Infertility )


掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板1

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.4858

fgetcを使って大きなファイルを読めない。
投稿者---yu(2005/11/13 22:54:19)


こんばんは。fgetcで大きなファイルを途中までしか読めません。
具体的には1300 byte程度のファイルなら全て読むことが出来るのですが、
80 kbyte程度のファイルは途中まで(2048 byte)しか読めません
(The file offset is 2048.と表示されます)。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    fp = fopen(argv[1], "r");
    while(1)
    {
        if(fgetc(fp) == EOF) break;
    }
    printf("The file offset is %ld.\n", ftell(fp));
    fclose(fp);
    return 0;
}

環境: Windows 2000 sp4; Borland C++ compiler 5.5.1


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:fgetcを使って大きなファイルを読めない。 4859 επιστημη 2005/11/13 23:26:14
<子記事> Re:fgetcを使って大きなファイルを読めない。 4861 RiSK 2005/11/13 23:35:35


No.4859

Re:fgetcを使って大きなファイルを読めない。
投稿者---επιστημη(2005/11/13 23:26:14)


>こんばんは。fgetcで大きなファイルを途中までしか読めません。
>具体的には1300 byte程度のファイルなら全て読むことが出来るのですが、
>80 kbyte程度のファイルは途中まで(2048 byte)しか読めません

fp = fopen(argv[1], "rb");

ではどうなりますか? バイナリファイルをテキストとしてfopenしてませんか?



この投稿にコメントする

削除パスワード

No.4863

ありがとうございます
投稿者---yu(2005/11/14 19:00:16)


>バイナリファイルをテキストとしてfopenしてませんか?
ご指摘の通りです。
テキストファイルとしてfopenするとバッファリングするんですね。
知らなかった。。。
教えていただいた方法を使ってみます。


この投稿にコメントする

削除パスワード

No.4865

自己レス
投稿者---yu(2005/11/14 19:12:50)


fopen(argv[1], "rb");
で解決しました。επιστημηさんRiSKさん、ありがとうございました。


この投稿にコメントする

削除パスワード

No.4861

Re:fgetcを使って大きなファイルを読めない。
投稿者---RiSK(2005/11/13 23:35:35)


で,質問は?

>fgetcで大きなファイルを途中までしか読めません。

ストリームのバッファリングの問題です。

>具体的には1300 byte程度のファイルなら全て読むことが出来るのですが、
>80 kbyte程度のファイルは途中まで(2048 byte)しか読めません

バッファが(bccデフォルトの) 2048 バイトしか確保されていないからです。


解決するには,最後まで読めるくらいバッファの容量を増やすか,バッファリング無しにするかします。
バッファの容量を増やすには setbuf, setvbuf を使います。
バッファリングなしにするには,バイナリモードでオープンします。

テキストモードでオープンして,setbuf(fp, 0, _IONBF, 0);
としてもバッファリング無しになるかと思ったのですが,
VC6 では ftell で(ファイルサイズ以下の) 28 が返ってくる…。
なんでだろ?


この投稿にコメントする

削除パスワード

No.4862

Re:fgetcを使って大きなファイルを読めない。
投稿者---RiSK(2005/11/14 12:44:46)


補足と訂正。

>バッファが(bccデフォルトの) 2048 バイトしか確保されていないからです。

テキストモードでオープンした際,
 フルバッファリングの場合,
  ファイルをすべて読み込めるバッファが必要になります。
 行バッファリングする場合,
  一番長い行より大きいバッファが必要になります。


>テキストモードでオープンして,setbuf(fp, 0, _IONBF, 0);

setvbuf(fp, 0, _IONBF, 0); の間違い。


>テキストモードでオープンして,setvbuf(fp, 0, _IONBF, 0);
>としてもバッファリング無しになるかと思ったのですが,

ちゃんとバッファリング無しになります。私の実験の仕方が誤っていました。
バイナリファイルをテキストモードで開いたので,
SUB(0x1A, EOF, Windows系のCtrl+Z)までで,読み込みが止まっていました。
# 質問者がバイナリをテキストモードで開いていると思って,
# 同じような環境で実験しようとしたの…
失礼しました。

まとめると,

テキストファイルを
 テキストモードでオープンする場合,
  バッファ増やす/バッファリング無し→解決
 バイナリモードでオープンする場合,
  自動的にバッファリング無し→解決
バイナリファイルを
 テキストモードでオープンする場合,
  改行文字やEOFの問題があるのでNG
 バイナリモードでオープンする場合,
  自動的にバッファリング無し→解決

となります。


この投稿にコメントする

削除パスワード

No.4864

ありがとうございます
投稿者---yu(2005/11/14 19:07:19)


>テキストファイルを
> テキストモードでオープンする場合,
>  バッファ増やす/バッファリング無し→解決
> バイナリモードでオープンする場合,
>  自動的にバッファリング無し→解決
>バイナリファイルを
> テキストモードでオープンする場合,
>  改行文字やEOFの問題があるのでNG
> バイナリモードでオープンする場合,
>  自動的にバッファリング無し→解決
>
>となります。

丁寧にまとめてもらって、ありがとうございます。
僕の場合バイナリをテキストとしてfopenしたのが問題みたいです。
また、バッファリングをfopenの後で止めることも出来るんですね。
教えていただいた方法を使ってみます。


この投稿にコメントする

削除パスワード

No.4866

Re:fgetcを使って大きなファイルを読めない。
投稿者---かずま(2005/11/15 08:52:06)


> バッファが(bccデフォルトの) 2048 バイトしか確保されていないからです。

512バイトです。
コマンド引数にファイル名を指定して次のプログラムを実行してみてください。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fp;

    if (argc != 2) return 1;
    fp = fopen(argv[1], "r");
    if (!fp) return 1;
    printf("fp->bsize=%d\n", fp->bsize);
    fclose(fp);
    return 0;
}

> テキストモードでオープンした際,
>  フルバッファリングの場合,
>   ファイルをすべて読み込めるバッファが必要になります。
>  行バッファリングする場合,
>   一番長い行より大きいバッファが必要になります。

バッファのサイズは関係ありません。そうでないと、次のプログラムで
どんなサイズのテキストファイルでもコピーできることが説明できません。
#include <stdio.h>

int main(int argc, char *argv[])
{
    FILE *fin, *fout;  int c;

    if (argc != 3) return 1;
    fin = fopen(argv[1], "r");
    if (!fin) return 1;
    fout = fopen(argv[2], "w");
    if (!fout) return 1;
    while ((c = fgetc(fin)) != EOF)
        fputc(c, fout);
    fclose(fout);
    fclose(fin);
    return 0;
}



この投稿にコメントする

削除パスワード

No.4868

Re:fgetcを使って大きなファイルを読めない。
投稿者---RiSK(2005/11/15 22:29:32)


>> バッファが(bccデフォルトの) 2048 バイトしか確保されていないからです。
>
>512バイトです。
>コマンド引数にファイル名を指定して次のプログラムを実行してみてください。

あら...確かに 512 バイトですね。BUFSIZ も 512 と定義されていました。

>バッファのサイズは関係ありません。そうでないと、次のプログラムで
>どんなサイズのテキストファイルでもコピーできることが説明できません。

仰るとおりです。


では何が原因なのか,調べた結果を報告します。

ftell の使い方が間違っていました。
JIS X3010 7.19.9.4より引用:
バイナリストリームの場合,その値はファイルの始めからの文字数である。

ですが,
テキストストリームの場合,そのファイル位置表示子は,本関数の呼出し時の位置にそのストリームに対応するファイル位置表示子を戻すために,fseek関数で使用できる情報を含む。ただし,この情報の内容は規定されない。このとき,本関数の2回の呼出しの返却値の差は,必ずしも書き込み文字数または読取り文字数の意味とは限らない。

だそうです。
テキストストリームを ftell した結果を fseek に渡すのは妥当だが,
それ以外の用途には未規定なので,使っちゃダメだと解釈しました。

確認プログラム。ftell と i の値が違う。
#include <stdio.h>
int main(int argc, char *argv[])
{
    FILE *fp;
    int i;

    fp = fopen(argv[1], "r");
    for (i = 0; fgetc(fp) != EOF; ++i) ;
    printf("ftell(fp) = %d\n", ftell(fp));
    printf("i = %d\n", i);
    fclose(fp);
    return 0;
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity