PSP xvi

PSPプログラミングを教えるブログ(本気で頑張る人アクセス大歓迎サイト)

PSP-X.gif

記事の間違いを報告  新アップローダー
記事修正情報 PSPプログラミング資料 自作ゲーム PSP用エミュレータ リンク

公認リンク
公式PSP専科 公式PSVita専科 はじめるPSPSDK PSP EXEC GAME M@STER PSP 猫山のYouTubeチャンネル

TAG
全記事にタグをつけています  http://nekoyama2gillien.blog36.fc2.com/?tag=タグ
PSP PSPプログラミング DXライブラリPortable OSLib ショートプログラム ハローワールド
PSP自作ゲーム PSP自作ソフト エミュレータ ゲームアーカイブス PSP動画
動画 初音ミク ミクミクダンス MMDドラマ ゲーム 魔法少女まどか☆マギカ 侵略!イカ娘
アイドルマスター

このブログについて

このブログでは、非公式のPSPソフト、いわゆる自作ソフト( PSP Homebrew )を作る事を目的とします。

著作権などの こまかい利用規約については、こちらを開いてお読み下さい

このブログについて知りたい方、初めて来訪された方はこちらを開いてお読みください
お問い合わせは 猫山猫宗(nekomune@gmail.com)までどうぞ


当ブログはリンクフリーです。ブログ名は、アルファベットで「PSP xvi」と書いて『ピーエスピー・エクシビ』とお読みください。
相互リンクを希望されるブログ運営者様は、ココで申請して下さい。


このブログで全記事から探し物の方は、ここをクリックして下さい。
http://nekoyama2gillien.blog36.fc2.com/?all

スポンサーサイト 

--/--/--
--. --:--

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

[edit]

CM: --
TB: --

page top

質問に答えるシリーズ
- メモリ書き込み編 -

書き換え方法についての質問でしたが、まず、書き込みから解説します(知ってたらスルーで)。


メモリへの書き込みは、メインメモリやグラフィックメモリ(V-RAM)に対して行なうのが一般的です。

基本は、アドレス(=メモリの番地)を指定して、値を代入する事で、実現。

例1
0x90000000 番地 に、0x31 を入れる

char *add; // 1バイト中身のアドレスポインタ
add = 0x90000000; // 0x90000000 番地
*add = 0x31; // 代入

例2
グラフィック画面(32ビットカラーモード & フレーム0 & 座標 [0,0] )に、青色の点(=0x00FF0000)を打つ

long *v-add; // 4バイト中身のアドレスポインタ
v-add = 0x44000000; // フレーム0 & 座標 [0,0] のアドレス(V-RAM)
*v-add = 0x00FF0000; // 青色(=0xFF0000)の点を打つ


PSP Filer 6.0 に、メモリビュワー機能があるので、簡単に ご紹介

PSP Filer を起動後、△ボタン、□ボタン、の順に押すと、メモリビューワになります。
これによると、アドレスは 下記の様になっています。

●メインメモリは、0x80000000 ~ 0x9FFFFFFF
●拡張メモリは、0xA0000000 ~ 0xBFFFFFFF (PSP-2000 or PSP-3000 のみ)
●グラフィックメモリは、0x04000000 ~ 0x041FFFFF (V-RAMでっす)
●スクラッチパッドは、0x00010000 ~ 0x00013FFF (I/Oポートなのか?)

【ヒント】 ビュワーなので、メモリの書き換えは出来ませんよ


むぅ、グラフィックメモリのアドレスが、微妙に違うのかな?(なぞ)
正しいアドレスマップとかは、後日調べます。


SDKに、メモリ操作を行なう関数が用意されているので、ご紹介。
ヘッダの場所
 C:\pspsdk\psp\sdk\include\libc\string.h

この string.h をテキストエディタ等で開いて下さい。
mem~~関数 と、str~~関数 がありますね。

mem~~関数 は、バイナリ操作で、str~~関数 は、文字列型操作です。


配列型変数の初期化をする場合、memset( ); という関数を使うと便利です。

int  hairetu[5963]; // 一次元 配列型変数の宣言
memset( hairetu , 0 , sizeof(hairetu) ); // hairetu の中身全部を 0 で埋める
              // 文字列型変数の初期化(0x00 で 埋める)を行なうときにも対応

sizeof(○○) というのは、○○のサイズ(使用量)を求める計算式です。コンパイル時に計算されます。
sizeof( ) は、関数ではありません。sizeof( ) で無いことに注目!


メモリの書き換えの際、注意する点は、データ格納順番とキャストとアドレッシングです。

long  *pointer;
pointer = 0x88000000;
*pointer = 0x123456;

を実行すると、メモリに書き込まれる内容は、下記のようになります。

アドレス  内容
88000000  56
88000001  34
88000002  12
88000003  00

注目
 ・ "0x123456”は、3桁の16進数ですが、pointer が (long *) なので、4バイト単位でのやりとりになります。
 ・ バイナリ単位で見ると、0x00, 0x12, 0x34, 0x56 の順番ではなくて、0x56, 0x34, 0x12, 0x00 という風に 書き込まれている事実!


いっぽう、
long  *pointer;
pointer = 0x9A000001
*pointer = 0xABCDEF88;

を実行すると、バスエラーが発生します。

注目
 ・ (long *) や (short *) などのポインタ変数の場合、ポインタのアドレスに奇数を代入してはいけません。
 ・ もし偶数アドレスであっても4で割ると余り2になるアドレスへのlong値の転送(代入)の場合もバスエラーが発生します。




次は、メモリの書き換え編ですよー。


スポンサーサイト

[edit]

CM: 0
TB: 0

page top

質問に答えるシリーズ
- メモリ内容の書き換え編 -

さて メモリ書き換えですが、方法は、メモリの値を読み込み、内容に変更を加えてから メモリの同じ場所へ書き込むことが基本です。

では早速

例1
8D120000番地(16進数) からの連続9バイトに、各 25(10進数)ずつ足す

char data; // 足し算用
long i; // アドレス 兼、ループ用
for( i = 0x8D12000; i < 0x8D120000+9; i++)
{
data = (char *)i; // メモリ内容の読み込み
data += 25; // 足し算
(char *)i = data; // メモリへ書き出し
}


例2
グラフィック画面(32ビットカラーモード & フレーム0)全体に、青みをかける

