objective c 構造体をファイルに保存したい

構造体をファイルに保存して使用する方法が分かりません。

ファイルの生成はググれば分かると思うのですが、

ファイルを生成した後、構造体のデータをファイルに書き込んで置く方法が分かりません。

どうしたら良いでしょう?

Cをやっていた頃の考えで想像すると、

ファイルに文字列を書き込んでいくやり方になりますが、

それでは手間がかかりすぎます。

直接データをファイルに書き込むという方法はないのでしょうか?

Mac OS X (10.6.8)

投稿日 2012/09/15 10:29

返信
返信: 14

2012/09/17 14:53 Stripe への返信

CHARACTER *Chと言う構造体があった場合、

Chをそのまま保存する手段がないという事でしょうか?


プロジェクトを立ち上げるときにCreate Document Based Applicationってありますが、

あんな感じで保存は出来ないのでしょうか?

また、Create Document Based Applicationに途中から決定するにはどうすれば良いのでしょうか?

2012/09/17 15:47 キリー への返信

キリー さんによる書き込み:


Cをやっていた頃の考えで想像すると、

ファイルに文字列を書き込んでいくやり方になりますが、

それでは手間がかかりすぎます。

直接データをファイルに書き込むという方法はないのでしょうか?

ANSI Cなどの構造体の先頭アドレスを指定してファイルにアクセスさせれば、バイナリで処理出来る為、わざわざ文字列に変換する必要がないと思いますが、如何のものでしょうか?

2012/09/17 16:09 蝦夷_オカメの親 への返信

ありがとうございます。

しかし、その方法でやってみたのですが、

何故かアクセスバイオレーションっぽいエラーが出ます。

-(IBAction)SaveBtn:(id)sender{

Ch = ctop;

fp = fopen("sbdata.txt", "wb");

fwrite(&Ch, sizeof(Ch)*255, 100, fp);

fprintf(fp, "¥n");

fclose(fp);

}

-(IBAction)CancelBtn:(id)sender{

Ch = ctop;

fp = fopen("sbdata.txt", "rb");


fread(&Ch, sizeof(Ch)*255, 100, fp);

fclose(fp);

}


セーブボタンにて、ファイルを保存。

キャンセルボタンにて、ファイルを読み込みをやってみたのですが、

何故かアクセスバイオレーションになります。

一体何が原因かと思われますか?


typedef struct _FUKULAYER{

int no;

NSMutableString *layerName;

NSImage *layer;

int layerNo;

NSRect src;

bool invisible;

int x;

int y;

struct _FUKULAYER *next;

}FUKULAYER;


typedef struct _CHARACTER{

int no;

NSMutableString *name;

FUKULAYER *fk;

struct _CHARACTER *next;

}CHARACTER;


CHARACTER *Ch;


構造体はこんな感じです

2012/09/17 17:12 キリー への返信

すみません、上のボタンの関数は間違えました。

-(IBAction)SaveBtn:(id)sender{

fp = fopen("sbdata.txt", "wb");



fwrite(&Ch, sizeof(Ch), 1, fp);


fclose(fp);

}

-(IBAction)CancelBtn:(id)sender{

fp = fopen("sbdata.txt", "rb");


fread(&Ch, sizeof(Ch), 1, fp);


fclose(fp);

}

例えば、このようにした場合、

書き込まれるのは、Chの自身のポインターだけでしょうか?

typedef struct _CHARACTER{

int no;

NSMutableString *name;

FUKULAYER *fk;

struct _CHARACTER *next;

}CHARACTER;


で、参照している、 nextのポインターアドレスも書き加えられますか?

また、nextのnext Ch->next->nextも書き加えられますか?

関数の所で、項目数が、1になっていますが、このような構造体の場合、

nextの値もひっくるめて、sizeofがChとなるのでしょうか?

その辺の所を教えてください。お願いします。


あと、freadの&Chでちゃんとアドレスにファイルの値が代入されているのでしょうか?

2012/09/17 17:42 キリー への返信

気づきましたが、ファイルが生成されません。

objective C ではC言語のファイル生成ではいけないのでしょうか?

また、NSDataとNSFileHandleによる

NSFileHandle *fileHandle;

NSData *data;

[fileHandle writeData:data];


などのやり方がありますが、やはりそこに構造体を組み込むのは難しいのでしょうか?

