ページ 11

fseek()

Posted: 2015年2月12日(木) 00:35
by jenga
テキストファイル読み込みについての質問です。

fopen()関数にてテキストファイルをテキストモードで開き、
fgetc()関数で1文字ずつファイル内容を取得していく途中で、
ファイルポインタを戻す処理を行いたく、fseek()関数を利用しようとしたのですがうまくいきません。
解決策や、代理案を模索していたのですがなかなか見つからず。。。 何かいい案はないでしょうか?

以下、テスト作成して 思うように動作しなかったソースコード

コード:

#include <stdio.h>

void main(void){
	long Base;						// 戻したいファイルポインタ位置を記録
	FILE *fp = fopen("test.txt", "rt");		// ファイルオープン
	
	/*** 読み込みエラーチェック ***/
	if(fp != NULL){
		fgetc(fp);
		fgetc(fp);
		Base = ftell(fp);				// 戻したい位置を記録しておく
		fgetc(fp);
		fgetc(fp);

		fseek(fp, Base, SEEK_SET);		// あらかじめ記録しておいた位置へファイルポインタを戻す

		fclose(fp);
	}
}

Re: fseek()

Posted: 2015年2月12日(木) 00:58
by かずま
jenga さんが書きました: 以下、テスト作成して 思うように動作しなかったソースコード
そのプログラムは、変数 c が定義されていないのでコンパイルできません。
c を定義してコンパイルし、実行しても何も表示しないので
何がうまくいかないのかわかりません。
test.txt の中身は何ですか?

fseek が思い通りに動くことは次のプログラムでわかります。

コード:

#include <stdio.h>
 
int main(void)
{
    int c;
    long Base;
    FILE *fp = fopen("test.txt", "r");
    if (fp != NULL) {
        c = fgetc(fp); putchar(c);
        c = fgetc(fp); putchar(c);
        Base = ftell(fp);
        c = fgetc(fp); putchar(c);
        c = fgetc(fp); putchar(c);
        fseek(fp, Base, SEEK_SET);
        c = fgetc(fp); putchar(c);
        c = fgetc(fp); putchar(c);
        fclose(fp);
    }
	return 0;
}
test.txt

コード:

abcdefghijklmnopqrstuvwxyz
実行結果

コード:

abcdcd

Re: fseek()

Posted: 2015年2月12日(木) 01:10
by かずま
かずま さんが書きました: そのプログラムは、変数 c が定義されていないのでコンパイルできません。
c を定義してコンパイルし、実行しても何も表示しないので
何がうまくいかないのかわかりません。
すみません。ちょっと勘違いしていました。
元のプログラムを見て、表示が何もないので
これでは何がうまくいかないのかわからないと思い、
fgetc(fp); を c = fgetc(fp); putchar(c); に置き換えて
コンパイルしたら、c が定義されていないとなった、ということです。

「うまくいかない」というだけの質問はよろしくありません。
ソースプログラムと、具体的な入力データと、
期待する実行結果と、実際の実行結果を提示しましょう。

Re: fseek()

Posted: 2015年2月12日(木) 01:23
by jenga
どうやら勘違いだったようです。 お騒がせしました!
載せていただいたコードを確認しましたところ、正常動作しました。

もともと別のプログラムにてfseek()を利用していたのですが、
デバッグ中にウォッチでファイルポインタの指す位置を見ていて、fseek()を実行した直後に
ファイルポインタの示す値がファイルの先頭になっていたため、「おかしいな?」と思い
新しく作った 掲載プログラムにてfseek()の動作確認をしたところ、まったく同じ症状が出たために質問させていただきましたが、

正常動作するプログラムでも同じ症状が出ることがわかりました。
VisualStudio2010の仕様かバグか、私のPCの問題かどうかはわかりませんが、とりあえず問題は解決しました!

すばやい回答ありがとうございました!

Re: fseek()

Posted: 2015年2月12日(木) 01:35
by かずま
jenga さんが書きました: もともと別のプログラムにてfseek()を利用していたのですが、
デバッグ中にウォッチでファイルポインタの指す位置を見ていて、fseek()を実行した直後に
ファイルポインタの示す値がファイルの先頭になっていたため、「おかしいな?」と思い
新しく作った 掲載プログラムにてfseek()の動作確認をしたところ、まったく同じ症状が出たために質問させていただきましたが、
ウォッチでファイルポインタの指す位置を見る方法を教えてください。

Re: fseek()

Posted: 2015年2月15日(日) 15:05
by かずま
jenga さんが書きました: もともと別のプログラムにてfseek()を利用していたのですが、
デバッグ中にウォッチでファイルポインタの指す位置を見ていて、fseek()を実行した直後に
ファイルポインタの示す値がファイルの先頭になっていたため、「おかしいな?」と思い
新しく作った 掲載プログラムにてfseek()の動作確認をしたところ、まったく同じ症状が出たために質問させていただきましたが、

正常動作するプログラムでも同じ症状が出ることがわかりました。
VisualStudio2010の仕様かバグか、私のPCの問題かどうかはわかりませんが、とりあえず問題は解決しました!
Visual Studio のウォッチは変数または式の値を見るものです。
元のプログラムの変数は fp と Base だけです。

MSDN のドキュメントには、fseek は、「指定した場所にファイル
ポインターを移動します。」と記述されています。

質問者は、fp がファイルポンタだと勘違いし、
fopen実行直後と fseek実行直後で fp の値が変わっていないので
fseekのバグだと思い込んだようです。

http://linuxjm.sourceforge.jp/html/LDP_ ... eek.3.html
には、「fseek() 関数は stream によって指定されたストリームにおいて、
ファイル位置表示子 (file position indicator) をセットする。新たな
位置 (バイト単位)は whenceで指定された位置に offset バイトを
加えることによって与えられる。」とあります。

ファイル位置表示子は、ファイルの読み書きをする位置ですが、
これは ftell で取得しないとわかりません。
fseek の後に Base = ftell(fp) を実行して、その Base をウォッチ
すれば、fseek のバグではないことが分かるでしょう。