#define VRAM_ADDRESS 0x44000000 // グラフィック画面の開始アドレス
#define FRAMESIZE 0x88000 // 1フレーム辺りのサイズ(横512pixel×縦272pixel
// ×色深度4bytes)
long rgb; // データ用
long i; // アドレス 兼、ループ用
for( i = VRAM_ADDRESS; i < VRAM_ADDRESS + FRAMESIZE; i+=4 )
{
rgb = (long *) i ; // 読み出し1回目
rgb = (long *) i ; // 読み出し2回目注 1
rgb |= 0x008F0000; // 青っぽい色(=0x8F0000) を OR でくっつける
(long *) i = rgb; // 書き出し
}
注 1
PSPのグラフィックメモリは、二度読みしないと正しい値が求められない様です。

例3
グラフィック画面(32ビットカラーモード & フレーム0)全体を、少し暗くする

#define VRAM_ADDRESS 0x44000000 // グラフィック画面の開始アドレス
#define FRAMESIZE 0x88000 // 1フレーム辺りのサイズ(横512pixel×縦272pixel
// ×色深度4bytes)
long rgb; // データ用
unsigned char rgbA, rgbR, rgbG, rgbB; // 色成分用
long i; // アドレス 兼、ループ用
for( i = VRAM_ADDRESS; i < VRAM_ADDRESS + FRAMESIZE; i+=4 )
{
rgb = (long *) i ; // 読み出し1回目
rgb = (long *) i ; // 読み出し2回目
rgbA = ((rgb & 0xFF000000) >> 3) & 0xFF000000; // α成分(念のため)
rgbR = ((rgb & 0x000000FF) >> 3) & 0x000000FF; // 赤成分
rgbG = ((rgb & 0x0000FF00) >> 3) & 0x0000FF00; // 緑成分
rgbB = ((rgb & 0x00FF0000) >> 3) & 0x00FF0000; // 青成分
(long *) i = rgbA | rgbR | rgbG | rgbB; // 書き出し
}
RGB各色の情報を、3ビット右にずらして削って、輝度を下げています。


ビット操作も出来ます。


9152FF01番地(16進数)の、1ビット目をOFF にして2ビット目をON にして 6~8ビット目を反転したい

char *pointer; // ポインター変数
char data; // ビット操作用

pointer = 0x9152FF01; // ポインタ変数にアドレス設定
data = *pointer; // 読み出し
data &= 0xFE; // 1ビット目をOFF(アンド記号) 0xFE = 11111110b(2進数)
data |= 0x02; // 2ビット目をON(縦線記号) 0x02 = 00000010b(2進数)
data ^= 0x70; // 6~8ビット目を反転(べき記号)0x70 = 11100000b(2進数)
*pointer = data; // 書き込み

最下位ビット(右側)が 1ビット目で、最上位ビット(左側)が8ビット目です。




さて、お次は本命のファイル操作ですが、その前にビット操作についての講釈をします。

[edit]

CM: 9
TB: 0

page top

ファイル操作編 - ファイルを開く
まずは、ファイルを開く方法から、みっちりと お勉強します。


PSPで、ファイルとして扱えるのは、以下のデバイスです。

デバイス名 ドライブ名
・メモリースティック   "ms0:"
・フラッシュメモリ "flash0:" "flash1:" "flash2:" "flash3:"
・UMDディスク "disc0:"
・赤外線ポート "irda0:"

赤外線ポートがあるのは、PSP-1000のみ

ファイルを扱うには、ファイルハンドルを取得して、そのファイルハンドルで行ないます。
ファイルハンドルは、ファイル構造体へのポインタ (FILE *)、もしくは int で定義します。


● ファイルを読み込みモードで開く関数を ご紹介
・FILE *fp; の場合
  fopen( "ファイル名", "r");
    FILE *fp 用のファイルを開く関数です。
    "ファイル名"には、絶対PATH注1、もしくは相対PATH注2 でファイル名を 書きます
    返り値は、ファイル・オープンエラーなら NULL (== 0x00 )
          正常に ファイル・オープン出来たなら ファイルハンドル
    注1
    絶対PATH とは、ファイル名をデバイス名から 全部表記したもの。フルPATH
    注2
    相対PATH とは、ファイル名をカレントディレクトリを基準として相対的な差分で表記したもの。

・int fp; の場合
  sceIoOpen( "ファイル名", PSP_O_RDONLY, 0777);
    int fp 用のファイルを開く関数です。
    "ファイル名"には、メモリースティック上の PATH を書きます
    返り値は、ファイル・オープンエラーなら NULL (== 0x00 )
          正常に ファイル・オープン出来たなら ファイルハンドル


『ファイル構造体』 を 定義しているヘッダーファイル
C:\pspsdk\psp\sdk\include\libc\stdio.h
typedef struct {
int type;
int fd;
int cnt;
int flag;
int has_putback;
u8 putback;
} FILE;

ファイルを開く例 その1 FILE *fp; 編
FILE  *fd;
fd = fopen("ms0:/seplugins/GAME.txt","r");

解説
"r" は、"read""r"。読み込みモードで開く。

"ms0:/seplugins/GAME.txt" というファイルが無かったら、fd には、 NULL( == 0 ) が入る。
"ms0:/seplugins/GAME.txt" というファイルが存在したら、fd には、ファイルハンドルが入る。


FILE 構造体へのポインタ fd を使用している関数は、下記のヘッダーファイルに書いてあるので
各自、探して読んでみて下さい。

C:\pspsdk\psp\sdk\include\libc\stdio.h



ファイルを開く例 その2 int fp; 編
SceUID  fd;
fd = sceIoOpen("ms0:/MUSIC/Mario OP.mp3", PSP_O_RDONLY, 0777 );

SceUID は、int型です。
C:\pspsdk\psp\sdk\include\kerneltypes.h 内で、定義されています。
/** UIDs are used to describe many different kernel objects. */
typedef int SceUID;

解説
PSP_O_RDONLY は、『読み込みモードで開く』というパラメータ値。

"ms0:/MUSIC/Mario OP.mp3" というファイルが無かったら、fd には、 負の値 が入る。
"ms0:/MUSIC/Mario OP.mp3" というファイルが存在したら、fd には、ファイルハンドルが入る。

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 18
TB: 0

page top

ファイルを開いたら、何をするのか。