2012/09/18 02:42 キリー への返信

struct X {
    int a;
    int b;
};


このような構造体なら、ただの8バイトのデータなので、構造体のポインタを起点に8バイトをファイルに書き出すだけです。


struct Y {
   int c;
   struct X *x;
};


しかし、このような構造体だと、32bit環境ではstruct Xと同じく8バイトのデータとなりますが、ポインタ値をファイルに書き出しても無意味です。


そのため、Cの構造体をファイルに保存するときは、自分で好きなようにエンコードしてください。

特別な方法は用意されていません。

それは、Document-Based Applicationであっても同じです。


Objective-Cのオブジェクトであれば、Cocoaフレームワークである程度のサポートが受けられますが。

2012/09/18 03:49 キリー への返信

fwrite(&Ch, sizeof(Ch), 1, fp);

は、単に、&Ch のアドレスから Ch のサイズ( == sizeof( struct _CHARACTER ) ) [byte] の範囲にあるメモリの内容を書き込むだけです。

int, long, double や char name[32] のような固定長の配列であれば良いですが、(NSString *)name や (struct _CHARACTER *)next 等の実体は、そのメモリ範囲にはありません。


nextの値もひっくるめて、sizeofがChとなるのでしょうか?


このようなことは決してありません。sizeof( xxx ) はいつも定数です。

( もちろん、構造体の中に再帰的に struct _CHARACTER の(ポインタではなく)実体を含めることもできません。)

この辺りは、C も Objective-C も変わりません。C 言語も Objective-C もシンプルです。

確か NSArchiver など、Objective-C でオブジェクトをそれに関したプロトコルに適合させれば、そのような再帰的なオブジェクトの構造を保存/読み込みすることもできたと思いますが、それなりの手間がかかります。

また、CoreData を使うとかなり自動でやってくれるかもしれませんが、それについてはよく知りません。


気づきましたが、ファイルが生成されません。

objective C ではC言語のファイル生成ではいけないのでしょうか?

Command Line Tool の Foundation Tool ( または type:Foundation ) (Xcode のプロジェクトのテンプレート) など、Command Line Tool で、ターミナルで起動すれば良いと思いますが、

通常のアプリケーションをダブルクリックで起動したときは、カレントディレクトリが設定されていなかったと思います。

fp = fopen("sbdata.txt", "wb");

ではなく、絶対パスで指定すれば良いと思いますが。

ホームディレクトリからのパスを示す ( ~/sbdata.txt ) も使えません。( NSString にそれを絶対パスに変換するメソッドがあったと思いますが。)

2012/09/18 19:50 蝦夷_オカメの親 への返信

ファイルを保存するときにNSDataを使うやり方があるようです。

例えば、

BOOL ret;

NSString *path = @"~/Documents/Test.txt";

path = [path stringByExpandingTildeInPath];


ret = [[NSFileManagerdefaultManager] createFileAtPath:path contents:nilattributes:nil];

if(!ret){

NSLog(@"Failed to create a file");

}


NSFileHandle *fileHandle;

fileHandle = [NSFileHandle fileHandleForWritingAtPath:path];

if(!fileHandle){

NSLog(@"failed to create file-Handle");

}


NSData *data;


data = [NSDatadataWithBytes:"ABCDEFG"length:7];


[fileHandle writeData:data];


[fileHandle synchronizeFile];


[fileHandle closeFile];


で、マイドキュメントにTest.txtが生成できましたが、

このNSDataを使ってなんとか、構造体の情報をコピーする事は出来ないでしょうか?

とくに、構造体と言えど、Objective-cのNSImageなどを使っているので、

実際に文字にエンコードするのは想像がつきません。

また、リスト構造をファイルように出力し直す関数を作るなど途方に暮れてしまいます。

なんとかNSDataでいけないでしょうか?


Stripeさん

Document Based Applicationにすると、ファイル項目に保存と出てきて、

読み込むとそのままの状態でロードしてくれる仕様ではないのですか?

自分の好きなようにエンコードと言われても、NSImageを含んでいるし、

リスト構造なので膨大な手間がかかりそうで、ボーゼンとしています。

上記のようなNSDataの利用で何とかなりませんか?



yuiさん

char *cwd;

cwd = getcwd(NULL, 0);

printf("CWD:%s\n", cwd);

free(cwd);

