2012-03-25 7 views
3

これが私の問題を解決する最善の方法であるかどうか疑問に思っています。Cでバイナリファイルの特定の場所に移動し(fseekを使用)、その場所から読み取る(freadを使用)

私は、必要な情報が保持されているバイナリファイルの特定のオフセットの値を知っています...私がしたいのは、オフセットにジャンプし、その位置から開始して一定量のバイトを読み込むことです。

Googleを使用した後、私は、fseek()を使用してオフセットの位置に移動し、fread()を使用してその位置からバイト数を読み取ることが最善の策であると判断しました。

これは正しいと思いますか?もしそうなら、そのようにするのが最善でしょうか? 2つの方法を組み合わせる方法

私が正しくない場合は、代わりに何を提案しますか?

ご協力いただきありがとうございます。

マット

編集

私は(関数freadのチュートリアルに従っ)、以下にそれを調整する:

`#include <stdio.h> 
    int main() 
    { 
     FILE *f; 
     char buffer[11]; 
     if (f = fopen("comm_array2.img", "rt")) 
     { 
     fread(buffer, 1, 10, f); 
     buffer[10] = 0; 
     fclose(f); 
     printf("first 10 characters of the file:\n%s\n", buffer); 
     } 
     return 0; 
    }` 

だから私は 'comm_array2.img' ファイルを使用し、ファイルから最初の10文字を読み取ります。

しかし、私はそれを理解して何から、これはスタート・オブ・ファイルから行く、私は

この作るより多くの意味です(オフセット)いくつかのインプレース・イン・ファイルから行きたいですか?

編集ナンバー2:

私が少し薄暗いされていたことが表示されます、そしてすべてのことが必要とされている(それは私の試みからと思われる)私が持っている)のfread(前のfseek()を置くことです上記のコードでは、その場所を探してそこから読み込みます。

+2

はい。 fseek()とfread()を使用します。どのコードを試しましたか? – erisco

+1

はい、そうですが、あなたの質問や問題は何ですか? –

+0

ウェブ上でそれらを使用する方法を示すチュートリアルがあります。検索用語「fseek fread Cチュートリアル」を使用して、いくつかを見つけるのは簡単です。あなたは何かを経験しましたか? – gbulmer

答えて

2

ファイルディスクリプタの代わりにファイルストリームを使用している場合は、POSIX pread()システムコールに類似した(シンプルな)関数を書くことができます。

ファイルディスクリプタの代わりにストリームを使用して容易にエミュレートできます。おそらく、あなたは自分自身(私はコメントで提案1からわずかに異なるインタフェースを持っている)このような関数を記述する必要があります

size_t fpread(void *buffer, size_t size, size_t mitems, size_t offset, FILE *fp) 
{ 
    if (fseek(fp, offset, SEEK_SET) != 0) 
     return 0; 
    return fread(buffer, size, nitems, fp); 
} 

これはpread()fread()の規則間の妥当な妥協です。


関数呼び出しの構文は次のように何を求めますか?たとえば、オフセット732から読み込み、次にオフセット432(両方ともファイルの先頭からの読み込み)から読み込み、ファイルストリームはfと呼ばれます。

読み込むバイト数は指定していないので、毎回100と仮定します。私は、ターゲット変数(バッファ)がbuffer1buffer2であり、両方とも十分に大きいと仮定しています。

if (fpread(buffer1, 100, 1, 732, f) != 1) 
    ...error reading at offset 732... 
if (fpread(buffer2, 100, 1, 432, f) != 1) 
    ...error reading at offset 432... 

戻りカウントは100バイトの完全な単位の数です。 1(すべて取得)または0(何かがうんざり)。

そのコードを書いて、他の方法があります。

if (fpread(buffer1, sizeof(char), 100, 732, f) != 100) 
    ...error reading at offset 732... 
if (fpread(buffer2, sizeof(char), 100, 432, f) != 100) 
    ...error reading at offset 432... 

これは100のシングルバイトを毎回読み込みます。このテストでは、期待どおり100個のテストがすべて確実に得られます。この2番目の例で戻り値を取得すると、取得したデータの量を知ることができます。最初の読み取りが成功し、2番目の読み取りが失敗した場合は非常に驚くべきことです。他のプログラム(またはスレッド)はfpread()への2つの呼び出しの間にファイルを切り捨てる必要がありましたが、もっと楽しいことが起こることが知られていました。


エミュレーションは完璧ではありません。 pread()コールでは、fseek()fread()の組み合わせが提供されないことが保証されたアトミック性を提供します。しかし、実際には問題になることはほとんどありません。複数のプロセスやスレッドが、ファイルの配置や読み込みを同時に行っている場合を除き、それはほとんど問題になりません。

+0

ありがとう、私は少しあなたのコメントに行くようにしていたと私は先制感謝したので、ありがとう。 私はこの権利を理解していれば、その関数を作成し、もともとpreadを使用していたのと同じで、ファイルディスクリプタではなくファイル名を渡してオフセットします。 – user1291631

+0

並べ替えの...あなたのコメントはファイル名に言及していますが、 'fread()'と 'fseek()'のどちらもファイル名では動作しません。それは 'fopen()'の仕事です。 'fpread()'関数は 'fseek()'と 'fread()'の呼び出しを置き換えるものです。明らかに、ファイル名を取りたい場合は、関数内のファイルを 'fopen()'して(おそらく) 'fclose()'する必要があり、 'fp'パラメータを渡すことはありません。ファイル名を最初の引数として指定します。読み込みのためにバイナリファイルを開くには '' rb "'を使います。 bがUNIX上にあるかどうかは関係ありませんが、他のプラットフォームではそうです。 –

+0

ああ、私が言っていた私の謝罪は、何か 'fp'(つまり、私が理解しているようにfopen()を使ったときに返されるもの)を渡します。しかし、あなたのコメントから、 'fp'パラメータ? – user1291631

0

あなたの理論は正しいと思います。オープン、シーク、リード、クローズ。

読み込みたいデータの構造体を作成し、構造体の割り当てられたメモリのread()へのポインタを渡します。 #pragma pack(1)やそれに類するものが構造上に必要になります。

1

頻繁に気になる部分の間の距離によって異なります。気になる部分の間に数バイトを飛ばしたり無視したりする場合は、それをスキップするのにfseekを使用するのではなく、そのデータを読み込んだり無視したりする方が簡単です。これを行う典型的な方法は、関心のあるデータと気にしないデータのためのプレースホルダの両方を保持する構造体を定義し、構造体を読み込んで気になる部分を使うだけです:

struct whatever { 
    long a; 
    long ignore; 
    short b; 
} w; 

fread(&w, 1, sizeof(w), some_file); 

// use 'w.a' and 'w.b' here. 

あなたが心配している部品の間に大きな距離がある場合は、重要な部品に手を加えるためにfseekを使用するという独自の考え方がより簡単になる可能性があります。

関連する問題