・必要なら、ファイルサイズを求めてみる
・そのファイルを全部読み込むなら、必要分のメモリを確保すべしッッ!
・ファイルの読み込み
・ファイルを閉じる(特に書き込みの後は、ファイルを閉じないと内容は保障されません)
・プログラム終了前に、確保したメモリを解放する事!


ファイルサイズを求めてみよう


ファイルサイズの取得 その1
long GetFileSize( FILE *fd )
// ファイルサイズを求める関数 ( FILE * で宣言したファイルハンドル用 )
// この関数を呼び出す前に、ファイルハンドルを取得しておいて下さい

{
long length; // ファイルサイズ用の変数(ココに入る)

fseek( fd, 0, SEEK_SET ); // 読み出し位置を先頭へ
fseek( fd, 0, SEEK_END ); // 読み出し位置を末尾へ
length = ftell( fd ); // 計ります
fseek( fd, 0, SEEK_SET ); // 読み出し位置を先頭へ

if (length <= 0)
return 0; // エラーや、ファイルサイズが 0 なら 0 を 返します
else
return length; // 数えるのに成功したら、そのファイルサイズ を 返します
}



ファイルサイズの取得 その2
long pgGetFileSize( int fd )
// ファイルサイズを求める関数 ( int で宣言したファイルハンドル用 )
// SceUID キャストが正しく認識しないようなので、int で書いておく
// この関数を呼び出す前に、ファイルハンドルを取得しておいて下さい

{
long length; // ファイルサイズ用の変数(ココに入る)

sceIoLseek(fd, (long long int)0, SCE_SEEK_SET); // 読み出し位置を先頭へ
length = sceIoLseek(fd, (long long int)0, SCE_SEEK_END); // 読み出し位置を末尾へ
sceIoLseek(fd, (long long int)0, SCE_SEEK_SET); // 読み出し位置を先頭へ

return length; // ファイルサイズ を 返します
}



解説

・ファイルシーク関数を使って、ファイルサイズを計ります
・ファイルを開いてから、どちらかの関数を呼び出すと、ファイルサイズが得られます
・ファイル読み込み位置を先頭に戻さないと、[EOF] にナリマスヨー!!


[EOF] は、End Of File の略で、ファイルの終わりを指します。

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 0
TB: 0

page top

ファイル操作編 - ファイルサイズ分のメモリを確保する

ファイルからデータを読み込む際、メモリを必要分 確保しておかないと、メモリの内容は保障されません。
メモリを確保しておかないと、データを上書きされたり、消されたりされる可能性があります。


メモリの確保(割り当て)
アロケーション(allocation)は、『割り当てる』という意味ですが、メモリの確保ですよ?

ちゅうい  以下のプログラムは、試作段階なので、実用には向いていません


char *ptr; // メモリ確保用のポインター変数 兼、メモリハンドル用
// ↑↑ グローバル変数にしておくといいかも。
char *malloc( int ); // メモリ確保関数の宣言(通常は、ヘッダーファイルを include すれば宜しいかと )
long GetFileSize( FILE * ); // 前回、製作した関数の宣言。ファイルサイズを求めます


FILE *fd; // ファイルハンドル用
long fsize; // ファイルサイズ

fd = fopen( "ms0:/MUSIC/TETRIS.mp3", "r" );
if(fd == NULL)
return ERROR__FILE_NOT_FOUND; // ファイルが無かったらエラーで返ります.

fsize = GetFileSize( fd );
if(fsize == 0) // ファイルサイズが 0バイトならエラーで返ります.
return ERROR__FILE_SIZE_ZERO;
else
{ // ファイルサイズが 1バイト以上ならメモリ確保処理を行ないます.
// メモリの確保は、ここからがメインです
ptr = malloc( fsize ); // メモリの確保をやってみる.
if(ptr == NULL) // メモリの確保が出来なかったら、以下
{
free(ptr); // メモリの解放.
fclose(fd); // ファイルを開いていたら、リターンの前に閉じておきましょう!
return ERROR__MEMORY_IS_NOT_ALLOC; // エラーで返ります.
}
}
// ← ここまで来れたら、ptr には、指定ファイルのサイズ分のメモリへのハンドルが得られています.

// ← この辺りには、ファイル読み込み処理とかを記述して行きます

free(ptr); // メモリの解放.
// ↑↑ コトが終わったら、メモリを解放します(重要)



解説

・malloc関数 で、必要なバイト数のメモリを確保(割り当て)します。
・この場合では、ファイルサイズ分のバイト数をメモリ確保しています。
・メモリが確保できない場合があります。
・メモリハンドルは、ちゃんと管理しておいて下さい(メモリの解放の時にも必要)。

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 0
TB: 0

page top

ファイル操作編 - ファイルの読み込み処理

ファイルを、読み込みモードで 開きます。
必要なら、そのファイルのファイルサイズを計ります。
その後は、ファイルを丸ごと読み込みしたり、必要箇所だけ読み込みしたりなど、何をするかは自由です。

なお、ファイルの読み込みを終えて、もう、そのファイルにアクセスしないという場合は、その開いたファイルを閉じましょう。


では、読み込みに必要な関数を ご紹介

● 1バイト読み込み
int getc( FILE *fd );
  解説:ファイルハンドル fd から、1バイト読み込む。
      ファイルの終わりなら、-1(4バイト値0xFFFFFFFF)が得られます.

● 複数バイト読み込み(チョイ読み型)
char *fgets( char *buff, int size, FILE *fd );
  解説:ファイルハンドル fd から、(size-1) バイト読み込み、buff の指すアドレス以降へ
    読み込みした内容を格納する.
     文字列を読み出す作業に適しています.
     返り値は、ポインタ *buff のアドレス (正常時)
           0 (ファイルの終わり時)
          -1 (エラー時)
    更に、読み込みした内容が、テキストの文字列だった場合、
    文字列の終わりに、[CR][LF][0x00]という3バイトコードが付加されます。
    情報提供 = 憂煉さん 詳細は、この記事のコメントを読んで下さい。


● 複数バイト読み込み( 一気読み型 / FILE *fd 版 )
int read( FILE *fd, char *buff, int size );
  解説:ファイルハンドル fd から、size バイト読み込み、buff の指すアドレス以降へ
    読み込みした内容を格納する.
     バイナリデータを一気に読み込む作業に適しています.
     返り値は、実際に読み込まれたバイト数(正常時)
           0 (ファイルの終わり時)
          -1 (エラー時)