で、カレントディレクトリを確認した所、不可視のライブラリーのフォルダーに

/Users/Killery/Library/Developer/Xcode/DerivedData/アプリ名-alaeedngdgfxhebjhvridhgcreku/Build/Products/Debug


という訳の分からない名前のフォルダーを経由していました。4.4.1から仕様が変わったのですか?

とても検索しにくく、ディラクトリも見つけるのが大変だったです。

パスも

NSString *path = @"test.txt"

ならいけるのに、

NSString *path = @"/test.txt"

とするとNSLogで(null)となりダメでした。全く持ってわけが分かりません。

アプリケーションの実用性を考えて、絶対パスではなく、相対パスにしたいのですが、

データフォルダーにデータファイルを入れて書き込むと言った感じにするにはパス指定はどうすれば良いでしょうか?

>蝦夷_オカメの親さん

>ファイル出力させる場合、クラスの変数やポインタ変数の定義は構造体に組み込むと正しくファイル入出力しないと思います。

そうなんですか?処置なしではないですか…。

文字列やイメージの扱いを配列にしても良いですが、今からは出来ません。

全く、Objective c には困ったものです、その風変わりな仕様のせいで、開発は中断させられてばかりです。

イメージの扱いについてですが、配列にしたとして、NSImageをそのままファイルに出力できるのですか?

変数や文字列と違って、NSImageはデータ型なので、自作のエンコードのしようがありません。

NSImageはどうやってファイルに保存したら良いのか今の所全く想像がつかずに困っています。

2012/09/19 03:40 キリー への返信


Stripeさん

Document Based Applicationにすると、ファイル項目に保存と出てきて、

読み込むとそのままの状態でロードしてくれる仕様ではないのですか?

自分の好きなようにエンコードと言われても、NSImageを含んでいるし、

リスト構造なので膨大な手間がかかりそうで、ボーゼンとしています。

上記のようなNSDataの利用で何とかなりませんか?




NSDataって、ただのバイト配列ですよ。

C言語でいうと

unsigned char data[1000];

これと同じようなものです。


だから、構造体をバイト配列に変換(エンコード)することができるなら、NSDataを利用できるでしょう。

2012/09/19 05:27 キリー への返信

全く、Objective c には困ったものです、その風変わりな仕様のせいで、開発は中断させられてばかりです。


