|
DelphiXE3 [FMX] ファイル 2014/06/07 |
前回は、印刷の機能について記述しました。
今回は、ファイルについて見ていきます。
[Dialogs]内の
・「開く」画面(OpenDialog)
・「保存」画面(SaveDialog)
については既に記述した通りです。また、シンプルなテキストファイルの読み書きであれば、メモ(Memo)コンポーネントを利用する事が出来ます。例えば
のようにコンポーネントを配置し、OpenDialog1、SaveDialog1 の Filter プロパティ内容を
TextFile(*.txt)|*.txt|
TextFile(ANSI)(*.txt)|*.txt|
TextFile(UTF8)(*.txt)|*.txt|
TextFile(Unicode)(*.txt)|*.txt |
とします(※上記は改行していますが、実際には改行していません)。また、Label1 の AutoSize プロパティを「True」にしています。
// 起動時
procedure TForm1.FormShow(Sender: TObject);
begin
Label1.Text := '';
end;
// 開く
procedure TForm1.Button1Click(Sender: TObject);
begin
if (Label1.Text <> '') then begin
OpenDialog1.InitialDir := ExtractFilePath(Label1.Text);
OpenDialog1.FileName := ExtractFileName(Label1.Text);
end
else begin
OpenDialog1.InitialDir := ExtractFilePath(ParamStr(0));
OpenDialog1.FileName := '';
end;
if (OpenDialog1.Execute) then begin
Label1.Text := OpenDialog1.FileName;
Memo1.Lines.Clear;
try
case (OpenDialog1.FilterIndex) of
1: Memo1.Lines.LoadFromFile(Label1.Text);
2: Memo1.Lines.LoadFromFile(Label1.Text,TEncoding.ANSI);
3: Memo1.Lines.LoadFromFile(Label1.Text,TEncoding.UTF8);
4: Memo1.Lines.LoadFromFile(Label1.Text,TEncoding.Unicode);
end;
finally
;
end;
end;
end;
// 保存
procedure TForm1.Button2Click(Sender: TObject);
begin
if (Label1.Text <> '') then begin
SaveDialog1.InitialDir := ExtractFilePath(Label1.Text);
SaveDialog1.FileName := ExtractFileName(Label1.Text);
end
else begin
SaveDialog1.InitialDir := ExtractFilePath(ParamStr(0));
SaveDialog1.FileName := '';
end;
if (SaveDialog1.Execute) then begin
Label1.Text := SaveDialog1.FileName;
try
case (SaveDialog1.FilterIndex) of
1: Memo1.Lines.SaveToFile(Label1.Text);
2: Memo1.Lines.SaveToFile(Label1.Text,TEncoding.ANSI);
3: Memo1.Lines.SaveToFile(Label1.Text,TEncoding.UTF8);
4: Memo1.Lines.SaveToFile(Label1.Text,TEncoding.Unicode);
end;
finally
;
end;
end;
end; |
とするだけで、簡単なテキストエディタが出来上がりです。
「Memo1.Lines.LoadFromFile(Label1.Text);」のように、ファイルを開く際にエンコーディング指定を省略すると、「適切なエンコーディングを用いてロードされます」(※ヘルプより)との事です。また、
「Memo1.Lines.SaveToFile(Label1.Text);」のように、ファイルを保存する際にエンコーディング指定を省略すると、前回に「開く」をした際のエンコーディングで保存するようです。「開く」をしていない場合は、ANSIエンコーディングで保存するようです。
FireMonkey(FMX)には、リッチエディット(TRichEdit)コンポーネントは存在しませんので、それについて記述する事は出来ません。
次に、INIファイルについて見てみます。
INIファイルは、アプリケーションの設定などを保存・呼び出しする際に利用される設定ファイルですが、DelphiXE3 では System.IniFiles ユニットが存在します。試しに、上記のサンプルで、フォーム位置を保存・呼び出し出来るようにしてみます。uses節に「System.IniFiles」を追記しておきます。
type
TForm1 = class(TForm)
・・・
private
{ private 宣言 }
procedure OpenIniFile;
procedure SaveIniFile;
public
{ public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.OpenIniFile;
var
IniFile : TIniFile;
begin
IniFile := TIniFile.Create(ChangeFileExt(ParamStr(0),'.ini'));
try
Form1.Left := IniFile.ReadInteger('Form','X',0);
Form1.Top := IniFile.ReadInteger('Form','Y',0);
except
;
end;
IniFile.Free;
end;
procedure TForm1.SaveIniFile;
var
IniFile : TIniFile;
begin
IniFile := TIniFile.Create(ChangeFileExt(ParamStr(0),'.ini'));
try
IniFile.WriteInteger('Form','X', Form1.Left);
IniFile.WriteInteger('Form','Y', Form1.Top);
except
;
end;
IniFile.Free;
end;
// 起動時
procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Text := '';
OpenIniFile;
end;
// 終了時
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
SaveIniFile;
end; |
起動時の処理を OnShowイベントハンドラで行なっていましたが、その場合、フォーム位置が移動する様子がパッパッと見えてしまうため、OnCreateイベントハンドラで行うように修正しています。
起動時に、INIファイルを読み込むようにして、終了時に INIファイルを書き込むようにしています。「IniFile : TIniFile;」は TForm1クラス定義内に入れてしまってもいいと思いますが、起動時に INIファイルを開け閉めする、終了時に INIファイルを開け閉めする、という意識のため、こうしています。
プログラムを実行し、終了すると、実行プログラムと同じフォルダ内に、ファイル名がプログラム名と同じで拡張子が「.ini」のファイルが作成出来ています。それを Windowsの「メモ帳」等で開くと
のようになっているのが分かると思います。思惑通りに実行出来ていますね。設定ファイル内には、このほか、フォームの大きさ、前回ファイル名、等を扱えるようにするのも良いと思います。
次は、メモコンポーネントを使用しない、テキストファイルの読み書きについて見ていきます。取り敢えず、上記と同じく、設定内容を INIファイルを使用せず、テキストファイルとして読み書きするような手続きを作成してみます。
type
TForm1 = class(TForm)
・・・
private
{ private 宣言 }
procedure OpenIniFile;
procedure SaveIniFile;
procedure OpenDatFile;
procedure SaveDatFile;
public
{ public 宣言 }
end;
・・・
procedure TForm1.OpenDatFile;
var
F : TextFile;
fn,s : String;
begin
fn := ChangeFileExt(ParamStr(0),'.dat');
Form1.Top := 0;
Form1.Left := 0;
if not(FileExists(fn)) then exit;
try
AssignFile(F, fn);
FileMode := 0;
Reset(F);
ReadLn(F, s); Form1.Left := StrToInt(s);
ReadLn(F, s); Form1.Top := StrToInt(s);
CloseFile(F);
except
CloseFile(F);
end;
end;
procedure TForm1.SaveDatFile;
var
F : TextFile ;
fn,s : String;
begin
fn := ChangeFileExt(ParamStr(0),'.dat');
try
AssignFile(F, fn);
ReWrite(F);
s := IntToStr(Form1.Left); WriteLn(F,s);
s := IntToStr(Form1.Top ); WriteLn(F,s);
CloseFile(F);
except
CloseFile(F);
if FileExists(fn) then DeleteFile(fn);
end;
end;
// 起動時
procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.Text := '';
// OpenIniFile;
OpenDatFile;
end;
// 終了時
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// SaveIniFile;
SaveDatFile;
end; |
コンパイル時に OpenIniFile、SaveIniFile を使用していないというヒントが出ますが気にせず実行してみます。INIファイルの時と同様に行われる事が分かります。
コードを単純化するため、文字列を整数に変換するのに StrToInt関数を利用していますが、この関数は、想定しない値が入ると例外が発生してしまうため、私自身はこの関数をほとんど利用せず、通常は、Val関数を利用した自作の関数を利用しています。
ここでは、データファイルということで、「.dat」の拡張子にしていますが、これを Windowsの「メモ帳」等で開くと
のように数値だけになっているのが分かります。書き込む際に
「WriteLn(F,'X='+s);」のようにすればいいのですが、読む込む際に、最初の「X=」を読み飛ばすプログラムコードを入れる必要があります。それを手間である・プログラムの可読性が辛くなるので除外するか、あるいは、データファイルを別アプリケーションで参照する事を意識して付けるか、という判断は自由にされると良いと思います。
INIファイルの良さは、可読性もありますが、後で設定ファイルの構成を編集しやすくなるという所です。つまり、セクション名・キー名さえちゃんとしておけば、設定ファイル内の設定場所は後でいくらでも変更出来ます。
テキストファイルで行う場合は、後で編集するのがかなり厳しくなります。行を追加していくのは比較的容易ですが、行間に挿入したくなる場合には、既にプログラムを実行していると容易ではありません。そうなると、
white not(EOF(F)) do begin
ReadLn(F, s);
if ・・・ then ・・・
else if ・・・ then ・・・
・・・
(或いは case文)
end; |
のように1行読んで判断して・・・といったプログラミングが必要になります。これは流石に手間であるため、設定ファイルを読み書きするだけでそんな事をする位ならば、TIniFile を利用する、という選択をする場合が多いです。
なお、Windowsアプリケーションでの設定では、INIファイルのほか、レジストリを使用する、という事もよく行われてきています。レジストリは、
System.Win.Registry
内にありますので、FireMonkey(FMX)でも利用できると思いますが、Windows限定になると思われますので、マルチプラットフォーム対応を考えるならば、使う事は出来ません。
ちなみに、私自身はこれまでも書いていますが、レジストリが大きくなると Windowsが重くなる、とか、レジストリが壊れると相当に困る事になる、とか、設定を他PCへ移行したりするのが手間であるとか、などで元々自分の好みではありませんからほとんど使っていません。
というわけでレジストリについては記述しません。
そもそも、マルチプラットフォーム対応を考えるからこそ、FireMonkey(FMX)を利用するのだから、Windowsでしか使えない機能について考えるのは本末転倒であるやもしれません。
次は、バイナリファイルについて見てみます。
上記のデータファイル読み書きを少し変更してみます。
procedure TForm1.OpenDatFile;
var
F : File;
fn : String;
i : Integer;
begin
fn := ChangeFileExt(ParamStr(0),'.dat');
Form1.Top := 0;
Form1.Left := 0;
if not(FileExists(fn)) then exit;
try
AssignFile(F, fn);
FileMode := 0;
Reset(F,1);
BlockRead(F,i,SizeOf(i)); Form1.Left := i;
BlockRead(F,i,SizeOf(i)); Form1.Top := i;
CloseFile(F);
except
CloseFile(F);
end;
end;
procedure TForm1.SaveDatFile;
var
F : File;
fn : String;
i : Integer;
begin
fn := ChangeFileExt(ParamStr(0),'.dat');
try
AssignFile(F, fn);
ReWrite(F,1);
i := Form1.Left; BlockWrite(F,i,SizeOf(i));
i := Form1.Top; BlockWrite(F,i,SizeOf(i));
CloseFile(F);
except
CloseFile(F);
if FileExists(fn) then DeleteFile(fn);
end;
end; |
実行する前に、以前作成したデータファイルは Windowsのエクスプローラで削除しておいて下さい。
実行すると、これまで同様に、フォーム位置の保存・呼び出しが出来るのが確認出来ると思います。データファイル「〜〜.dat」のファイルを Windowsの「メモ帳」等で開くと
等のように何が書かれているのか分かりません。
バイナリエディタで開くと
のように表示されるのが分かります。
Integer型=4バイトで、2つの整数値を保存していますから8バイトのファイルになるという事ですね。フォーム位置ですから、2バイトの SmallInt型(Int16型)でも構わないと思います。そうすれば4バイトのファイルになります。
というわけで、バイナリファイルにすると、ファイルサイズを圧縮しやすくなりますが(状況によってはそうでもない場合もあります)、ファイル内容の可読性は相当に低くなります。
というわけで、FireMonkey(FMX)でも、テキストファイル、バイナリファイルの読み書きについては正常に動作しているというのがわかりました。文字列については確認していませんが。
|
|
バッチファイル
BASIC
C言語のお勉強
拡張子な話
DOSプログラム
Delphi
>Dehi入門編
>Delphi2010
>DelphiXE3
▲2014/06/06
2014/06/07
▼2014/06/09
シェアウェア
Script!World
データベース
|