● 複数バイト読み込み( 一気読み型 / read( ); の int fd 版 )
int sceIoRead( int fd, char *buff, int size );
  解説:ファイルハンドル fd から、size バイト読み込み、buff の指すアドレス以降へ
    読み込みした内容を格納する.
     バイナリデータを一気に読み込む作業に適しています.
     返り値は、実際に読み込まれたバイト数(正常時)
           0 (ファイルの終わり時)
          -1 (エラー時)


いっぽう、読み込み中に、データの読み飛ばし(スキップ)をしたい場合もあるかと存じます。
そんな時は、シーク関数を使うと便利です。


● 指定バイト数の読み飛ばし( FILE *fd版 )
fseek( FILE *fd, long, SEEK_CUR );

例:15バイト分、読み飛ばす。
fseek( fd,15, SEEK_CUR );

例:38バイト分、読み飛ばす。
fseek( fd, 38, SEEK_CUR );

解説
使用例を見てもらえば、良く解かるかと。
第2パラメータで、読み飛ばすバイト数を指定。


● 指定バイト数の読み飛ばし( int fd版 )
sceIoLseek( int fd, long, SEEK_CUR );

例:21バイト分、読み飛ばす。
sceIoLseek( fd, 21, SEEK_CUR );

解説
第2パラメータで、読み飛ばすバイト数を指定。


尚、ファイルの終わりの事を、専門用語で [EOF] (= いー・おー・えふ )と言います。
End Of File の略です。

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 8
TB: 0

page top

さて、一段落 着きたいので、ファイルを閉じるをお勉強でっす。

これはカンタン!


FILE *fp; なら fclose(fp);

int fp; なら sceIoClose(fp);


fp が指すファイルへのアクセスが出来なくなります。
ファイルを開くときは、また fp を取得してからですよっ!

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 0
TB: 0

page top

確保したメモリは、プログラムを終了してもメモリが確保されたままになるので、
プログラムを終了する前に、全てのメモリを解放しておかなくてはなりません(重要)

char *memptr = malloc( 確保サイズ );


メモリの解放 は簡単で、下記の関数で行ないます

free( 確保したメモリハンドル );


例を書くなら、

main()
{
#include <malloc.h>
char *memptr = malloc(1024); // メモリの確保、1024バイト

ナイスゲーム( );

free(memptr); // メモリの解放
}

のようになります。

【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放

[edit]

CM: 0
TB: 0

page top

メモリースティックへのファイル書き込みの方法(C++ プログラミング)をご紹介

● ファイルを書き込みモードで開く関数を ご紹介
・FILE *fp の場合
  fopen( "ファイル名", "w");
    FILE *fp 用のファイルを開く関数です。
    "ファイル名"には、メモリースティック上の PATH を書きます
    返り値は、ファイル・オープンエラーなら NULL (== 0x00 )
          正常に ファイル・オープン出来たなら ファイルハンドル

・int fp の場合
  sceIoOpen( "ファイル名", PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC, 0777);
    int fp 用のファイルを開く関数です。
    "ファイル名"には、メモリースティック上の PATH を書きます
    返り値は、ファイル・オープンエラーなら -1
          正常に ファイル・オープン出来たなら ファイルハンドル

  注 : ファイル名は、PATH (パス:道)で表記します。絶対PATHと相対PATHがあります。
  絶対PATH とは、ファイル名をデバイス名から 全部表記したもの。フルPATH
  相対PATH とは、ファイル名をカレントディレクトリを基準として相対的な差分で表記したもの。


● ファイルの書き込みに使える関数を ご紹介
・FILE *fp; の場合
  put( int data, FILE *fp );
    1バイト書き込み関数です
    data は、書き込む1バイトデータを int 型 整数値(もしくは文字1個など)で書きます
    fp は、ファイルオープン時のファイルハンドルを書きます
    返り値は、書き込みできたデータの値

  fputs( char *str, FILE *fp );
    文字列の書き込み関数です。
    文字列の終わりは、NULL文字( == 0x00 )になっていなければ なりません。
    書き込み時、文字列の末尾に、0x0d、0x0a、0x00 の3バイトが自動追加されます。
    fp は、ファイルオープン時のファイルハンドルを書きます
    返り値は、いちばん最後に書き込みした1文字

・int fp; の場合
  sceIoWrite(int fp, char *buff, int size);
    連続バイト書き込み関数です
    fp は、ファイルオープン時のファイルハンドルを書きます
    buff は、書き込む連続データの先頭アドレスを書きます
    size は、書き込みするデータのサイズ( 単位は バイト )を書きます
    返り値は、実際に書き込みできたデータのバイト数(負ならエラー発生)


では、まず、処理の手順を 日本語で 書いてみます。

【 手順 】
  1. 書き込みモードでファイルを開いて
  2. ファイル・オープンエラーが発生したら、ファイルを閉じてから エラーで終了する → 異常終了
  3. (ファイル・オープンエラーが発生しないなら、以下を実行)
  4. データを書き込みして
  5. ファイルを閉じて
  6. 終了 → 正常終了


上記手順を C++プログラミングしてみます。

【 プログラム・コード その1 FILE *fp; 編 】
    FILE *fp;
if( (fp = fopen("ms0:/ほえほえ.dat", "w")) == NULL)
{
fclose(fp); // ファイル・オープンでエラーなら、開いたファイルを閉じて…
return FILE_OPEN_ERROR; // エラー数値でリターン
}

int i;
for(i=0; i<1024; i++) // 1024回ループ
{
putc('a', fp); // 半角文字 a を一文字 書き込みする
} // つまり、1024個の a の書き込みになります
fclose(fp); // ファイルを閉じます
return NORMAL_FINISH; // 正常終了の数値でリターン


【 プログラム・コード その2 int fp; 編 】

int fp;
if( (fp = sceIoOpen("ms0:/ダヨーーン.dat", PSP_O_CREAT|PSP_O_WRONLY|PSP_O_TRUNC, 0777)) < NULL)
{
sceIoClose(fp); // ファイル・オープンでエラーなら、開いたファイルを閉じて…
return FILE_OPEN_ERROR; // エラー数値でリターン
}
ptr = GetDATA(); // 架空の、データ取得関数(仮)
sceIoWrite(fp, ptr, サイズ ); // ptrは、書き込むデータの先頭アドレス
// サイズはint型の整数数値です
sceIoClose(fp); // ファイルを閉じます
return NORMAL_FINISH; // 正常終了の数値でリターン