昔から ( https://discussionsjapan.apple.com/message/100690950#100690950 、他いろいろ ) よく Objective-C や Mac OS の API の批判をされてますが、指摘した retainCount や Objective-C の基本の件 ( https://discussionsjapan.apple.com/message/100696751#100696751 ) についても、その後も特にしっかり理解しないまま進めているようですので、キリーさんにそれらの件についての回答などはしないようにしています。意味がないと思いますので。

今回はカレントディレクトリの件など少し別の話でしたので、一部回答しましたが。

他の OS ( Windows や Linux 等 ) のプログラミングもできるようには見えませんし、よく「C言語なら・・・」と書いてますが、今回の sizeof( xxx ) の件などを見ても C言語についてさえ十分理解していないように見えます。

Objective-C は C言語にオブジェクト指向を追加しただけの言語で C 言語の理解は必須です。

GUI アプリケーションの開発の前に、C言語や Objective-C の基本的な部分から勉強をした方が良いと思います。


Document Based Applicationにすると、ファイル項目に保存と出てきて、

読み込むとそのままの状態でロードしてくれる仕様ではないのですか?


Document Based Application では、そういう形式のアプリケーションの開発が簡単になるような仕組みが多くあり、私は非常に良いフレームワークだと思っています。

ただ、だからといって何でもかんでも自動でやってくれるわけではありません。自分で定義したドキュメントのデータの保存や読み込みは自分で行う必要があります。(NSArchiverなど場合によっては役に立つ方法などもありますが。)

基本的には Document Based Application 等の Mac OS アプリケーションのフレームワークは、そのフレームワークが保存/読み込み/Undoなどの処理の枠組みを提供し、各アプリケーションがその枠組みに適合するように必要なメソッドなどを適切に実装する必要があります。キリーさんはかなり自分勝手にメソッド名などを付けているようですが、Mac OS のフレームワークの助けを借りたいと思うなら、Objective-C (on Mac OS)のマナーのようなものを理解し、それに適合するように実装していくことです。特に Automatic Reference Counting など新しい技術では、メソッド名などの制限も出てきます。

もちろん、そういったことを理解して行うとしても、使いやすいアプリケーションの作成にはかなりの手間がかかりますが。

2012/09/20 03:33 yui への返信

>Stripeさん

確か、plistの設定で、画像データはNSDataで扱っていたのを覚えています。

初期化は出来ませんが、指定のときにはNSData型にして画像を扱いました。

画像形式をNSDataに指定する事は出来ませんか?

何せ、自分が作っているリストのデータは文字や変数以外にNSImageが入っているもので、

今の所、バイト配列にエンコードするのは想像がつきません。

NSImageをプログラム上でNSDataに変換する事は出来ないでしょうか?


>yuiさん

自分が今作っているゲームにはちょっとしたエディタをつけていたのですが、

ファイル操作がまだよく分からない状態なので、内部データでやって行くしかありません。

結構作法とかも指摘されていますが、自分のモットーは動くゲームを作るのが第一なのです。

作法を延々と勉強していても同じような事の繰り返しばかりで開発にさける時間がなくなっていったのは、

C言語の時からです。質問しに回って、yuiさんのように作法をよく指摘される事が多いですが、

入門書や、アルゴリズムのノウハウ本は必ずと言っていいほどゲームを作る部分には触れてくれていないので、

モチベーションが上がらず、買っても読破することはほとんどありません。

ですから、ゲームを作るに特化した、実践的なテクニックや質問を重視して開発をとにかく進めているのが今のスタイルです。

sizeof に関しては、fileの仕様とセットだったのでちょっと混乱しただけです。

sizeofはそんなに難しい関数ではないので、単に明示した変数のサイズを転送するくらいにしか思ってませんでした。

よく、mallocとセットで使うものくらいの理解でゲームは動きましたし。


とにもかくにも自分は「動くゲーム」を作りたいのです。

下積みのころにあった、仕様や特に面白くもないサンプルをうつしながら学んでいく段階は好きではありませんでした。

objective c だって、最初は画像の表示も満足に出来ませんでした。

何故、macにはゲームを作る丁寧で親切な参考書がないのかいまだに不満です。

詳解objective c 2.0第3版もレベルが高いのか、学んだ事が実際に何の役に立つか、

または、簡単なゲームのサンプルのようなものが載ってなくて、個人的に分かりにくい本です。

自分が今まで一番参考になったのが、進めコードウォリアーともっと進めコードウォリアーです。

ああいう感じで、十分なのに何故か最近の本はバラけたサンプルや使いどころが分からないサンプルばかりで困っています。

かの有名なアーロンヒレガスの本だって、応用性がないサンプルで広がりを持てない、簡単な事が載っていなく、回りくどく説明するものでした。

ですから、今はオンラインで調べるばかりです。といっても、ググっても意外と日本語で回答がヒットしないので、苦労してますが。何かMac日本勢ももっとメジャーで分かりやすく目立つフォーラムをもうけてほしいものです。最近はみなさんと、stackoverflowに助けてもらってなんとか開発が進んでいる状態です。

何度も繰り返しますが、本当にいろいろと分かりにくい。

2012/09/20 04:03 キリー への返信

NSImageをプログラム上でNSDataに変換する事は出来ないでしょうか?


簡単にできますけど、、、

NSImageをNSDataにするだけでいいんですか?

構造体の話はどこへ行ったんですか?



とにもかくにも自分は「動くゲーム」を作りたいのです。


結論から言って、キリーさんには無理でしょう。


足し算すら出来ない人に、方程式は解けません。

犬小屋すら建てられない人に、住宅は建てられません。



入門書や、アルゴリズムのノウハウ本は必ずと言っていいほどゲームを作る部分には触れてくれていないので、モチベーションが上がらず、買っても読破することはほとんどありません。


ゲームを作る部分に触れているけど、キリーさんがそれを無視しているだけでしょう。

このスレッドはシステム、またはAppleコミュニティチームによってロックされました。 問題解決の参考になる情報であれば、どの投稿にでも投票いただけます。またコミュニティで他の回答を検索することもできます。

objective c 構造体をファイルに保存したい

Apple サポートコミュニティへようこそ
Apple ユーザ同士でお使いの製品について助け合うフォーラムです。Apple Account を使ってご参加ください。