アプリ版:「スタンプのみでお礼する」機能のリリースについて

ファイルのアクセス位置を最後から7行目に移動させるプログラムを作っています。
\nを数えることで行数を数えているのですが、以下の処理、間違えていますか?
コンパイルしてもできていないので間違えていることは明白なのですが、どこが違うかわかりません。
誰か、力になってください!

fseek(fp, -1, SEEK_END);/*読込位置最後にする */
while(!fseek(fp, -2, SEEK_CUR))/*逆順読込ループ*/
{
  if(getc(fp)=='\n')
 {cnt++;}
 if(cnt == 7)
 {break;}
}

A 回答 (5件)

こんな感じはどうでしょうか。



FILE *fp;
char c;
int cnt=0;
int cr_lf=0;

fp = fopen("hoge.txt", "r");
fseek(fp, -1L, SEEK_END);
do {
c=getc(fp);
if(cr_lf==0 && (c==0x0D || c==0x0A)){
cnt++;
cr_lf=1;
} else cr_lf=0;
if(cnt==7) break;
} while(fseek(fp, -2L, SEEK_CUR)==0);

fclose(fp);
    • good
    • 0

テキストストリームの場合、fseek関数はSEEK_CURでもSEEK_ENDでもオフセットには0しか指定できません。


というのも、ファイルに格納されている一文字と、プログラムから読み込んだときの一文字が、(文字数も値も)必ずしも対応しないからです。そのため、前から読まないと辻褄が合わなくなります。

典型的なものとしては改行文字で、例えばWindowsでは、ファイルには{ '\r', '\n' }の二文字が格納されているものが、プログラムから読み込むと{ '\n' }一文字になります。fseek関数でオフセットを指定する場合、普通はファイル上でのバイト数を指定する必要があるので、改行文字のところではオフセットを2に数えなければなりません。
他にも、処理系によってはロケール等に応じて更に状態が変化する可能性があります。

バイナリストリームの場合、上記のような問題はありませんが、今度はSEEK_ENDを指定しても、ファイルの終端に位置づけられる保証がなくなります。
つまり、結局は先頭から読んでいく以外に方法はありません。

なお、処理系を特定した場合にはこの限りではありません。
    • good
    • 0

ちょっと見ただけですが、疑問に思った箇所があったのでソースを直してみました。



int r;
fseek(fp, 0L, SEEK_END);
r = fseek(fp, -1L, SEEK_CUR);
while(!r)
{
  if(getc(fp)=='\n')
 {cnt++;}
 if(cnt == 7)
 {break;}
 r = fseek(fp, -2L, SEEK_CUR);
}

つまり、初回はまだ読んでないのでポインタを一つ戻すだけでよいのでは。
    • good
    • 0

\nは 0Dhと0Ahの複合になりますね。


(CRとLF)
ですので、キャラクタで判定するなら、バイナリの0x0Dなどで行ってみては如何でしょうか?

自信はありません。
    • good
    • 0

変数 cnt を初期化していますか?

    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!