ホーム   »  スポンサー広告  »  スポンサーサイト   »  PSPプログラミング  »  第7弾 : ファイル入出力 詳細説明

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

第7弾 : ファイル入出力 詳細説明


大分間隔が開いてしまいすいません(汗

はい。じゃあ前回の 第6弾 : ファイル入出力 のソースコード解説します。(棒

石持たないで、投げないで、痛いよ(泣


それでは、どっかに保存してあるはずの前回のソースコード開いてくださーい。
開きました?

では、まずはグローバル変数から

char FILE_PATH[256] = "ms0:/test.txt";

これが、今回のアプリで作成・書き込み・読み込みされるファイルのパスです。
ファイルパスの形式は前回説明済みですね。



毎度のコールバックをバーッと飛ばして、自作関数の init_screen 関数ですね。
画面クリアと印字位置初期化を兼ねています。



次は write_file 関数ですね。
これが要のファイル書き込み関数です。

char data[] = "Hello,World!";
変数 data が書き込まれるデータです。

SceUID fd = sceIoOpen( FILE_PATH, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777 );
ファイルを開きます。同時にファイル内容を消去しています。

sceIoOpen APIについて。
SceUID sceIoOpen(const char *file, int flags, SceMode mode);
 第1引数 const char *file : 作成または開きたいファイルへのパスを指定。
 第2引数 int flags : ファイルの作成または開く際の動作を指定します。
PSP_O_RDONLY : 読み込みのみ
PSP_O_WRONLY : 書き込みのみ
PSP_O_RDWR : 読み書きのみ(実体はPSP_O_RDONLY | PSP_O_WRONLYです)
PSP_O_APPEND : 追記で開く(ファイル末尾へシークする)
PSP_O_CREAT : 新規作成
PSP_O_TRUNC : ファイルを空にする(サイズ0)
PSP_O_EXCL : ファイルがあるのならば、作成しない
PSP_O_DIROPEN : ディレクトリを開く(作成は出来ない)

 第3引数 SceMode mode : ファイルパーミッションの指定です。通常は 0777 を指定します(注:8進数)。
 戻り値 : ファイル・ディスクリプタです。システムが割り振る識別番号だと考えて下さい。正常ならば0以上、異常ならば0より小さいです。
 補足 : SceUID型とSceMode型は int型のtypedefです。ディレクトリ作成はsceIoMkdir APIです。

int nWrite = sceIoWrite( fd, data, sizeof(data) );
ファイルに変数 data の内容を書き込みます。

sceIoWrite APIについて
int sceIoWrite(SceUID fd, const void *data, SceSize size);
 第1引数 SceUID fd : sceIoOpen APIの戻り値、ファイル・ディスクリプタを指定します。
 第2引数 const void *data : 書き込むデータのポインタを指定。
 第3引数 SceSize size : 書き込むデータのバイトサイズ。
 戻り値 : 書き込みに成功したバイトサイズ。正常0以上、異常0より小さい。
 補足 : SceSize型は unsigned int 型のtypedefです。

sceIoClose( fd );
開いたファイルを閉じます。 引数にはファイル・ディスクリプタ。戻り値が0よりも小さいならばエラーです。

これで write_file 関数の説明終了です。



次に、read_file 関数です。

char buffer[32] = "";
ファイル内容を読み込むバッファです。今回はNULL文字を含めて32バイトまで読み込みます。

int nRead = sceIoRead( fd, buffer, 31 );
ファイルから変数 bufferにデータを読み込みます。NULL文字を顧慮して、最大31バイトまで読み込みます。

int sceIoRead(SceUID fd, void *data, SceSize size);
 第1引数 SceUID fd : ファイル・ディスクリプタ
 第2引数 void *data : ファイルデータを読み込むバッファーへのポインタを指定
 第3引数 SceSize size : 最大で読み込むバイトサイズを指定
 戻り値 : バッファーに読み込んだバイトサイズ。正常0以上、異常0より小さい。

buffer[nRead] = '\0';
今回読み込むデータは文字列なので、NULL文字を確実に追加して置く。忘れがちなので注意。

あとは、読み込んだ結果を表示しています。
これで read_file 関数終了です。



次は、GetDate 関数ですね。関数内で静的変数を使用しているので注意して下さい。
ScePspDateTime 構造体の値を yyyy/mm/dd hh:mm:ss という書式に整形出力します。
typedef struct ScePspDateTime {
unsigned short year;
unsigned short month;
unsigned short day;
unsigned short hour;
unsigned short minute;
unsigned short second;
unsigned int microsecond;
} ScePspDateTime;

第1引数 ScePspDateTime *time : ScePspDateTime構造体へのポインタ。
戻り値 : 整形された文字列が格納される静的変数 str へのポインタ。



print_file_info 関数です。
ファイル情報を取得して、表示する関数です。

SceIoStat stat;
SceIoStat 構造体の宣言。
typedef struct SceIoStat {
SceMode st_mode;
unsigned int st_attr;
SceOff st_size; /** Size of the file in bytes. */
ScePspDateTime st_ctime; /** Creation time. */
ScePspDateTime st_atime; /** Access time. */
ScePspDateTime st_mtime; /** Modification time. */
unsigned int st_private[6]; /** Device-specific data. */
} SceIoStat;


sceIoGetstat( FILE_PATH, &stat ) (一部省略)
ファイル情報を SceIoStat 構造体へ格納します。

int sceIoGetstat(const char *file, SceIoStat *stat);
 第1引数 const char *file : 情報を取得したいファイルへのパスを指定
 第2引数 SceIoStat *stat : SceIoStat 構造体へのポインタ
 戻り値 : 正常0以上 異常0よりも小さい。

printf( "Attribute : %s\n", (stat.st_attr & FIO_SO_IFREG)? "Regular" : "Unknown" );
ファイルの属性(アトリビュート)を表示する処理です。
SceIoStat.st_attr に FIO_SO_IFREGOR が含まれる場合、そのファイルは通常ファイルです。

それ以下の処理は、ファイルサイズの表示。先程解説したGetDate関数を使用した、各日時の表示です。




次は wait_anykey 関数です。
いづれかのボタンが押されるまで待ち続けます。
お世辞にも、あまり出来のいい実装ではないので、オープンソースで探してみて下さい。




get_root_path 関数です。
これはmain関数のargv[0]にEBOOT.PBPのパスへのポインタが格納されることを利用した関数で。
デバイス名を自動で書き換えます。



よし、main関数だ。終わりが見えた!
今回は関数ポインタを使用したmain関数と使用しないmain関数を用意しました。

関数ポインタ使用バージョンmain関数解説

int keys[4] = { PSP_CTRL_CIRCLE, PSP_CTRL_TRIANGLE, PSP_CTRL_SQUARE, PSP_CTRL_CROSS };
int (*func[4])(void);
func[0] = write_file;
func[1] = read_file;
func[2] = print_file_info;
func[3] = exit_app;

以上が下準備です。
int型の keys 配列と 関数ポインタ func 配列の組み合わせが重要です。気が付きましたか?

for( n = 0; n < 4; n++ ) {
if( pad.Buttons & keys[n] ) {
func[n]();
wait_anykey();
init_screen();
break;
}
}


そして、for文で 取得したpad.Buttons と配列の数だけAND演算で一致するか確認し。
一致した場合、対応する func[n] 関数が呼ばれます。
理解出来ましたか?
滅多に、というかこんなことは、やらない筈なので、解らずともいいです。



関数ポインタを使用しないバージョンのmain関数解説

こっちの方はシンプルに作りました。
ベターな方法です、が量が増えると管理が大変なんですよね。
それで関数ポインタバージョンも紹介した訳です。

if( pad.Buttons & (PSP_CTRL_CIRCLE | PSP_CTRL_TRIANGLE | PSP_CTRL_SQUARE | PSP_CTRL_CROSS) )
ループ毎に取得したボタンがあるかどうか確認。

あったのならさらにIF文で分岐し、指定ボタンで対応する関数を呼び出します。
処理結果が消えないように wait_anykey 関数でボタン入力を待ちます。
ボタンが押されると、 init_screen 関数で画面が初期化されます。

main関数の説明終了。


はい。これでファイルI/Oはシーク以外おkなはずです(ぉぃ
シークは、標準Cとなにも変わりないのですが‥‥説明する必要あるんですか。

SceOff sceIoLseek(SceUID fd, SceOff offset, int whence);
 第1引数 SceUID fd : ファイル・ディスクリプタ
 第2引数 SceOff offset : シークするサイズをバイトサイズで指定
 第3引数 int whence : 何処を基準に移動するか。
  SEKK_SET : ファイル先頭から
  SEKK_CUR : 現在位置から
  SEEK_END : ファイル末尾から
 戻り値 : シークした後の、ファイルの位置を返す。
 補足 : SceOff 型は SceInt64 型のtypedef (符号付き64bit整数)。
 SceOff fsize = sceIoLseek( fd, 0, SEEK_END ); // これでファイルサイズ取得可能

ファイルI/O系で残るはディレクトリ操作と非同期バージョンですかね。
ディレクトリ操作は後々。
それでは、また次回。バーイ ノシ
スポンサーサイト
Comment
Trackback
Trackback URL
Comment Form
管理者にだけ表示を許可する
Twitter...A

estuibal=Y.K < > Reload

検索フォーム
RSSリンクの表示
リンク
QRコード
QR
ブロとも申請フォーム
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。