No.5ベストアンサー
- 回答日時:
>mallocで取れるだけ領域を取ってそこからその
処理系や環境によりますがWindowsやLinuxの場合100Mぐらいは余裕でとれてしまいます。
>構造体の途中からfreadすることって可能でしょうか?
可能です。
memcpy( (char*)s+読み込んだバイト , pBuf , structSize - (読み込んだバイト) );
みたいな感じになります。
sizeを読み込んでから切れる場合と、sizeの前で切れる場合があるので
sizeの前で切れた場合は次のバッファを読み込んでから構造体のサイズを確定する処理
をする必要があるでしょう。
ただ構造体のalignmentには注意してください。
例えば
typedef struct _S{
char a;
short b;
}S;
の場合3バイトとは限りません。コンパイラの設定によっては
paddingの部分で切れる可能性も考慮する必要があります。
No.7
- 回答日時:
実装例: #3のソースを改良したバージョン(解説は省略します、実際のテストは行っていません)
/* 1つの可変長・構造体データの最大バイト数(最低でも構造体サイズ+文字配列サイズ以上) */
#define MAX_SIZE (1024 * 1024) ←可能な限り大きいサイズで読み込む回数を減らせます
/* 可変長構造体のファイルからcsv形式のファイルへ出力 */
void FuncRead( FILE *fp, FILE *fo )
{
size_t size; /* 読み込んだバイト数 */
char *buff; /* 読み込むバッファ領域(先頭位置) */
char *last; /* 読み込むバッファ領域(最終位置) */
char *seek; /* 参照したバッファ位置(現在位置) */
構造体(仮) *data; /* 参照する構造体へのポインタ */
if ( (buff = malloc(MAX_SIZE)) != NULL ){
while ( (size = fread(buff,1,MAX_SIZE,fp)) != 0 ){
last = (buff + size);
seek = (buff);
data = (構造体(仮) *)seek;
while ( (data->str + data->size - 1) < last ){
FuncWrite( data, fo ); ←構造体(仮)のデータを出力させる関数
seek += (sizeof(構造体(仮)) + data->size - 1);
data = (構造体(仮) *)seek;
}
if ( feof(fp) ){
break;
}
fseek( fp, -(size_t)(last - seek), SEEK_CUR ); ←ファイルポインタを戻る
}
free( buff );
}
}
/*
●引数
(1)入力ファイルのポインタを fp で指定
(2)出力ファイルのポインタを fo で指定
●その他
void FuncWrite( 構造体(仮) *data, FILE fo );
●注意
・1つの可変長・構造体データは、構造体サイズ+data->size-1ですよ。
・文字配列が文字列ならば、NULL文字分を考えて上記ソースの-1は削除しましょう。
*/
改良版ありがとうございます。
とりあえず内容を見てみました。
このソースの処理は、
> while ( (data->str + data->size - 1) < last ){
> fseek( fp, -(size_t)(last - seek), SEEK_CUR ); ←ファイルポインタを戻る
のところを見る限り構造体全体が読めなかったら
ファイルポインタを読めなかった構造体の最初に戻って読み直すという
処理をしているみたいですね。
構造体の途中から読むということもしないので無難かもしれませんね。
No.6
- 回答日時:
#5です。
追記です。例えば1024バイトのバッファで何回も読み込んでいくような方式を考えた場合に
構造体のsizeが5000バイトを超えるようなパターンもありますね。
この回答への補足
あ、多分これは大丈夫です。
10Mぐらいのバッファで構造体もバッファより大きいものは存在しない予定なので・・・
それとついでの質問なのですが、
mallocで取れるバッファのサイズを調べる関数とかあるのでしょうか?
No.3
- 回答日時:
最初にftellでファイルサイズを取得しmallocで領域を確保し
freadで全部メモリーに読み込めばいいのでは?
そうすれな読み込み回数は1回で済みますから。
ファイルサイズが大きくmallocで確保できないような連続領域が必要なら
無理ですが。
簡単に書くとこんなかんじでしょうか。(なんのエラー処理もしていません)
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct _STRUCT
{
char c1,c2;
float f1,f2;
double d;
int size;
char str[1];
}STRUCT;
int main()
{
size_t structSize;
STRUCT* s;
char* pBuf;
size_t FileSize;
size_t ReadSize = 0;
FILE* fp = fopen("hoge.dat","rb");
fseek(fp,0,SEEK_END);
FileSize = ftell(fp);
printf("FileSize=%u\n",FileSize);
fseek(fp,0,SEEK_SET);
pBuf = (char*)malloc(FileSize);
fread(pBuf,FileSize,1,fp);
fclose(fp);
while( ReadSize < FileSize ){
structSize = sizeof(STRUCT) - sizeof(char) + ((STRUCT*)pBuf)->size;
s = (STRUCT*)malloc(structSize);
memcpy( s , pBuf , structSize );
printf("%s\n",s->str);
free( s );
ReadSize += structSize;
pBuf+=structSize;
}
free(pBuf);
}
この回答への補足
ありがとうです。
自分のしたかったことに近いです。
ですがファイルサイズがでかくなることも想定しているので
mallocで取れるだけ領域を取ってそこからその処理をして、
領域の最後に達したらファイルから読み直すという処理をつけたいと思ってます。
ですがそうした場合、構造体の途中までしか読めていない状況が発生すると思っています。
その場合欠けた部分より後はfreadで読み込む処理を入れなくてはいけない気がします。
ですが構造体の途中からfreadすることって可能でしょうか?
No.2
- 回答日時:
typedef struct 構造体(仮) {
char c1, c2;
float f1, f2;
double d;
int size;
chear str[1];
} 構造体(仮);
の形だと (構造体タグって必要?), 実際に使うにはこの構造体に対して malloc しないといけないんだけどその辺は OK? まあいいとして, 基本的には
0.仮にデータを保存しておく構造体を用意する
1.size まで fread
2.その size に従って構造体を malloc する
3.size のところまで memcpy
4,size の分だけ fread
の順. 今の ISO C なら str を
char str[];
で宣言できて, この場合には
{
構造体(仮) dummy, *data;
fread(&dummy, sizeof dummy, 1, fp);
data = malloc(sizeof *data + dummy.size);
memcpy(&dummy, data, sizeof dummy);
fread(data->str, 1, data->size, fp);
}
くらいになるかと.
1の方の方法をソースで書いてくれたのですね。
ありがとうです。
・・・ですが1の方のところで書いたとおりその方法は考えてはいました。
もう少し詳しく書いておくべきでしたね、すみません。
No.1
- 回答日時:
私だったら、
void hoge( int fd ) {
構造体(仮) kari;
int sz, cc;
char *str;
sz = (int) ( (void*) &kari - (void*) &kari.str );
cc = read( fd, &kari, sz );
/* cc をチェック */
str = (char*) malloc( kari.size );
/* str をチェック */
cc = read( fd, str, kari.size );
/* cc をチェック */
}
てな感じでしょうか。要は構造体(仮)のsizeまで最初に読みこんでから、size を見て、文字列を読むだけです。
ファイルを読み込む回数ですが、Linux とか最近のOSではメモリにキャッシュされるので、回数は昔ほど気にしなくても大丈夫です。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
CStringからchar*への型変換に...
-
C言語の文字リテラル中の16進文...
-
C言語にて構造体のメンバがNULL...
-
C言語で文字列をかえす正しい書...
-
小数点入りの文字列をfloat型に...
-
char 文字列型 の表現範囲が-12...
-
const char* s1とただのchar s1...
-
文字型配列に格納した空白の切捨て
-
36進数
-
#include <stdio.h> #include <...
-
ポインタを使って回文かどうか...
-
#include <stdio.h> int main(v...
-
C言語入門者です。今ポインタの...
-
[C] 構造体メンバーのカンマ区...
-
C++17で、unsigned char * 配列...
-
c言語の構造体について質問します
-
文字列の比較
-
動的メモリの初期化方法について。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
CStringからchar*への型変換に...
-
C言語にて構造体のメンバがNULL...
-
fstream型オブジェクトを関数の...
-
小数点入りの文字列をfloat型に...
-
char型にint型の数値を代入する。
-
const char* s1とただのchar s1...
-
new charとnew char[N]の違いは?
-
動的メモリの初期化方法について。
-
エクセルのMID関数は、C言語では?
-
C言語 strstrの実装
-
SetWindowTextについて。
-
char 文字列型 の表現範囲が-12...
-
文字列の途中から途中までを抽出
-
2次元配列の文字"列"の初期化方法
-
DWORDとcharの変換
-
C++17で、unsigned char * 配列...
-
C言語の文字リテラル中の16進文...
-
strcat関数を自作したいです
おすすめ情報