上記のプログラム・コードは、あくまで例です。採用する際は、各自、理想のプログラム・コードに書き換えて下さい。

ファイルを閉じる関数は、読み込み後も書き込み後も共に同じで、fclose( ); 、sceIoClose( ); のどちらかで可能です。使い分けて下さい。


次は、「ファイル入出力関数についての講釈」 です。


[edit]

CM: 6
TB: 0

page top

さて、ファイルを開く際に、fopen( ); 関数と sceIoOpen( );関数の2種類あるぞ、困った…。と思っておられる方がいるハズ。

そこで、今回は、ファイル入出力について書いてみようと思います。

ファイルポインタ構造体 (FILE *) を使うファイル操作を、バッファド・ファイル入出力と言い、バッファリングや、その他のサービスがされます。
いっぽう、ファイル・ディスクリプタ(ファイル記述子 / int)を使うのを 低水準ファイル入出力と言い、よりOSに近いレベルでのファイル操作となっています。

バッファリング
入力された内容がシステムバッファに溜められて、ある条件を満たした際に 一度にまとめてデータを渡す仕組み


【 バッファド・ファイル入出力の概念 】
文字単位・行単位での処理を行なえます。

【 低水準ファイル入出力の概念 】
ユーザが指定したバッファとの間で直接バイト単位の読み出し/書き込みを行なえます。

【 ファイル・オープンモードの解説 】
C:\pspsdk\psp\sdk\include\pspiofilemgr_fcntl.h ← このファイルに記述されている値について

モード 機 能
PSP_O_RDONLY 読み出し・オンリー・モード
PSP_O_WRONLY 書き込み・オンリー・モード
PSP_O_RDWR 読み出し・書き込み・モード
PSP_O_NBLOCK 不明(ひょっとして、ブロッキング転送に関係あり?)
PSP_O_DIROPEN ディレクトリ・オープン・モード(使用されない)
PSP_O_APPEND 追記モード
PSP_O_CREAT ファイルの新規作成モード
PSP_O_TRUNC 既存ファイルをオープンし、空ファイルにする
PSP_O_EXCL ファイルが存在すれば新規作成しない
PSP_O_NOWAIT 待ち時間無し転送モ-ド
↑↑ この値は、sceIoOpen( );関数などで使用されますね。


【 ファイルオープン関数の返り値 0 or 負 】
fopen( );関数の返り値は、エラーの時はNULLですが、sceIoOpen( );関数でのエラー返り値は、負の数(値は不定) です。うっかり間違えることが多いと思いますので気をつけて下さい。
正常な返り値は、共に正の値です。


PSPSDKでは、ファイルのテキスト形式やバイナリ形式という概念が無いのか、パラメータが省かれているのか、デフォルトでバイナリ形式となっているっぽいです。テキスト形式も扱えるバイナリ型ということでイイノカ?


次は、「メモリースティック内のファイルの書き換えの方法 その1」 の予定です。


【 関連記事 】
PSPプログラミング ファイル入出力関数についての講釈
PSPプログラミング fopen( ); のファイル・オープンモードのレポート
PSPプログラミング ファイル入出力関数まとめ
PSPプログラミング バッファド・ファイル入出力のまとめ(抜粋)
PSPプログラミング 低水準ファイル入出力のまとめ(抜粋)
PSPプログラミング メモリースティック内のファイル書き換え方法 その1
PSPプログラミング メモリースティック内のファイル書き換え方法 その2

[edit]

CM: 12
TB: 0

page top

下記の表は、PSPSDK での fopen( );関数のファイル・オープンモードを調べた結果です。
標準Cでのモノと同じであるようです。

fopen_hyou2.png


fopen( );のモードは、fopen(ファイル名, "モード"); の部分ですよ。

w+ と a+ は共に、ファイルからの読み出しが出来なかったようです。
興味がある方は調べて報告してください。

報告ありがとうございます。訂正しました。

r+ は、読み出し位置、書き込み位置をシークで移動できます。
読み出し後にシークしないで書き込みすると、ファイル末尾に追記書き込みになります
r+ は、ファイル書き換えに使えます(シーク使ってね)

w+ は、書き込み位置のシーク可能で、書き込み後ファイルを閉じると書き込みした部分までのファイルになります
w+ の場合、ホントはシークしちゃだめらしいですが…(ぉ

a+ の場合は書き込み位置をシークで移動できません。書き込み位置は常に末尾です。
a+ は、読み出し位置を いじれますが。

以上。


【 関連記事 】
PSPプログラミング ファイル入出力関数についての講釈
PSPプログラミング fopen( ); のファイル・オープンモードのレポート
PSPプログラミング ファイル入出力関数まとめ
PSPプログラミング バッファド・ファイル入出力のまとめ(抜粋)
PSPプログラミング 低水準ファイル入出力のまとめ(抜粋)

[edit]

CM: 2
TB: 0

page top

PSPプログラミング ファイル入出力関数まとめ 

2009/10/12
Mon. 23:02

ファイル入出力関数には、低水準ファイル入出力と、バッファド・ファイル(ストリーム)入出力とがあるのは、以前までに書いたのでご存知かと。

・バッファド・ファイル(ストリーム)入出力
  システムバッファを介して1文字単位あるいは1行単位のファイルアクセスを行ないます。
  テキストファイルの処理を行なうのに都合が良い。

・低水準ファイル入出力

  バイト単位のファイルアクセスを、ユーザバッファとの間で行ないます。

さて、次から、ファイル入出力関数を全部書いてみることにします。

ファイルの書き換え記事は出来ているのですが、順番に公開します(ファイル入出力関数記事が終わったら公開)。


【 関連記事 】
PSPプログラミング ファイル入出力関数についての講釈
PSPプログラミング fopen( ); のファイル・オープンモードのレポート
PSPプログラミング ファイル入出力関数まとめ
PSPプログラミング バッファド・ファイル入出力のまとめ(抜粋)
PSPプログラミング 低水準ファイル入出力のまとめ(抜粋)

[edit]

CM: 0
TB: 0

page top

この記事は、バッファド・ファイル入出力で主に使う関数のまとめです。
あまり使わないであろう関数については省いてあります。

全部の関数については、下記のヘッダーファイルを参照してください。
↓↓↓↓↓
C:\pspsdk\psp\sdk\include\libc\stdio.h


・バッファド・ファイル(ストリーム)入出力
  システムバッファを介して1文字単位あるいは1行単位のファイルアクセスを行ないます。
  テキストファイルの処理を行なうのに都合が良い。
  これらの関数が直接、データを 読み/書き するのではなくて、システムが設定したバッファとの間で行なうのです。
  システム・バッファのデータが空になったり、一杯になった時は、システムが自動的に(低水準ファイル入出力関数を用いて)データを 読み/書き します。


FILE *fp
    ↑ この fp は、ファイル・ポインタ変数と呼ばれます。

● fopen (ファイルを開く)
FILE *fopen(const char *PATH, const char *MODE);
  PATH == ファイル名を指すポインタ
  MODE == オープンモード("r" or "w" or "a" or "r+" or "w+" or "a+"
 [機能]
  PATHで示されるファイルを、MODEで示されるモードでファイルを開きます。
 [返り値]
  エラーなら NULL。
  正常に開けたなら、そのファイルへのファイル・ポインタ。

● fclose (ファイルを閉じる)
int fclose(FILE *fp);
  fp == ファイル・ポインタ
 [機能]
  fpで開かれているファイルを閉じます。
 [返り値]
  エラーなら 0以外(-1 みたいです)
  正常に閉じる事ができたら 0

● getc (ファイルからの1文字入力)
int getc(FILE *fp);
  fp == ファイル・ポインタ
 [機能]
  fpで開かれているファイルから1文字読み込み、その文字コードを返します。
 [返り値]
  ファイル・エンド [EOF] なら -1
  正常に読み込めたら その文字のコード

● putc (ファイルへの1文字出力)
int putc(int CH, FILE *fp);
  CH == 出力する文字データ
  fp == ファイル・ポインタ
 [機能]
  fpで開かれているファイルに、文字CHを出力します。
 [返り値]
  エラーなら -1
  正常に出力できたら その文字のコード

● fgets (ファイルからの1行入力)
char *fgets(char *BUFF, int SIZE, FILE *fp);
  BUFF == 文字列バッファへのポインタ
  SIZE == 読み込む最大文字数(単位はバイト)
  fp == ファイル・ポインタ
 [機能]
  fpで開かれているファイルから、バッファBUFFに1行読み込みします。
  1行の終わりは 1バイトデータ '0x0a' コードで判定されます。C++では "\n"文字
  読み出した1行の終わりには、1バイトデータ '0x00' が付け加えられます。
 [返り値]
  エラーなら NULL(0)
  正常に行なわれたらBUFFへのポインタ

● fputs (ファイルへの1行出力)
int fputs(const char *BUFF, FILE *fp);
  BUFF == 文字列バッファへのポインタ
  fp == ファイル・ポインタ
 [機能]
  バッファBUFFの文字列(終了コードは '0x00' )を、fpで開かれているファイルに書き込みします。
  '\n' は、LF( 0x0a )に変換されて出力されます。
 [返り値]
  エラーなら -1
  正常に出力できたら 最後に出力した文字のコード(大抵、0x00000000 みたいです。NULL文字)

● fscanf (書式付きファイル入力)
int fscanf(FILE *fp, const char *format, void *arg1, void *arg2, ...)
  fp == ファイル・ポインタ
  format == 書式制御文字列
  arg1,arg2,... == 引数、もしくはポインタ
 [機能]
  fpで開かれているファイルから、書式formatに従い、引数 arg1,arg2,...にデータを入力します。
  書式制御の部分(方法)は、scanf と同じ。
 [返り値]
  ファイル・エンド、もしくはエラーなら -1
  正常に出力できたら 入力できた項目数

● fprintf (書式付きファイル出力)
int fprintf(FILE *fp, const char *format[,arg1,arg2, ...])
  fp == ファイル・ポインタ
  format == 書式制御文字列
  arg1,arg2,... == 引数
 [機能]
  fpで開かれているファイルに書式formatに従い、引数 arg1,arg2,...のデータを出力します。
  書式制御の部分(方法)は、printfと同じ。
 [返り値]
  エラーなら、負の値(-1 みたいです)。
  正常に出力できたら 出力したバイト数。

● fseek (ファイル読み書き位置の移動)
int fseek(FILE *fp, long POS, int MODE);
  fp == ファイル・ポインタ
  POS == 移動量
  MODE == 移動の基点モード(SET、CUR、END)
 [機能]
  fpで開かれているファイルからの読み書きをする現在位置を、任意位置へ移動します。
  MODE ─┬ SEEK_SET ファイルの先頭から
         ├ SEEK_CUR ファイルの現在位置から
         └ SEEK_END ファイルの終わりから
 [返り値]
  エラーなら 0以外
  正常に移動できたら NULL(0)




もう一度書きますが、バッファド・ファイル入出力の関数 全部については、下記のヘッダーファイルを参照してください。
↓↓↓↓↓
C:\pspsdk\psp\sdk\include\libc\stdio.h


【 関連記事 】
PSPプログラミング ファイル入出力関数についての講釈
PSPプログラミング fopen( ); のファイル・オープンモードのレポート
PSPプログラミング ファイル入出力関数まとめ
PSPプログラミング バッファド・ファイル入出力のまとめ(抜粋)
PSPプログラミング 低水準ファイル入出力のまとめ(抜粋)

[edit]

CM: 0
TB: 0

page top

この記事は、低水準ファイル入出力で主に使う関数のまとめです。
あまり使わないであろう関数については省いてあります。

全部の関数については、下記のヘッダーファイルを参照してください。
↓↓↓↓↓
C:\pspsdk\psp\sdk\include\pspiofilemgr.h


・低水準ファイル入出力

  バイト単位のファイルアクセスを、ユーザバッファとの間で行ないます。

int fp
  ↑この fp は、ファイル・ディスクリプタと呼ばれます。


低水準ファイル入出力では、ファイル・ディスクリプタ(ファイル記述子)という整数値を用いてファイル操作をします。

● sceIoOpen (ファイルを開く)
int sceIoOpen(const char *PATH, int FLAG, SceMode MODE);
  PATH == ファイル名を指すポインタ
  FLAG == ファイルのアクセスフラグ
  MODE == ファイルの属性(パーミッション)
 [機能]
  PATHで示されるファイルを、FLAGで示されるアクセスフラグでファイルを開きます。
  その際のファイルの属性は、MODEとします。

   FLAGの値  機 能
   PSP_O_RDONLY 読み出し・オンリー・モード
   PSP_O_WRONLY 書き込み・オンリー・モード
   PSP_O_RDWR 読み出し・書き込み・モード
   PSP_O_NBLOCK 不明(ひょっとして、ブロッキング転送に関係あり?)
   PSP_O_DIROPEN ディレクトリ・オープン・モード(使用されない)
   PSP_O_APPEND 追記モード
   PSP_O_CREAT ファイルの新規作成モード
   PSP_O_TRUNC 既存ファイルをオープンし、空ファイルにする
   PSP_O_EXCL ファイルが存在すれば新規作成しない
   PSP_O_NOWAIT 待ち時間無し転送モ-ド

MODE ファイルの属性(パーミッション) は、0777 で良いみたいです。

 [返り値]
  エラーなら 負の値 ( -2147418110 )
  正常ならファイル・ハンドル値

● sceIoClose (ファイルを閉じる)
int sceIoClose(int fp);
  fp == ファイル・ディスクリプタ
 [機能]
  fpのファイルを閉じます。
 [返り値]
  エラーなら 負の値 ( -2147351773 )
  正常なら 0

● sceIoRead (ファイルからの一括読み出し)
int sceIoRead(int fp, char *BUFF, int SIZE);
  fp == ファイル・ディスクリプタ
  BUFF == 読み出すデータの格納先
  SIZE == 読み出すデータのバイト数(希望する値)
 [機能]
  fpのファイルからバッファBUFFにSIZEバイトのデータを読み出します。
 [返り値]
  エラーなら 負の値 ( -2147351773 )
  正常なら 読み込みしたデータのバイト数

● sceIoWrite (ファイルへの一括書き込み)
int sceIoWrite(int fp, char *BUFF, int SIZE);
  fp == ファイル・ディスクリプタ
  BUFF == 書き込むデータが格納されているバッファ
  SIZE == 書き込むデータのバイト数(希望する値)
 [機能]
  fpのファイルへバッファBUFFからSIZEバイトのデータを書き込みします。
 [返り値]
  エラーなら 負の値 ( -2147351773 )
  正常なら 書き込みできたデータのバイト数

● sceIoLseek (ファイル読み/書き位置の移動)
int sceIoLseek(int fp, SceOff OFFSET, int WHENCE);
  fp == ファイル・ディスクリプタ
  OFFSET == 移動量
  WHENCE == 移動の基点モード(PSP_SEEK_SET、PSP_SEEK_CUR、PSP_SEEK_END)
 [機能]
  fpで開かれているファイルからの読み書きをする現在位置を、任意位置へ移動します。
  WHENCE ─┬ PSP_SEEK_SET ファイルの先頭から
           ├ PSP_SEEK_CUR ファイルの現在位置から
           └ PSP_SEEK_END ファイルの終わりから
 [返り値]
  エラーなら 0以外 ( 負の値 : -2147351773 )
  正常に移動できたら NULL(0)

● sceIoRemove (ファイルの削除)
int sceIoRemove(const char *PATH);
  PATH == ファイル名を指すポインタ
 [機能]
  PATH の ファイルを削除します。
 [返り値]
  エラーなら 0以外 ( 負の値 : -2147418110 )
  正常に削除できたら NULL(0)




もう一度書きますが、低水準ファイル入出力の関数 全部については、下記のヘッダーファイルを参照してください。
↓↓↓↓↓
C:\pspsdk\psp\sdk\include\pspiofilemgr.h


【 関連記事 】
PSPプログラミング ファイル入出力関数についての講釈
PSPプログラミング fopen( ); のファイル・オープンモードのレポート
PSPプログラミング ファイル入出力関数まとめ
PSPプログラミング バッファド・ファイル入出力のまとめ(抜粋)
PSPプログラミング 低水準ファイル入出力のまとめ(抜粋)

[edit]

CM: 0
TB: 0

page top

メモリースティック内のファイル書き換えの方法


ファイルの書き換えは、2通りの場合について解説します
(1) ファイルサイズが変わらない場合(この記事で紹介
(2) ファイルサイズが変わる場合(次の記事で紹介


>> (1) ファイルサイズが変わらない場合
書き換えする前と後で、デバイス上のファイルの並び方が物理的に変わらない場合です。
書き換えするデータ数が同じという条件

この場合の、ファイル書き換え方法の手順(日本語)

1. ファイルを読み書きモードで開きます
2. 書き換えする部分のデータを読み出します
3. 書き換え済みか調べます
4. 書き換え済みなら次の作業に移ります
5. 未書き換えなら、書き換える作業に入ります(以下)
6. ファイルの、書き換える位置にシーク命令で移動します
7. 必要なデータだけを書き込みます
8. ファイルを閉じます

上記を C++プログラミングしてみます

【 ファイル "ms0:/機密文書.TXT" の、
10バイト目からの連続8バイトデータ "ULTRAMAN" を "GORENJER"に書き換える例 】

この関数のコピペ&利用&改造は、ご自由にどうぞ。
赤い文字の部分は必要に応じて書き換える箇所です

// ファイルのデータ書き換え関数サンプル(同じデータ数での書き換え)
int File_Kakikae(void)
{
int fp;
char buff[256]; // バッファサイズは、書き換えに余裕の256バイト長だ

fp = sceIoOpen("ms0:/機密文書.TXT", PSP_O_RDONLY|PSP_O_WRONLY, 0777);
if(fp <0) // ファイル・オープンエラーなら
{
sceIoClose(fp); // ファイルを閉じて
return -1; // ファイルが開けないエラー
}
sceIoLseek(fp, 0, PSP_SEEK_SET); // ファイルの先頭へ移動
sceIoLseek(fp, 10, PSP_SEEK_CUR); // ファイルの10バイト目へ移動
sceIoRead(fp, buff, 8); // fpから、8バイトのデータ読み込み

if(memcmp(buff,"ULTRAMAN",8)==0) // 書き換え前か確認して
{ // 書き換え前なら書き換える(以下)
sceIoLseek(fp, 0, PSP_SEEK_SET); // ファイルの先頭へ移動
sceIoLseek(fp, 10, PSP_SEEK_CUR); // ファイルの書き換え位置へ移動
sceIoWrite(fp, "GORENJER", 8); // 書き換えデータを書き込む
}
sceIoClose(fp); // ファイルを閉じる
return 0; // 正常終了
}



FILE *fp; での記述例は省略します。


【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放
PSPプログラミング メモリースティック内のファイル書き換え方法 その1
PSPプログラミング メモリースティック内のファイル書き換え方法 その2

[edit]

CM: 0
TB: 0

page top

メモリースティック内のファイル書き換えの方法


ファイルの書き換えは、2通りの場合について解説します
(1) ファイルサイズが変わらない場合(前の記事で紹介
(2) ファイルサイズが変わる場合(この記事で紹介


>> (2) ファイルサイズが変わる場合

異なるデータ長へ書き換えするという条件
書き換えする前と後で、デバイス上のファイルの長さが変わってしまう場合です。

この場合の、ファイル書き換え方法の手順(日本語)

1. 書き換えるファイルを、読み書きモードで開きます
2. 更に、書き換えるファイルを、読み出しモードでも開きます
3. 書き換えする行まで、読み飛ばします
4. 書き換え済みかチェックします
5. 未書き換えなら、以下の作業をします
6. 書き換えする行の、次の行を読み込みます
7. 書き換えるデータ(行)を書き込みます
8. 6.で読み込みしたデータ(行)を書き込みます
9. [EOF]まで、データの切り詰め処理(書き直し)をします
10. 書き換え後のファイルサイズを取得します
11. 実際のファイルサイズを取得します
12. ファイルを閉じます
13. 書き換え後のファイルサイズが書き換え前より長くなった場合は、ここでおしまい
   (書き換え後のファイルサイズが書き換え前より短くなる場合は、下記を行なう)
14. メモリを確保して、ファイルをメモリに読み込んでから書き出す
15. メモリを解放して、ファイルを閉じます

上記を C++プログラミングしてみます


この関数のコピペ&利用&改造は、ご自由にどうぞ。

#include <stdio.h>
#include <malloc.h>

// テキストファイルを書き換える関数のサンプル
int File_Kakikae(filename, posLine, before, after)
// 引数の説明とか
const char *filename; // 書き換えを行なうファイルのPATH
int posLine; // 書き換えを行なう行の行番号(最初を1行目として計算)
const char *before; // 書き換え前の文字列へのポインタ
const char *after; // 書き換える文字列へのポインタ
{
char buff[256]; // 作業用のバッファ

FILE *fpRW = fopen(filename, "r+"); // 読み書き
FILE *fpR = fopen(filename, "r" ); // 読み出し
if( (fpRW == NULL) || (fpR == NULL) )
return -1; // ファイルが開けないエラー

int i;
for(i=1; i<posLine; i++) { // ループ(書き換えをおこなう行の手前まで)
fgets(buff, 256, fpRW); // 読み飛ばし
}
fseek(fpR, ftell(fpRW), PSP_SEEK_SET); // 読み出し位置をコピペ
fgets(buff, 256, fpR); // 1行 読み出し
if(strcmp(buff, before) == NULL) // 書き換え前か?
{ // 書き換え前なら以下を実行
fgets(buff, 256, fpR); // 書き換える行の、次の1行を読み出し
fputs(after, fpRW); // データを書き換える
fputs(buff, fpRW); // 先ほど読み出しておいた1行を書き込む

while(fgets(buff, 256, fpR) != NULL) { // 次の1行を読み出し
fputs(buff, fpRW); // 1行 書き込み(複写)
} // [EOF]まで繰り返し
}
else
{ // すでに書き換え済みだったら、何もせずにリターン
fclose(fpRW); // ファイルを閉じます
fclose(fpR ); // ファイルを閉じます
return 0; // すでに書き換え済みなのでエラーでは無い
}

long offset = ftell(fpRW); // 書き換え後のファイルサイズを取得
long fsize;
fseek(fpRW, 0, SEEK_SET);
fseek(fpRW, 0, SEEK_END);
fsize = ftell(fpRW); // 実際のファイルサイズを取得

fclose(fpRW); // ファイルを閉じます
fclose(fpR ); // ファイルを閉じます

if(fsize > offset) // ファイルサイズが短くなる場合への対処を以下に
{ // ここから、trancate( ) 関数のような処理(ファイルを短くする)
char *ptr; // メモリ確保用のポインター変数 兼、メモリハンドル用
int fp;

ptr = malloc( offset ); // メモリの確保をやってみる.
if(ptr == NULL) // メモリの確保が出来なかったら、以下
{
free(ptr); // メモリの解放.
return -1; // メモリが確保できなかったエラー
} // でも書き換えは成功しています。ファイルの末尾にゴミ付着エラー
fp = sceIoOpen(filename, PSP_O_RDONLY, 0777); // 読み出して
sceIoRead(fp, ptr, offset);
sceIoClose(fp);
fp = sceIoOpen(filename, PSP_O_WRONLY, 0777); // 書き込む
sceIoWrite(fp, ptr, offset);
sceIoClose(fp); // 閉じるとファイルが短くなる

free(ptr); // メモリの解放.
}
return 0; // 正常終了
}

(注) PSPSDKに、truncate( ) 関数が無かったので、代用処理を作ってみました。


【 ファイル "ms0:/重要文書.txt" の 5行目の文字列 "BEFORE\n" を "XYZ\n" に書き換える例 】
File_Kakikae("ms0:/重要文書.txt", 5, "BEFORE\n", "XYZ\n");


この関数の長所と問題点
○ 書き換える行を指定しているのは、他の行にも同じ文字列がある場合を想定しているからです。
○ 書き換えられているか確認してから書き換えるのは、念のためです。(^^;;;
× パラメータのエラーチェックは行なっていないのです。手抜きです。
× 短い文字列に書き換えを行なう場合、ファイルサイズが 32MB 以上だと、
 ファイルの末尾にゴミが残ります(ファイルがメモリに読み込めないため)。


【 関連記事 】
PSPプログラミング ファイルを開く手順をM@STERしよう!
PSPプログラミング ファイルサイズの取得をM@STERしよう!
PSPプログラミング メモリの確保(割り当て)をM@STERしよう!
PSPプログラミング ファイルの読み込みをM@STERしよう!
PSPプログラミング ファイルを閉じて・・・・・。
PSPプログラミング 忘れちゃダメよ!メモリの解放
PSPプログラミング メモリースティック内のファイル書き換え方法 その1
PSPプログラミング メモリースティック内のファイル書き換え方法 その2

[edit]

CM: 0
TB: 0

page top


h o m e |


 

2017-04