Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2019年10月17日] [更新 2019年10月19日] Delphi 一般・その他
   
数値のディスクへの保存とディスクからの読み込み
動作確認等 Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32
[整理番号 - 0810]







数値のディスクへの保存とディスクからの読み込み


単一の数値をディスクに保存し,保存した数値をディスクから読み込むサンプルです.

数値型の変数を指定して,ストリームに,その変数が使用しているバイト数分だけ書き込みます.そのストリームをディスクに保存します.するとファイルが作成されます.そのファイルに収められたデータが対象の数値のデータということになります.
ディスクから読み込む時は,ストリームにファイルをロードします.すると,ストリームに,ファイルに収められているデータが書き込まれます.そのストリームのデータを目的の数値型の変数の値として取得します.

本ページのサンプルでは,ストリームとして,主に TMemoryStream を使用しています.TMemoryStream とその派生クラスには,引数が数値型の変数だけでよいメソッド類があります.本ページではそれらのメソッド類を使用しています.
ファイル型の変数を使用したサンプルも掲載しています.



[備考]
TIniFile には,整数型の値と浮動小数点型の値をファイルへ書き込むためのメソッドとファイルから読み込むためのメソッドが実装されています.





01_Single 型のデータのディスクへの保存と読み出し


TMemoryStream とその派生クラスには,数値型の変数のデータをメモリストリームm 自身に書き込むためのメソッド WriteData があります.また,ReadData メソッドを使用すると,数値型の変数にメモリストリームのデータを読み込ませることができます.それらのメソッドを使用するサンプルです.
このサンプルでは Single 型の数値を保存してそれを読み出して表示します.



図1
ディスクに保存したデータを読み出して表示
  • 元の数値は 1.23456E5
  • 4 バイトの浮動小数点型の値として取得
  • 最初の表示は単純に文字列に変換した値
  • 次は指数形式で表示

リスト1
//=============================================================================
//  数値をディスクに保存する
//  4バイト(32ビット)の浮動小数点の値をファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LSingle   : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // 対象の数値をストリームに書き込む
    LSingle := 1.23456E5;
    LStream.WriteData(LSingle);

    // そのストリームのデータをファイルに保存
    LStream.SaveToFile(LFilePath);
  finally
    FreeAndNil(LStream);
  end;
end;

//=============================================================================
//  保存したデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LSingle   : Single;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // ファイルのデータをストリームに読み込む
    LStream.LoadFromFile(LFilePath);

    // 読み込んだデータを4バイト(32ビット)の浮動小数点の値として取得
    LStream.ReadData(LSingle);

    // 取得した値を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    FreeAndNil(LStream);
  end;
end;




02_Integer 型のデータのディスクへの保存と読み出し


WriteData メソッドと ReadData メソッドは各種の数値型の変数を扱えます.
以下は Integer 型の場合です.



図2
ディスクに保存したデータを読み出して表示
  • Integer 型の値として取得

リスト2
//=============================================================================
//  数値をディスクに保存する
//  Integer 型 (4バイト - 32ビット) の値をファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LInteger  : Integer;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // 対象の数値をストリームに書き込む
    LInteger := 12345678;
    LStream.WriteData(LInteger);

    // そのストリームのデータをファイルに保存
    LStream.SaveToFile(LFilePath);
  finally
    FreeAndNil(LStream);
  end;
end;

//=============================================================================
//  保存したデータを数値として取得
//  Integer 型 (4バイト - 32ビット) の値として取得
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LInteger  : Integer;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // ファイルのデータをストリームに読み込む
    LStream.LoadFromFile(LFilePath);

    // 読み込んだデータを Integer 型の値として取得
    LStream.ReadData(LInteger);

    // 取得した値を表示
    Memo1.Lines.Add(IntToStr(LInteger));
  finally
    FreeAndNil(LStream);
  end;
end;




03_Write と Read メソッドを使用した数値の保存と読み出し


Delphi 6 等の旧いバージョンの Delphi には WriteData, ReadData 等のメソッドは実装されていません.代わりに Write, Read, WriteBuffer, ReadBuffer 等のメソッドを使用します.
以下のコードはその例です.このサンプルコードは Windows 7 U32(SP1) + Delphi6(UP2) Pro の環境で動作を確認しています.実行結果は,本ページの最初のサンプルと同じです.



リスト3
//=============================================================================
//  数値をディスクに保存する
//  4バイト(32ビット)の浮動小数点の値をファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LSingle   : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // 対象の数値をストリームに書き込む
    LSingle := 1.23456E5;
    LStream.Write(LSingle, SizeOf(LSingle));

    // そのストリームのデータをファイルに保存
    LStream.SaveToFile(LFilePath);
  finally
    FreeAndNil(LStream);
  end;
end;

//=============================================================================
//  保存したデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TMemoryStream;
  LSingle   : Single;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // ファイルのデータをストリームに読み込む
    LStream.LoadFromFile(LFilePath);

    // 読み込んだデータを Singel 型の値として取得
    LStream.Read(LSingle, SizeOf(LSingle));

    // 取得した値を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    FreeAndNil(LStream);
  end;
end;




04_TFileStream を使用した数値の書き込みと読み出し


TFileStream を使用して,データをディスク上のファイルに書き込んだり読み出す例でず.
TFileStream はファイルストリームにデータを書き込むとそのままファイルの内容も更新されます.読み出す時もファイルストリームから直接読み込めます.TFileStream.Create メソッドで,ファイルに対しての読み書きモードを設定します.



リスト4
//=============================================================================
//  数値をファイルに保存する
//  4バイト(32ビット)の浮動小数点の値をファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TFileStream;
  LSingle   : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  // TFileStream の生成
  // 新規にファイルを作成するモードで生成 (既存ファイルは上書きとなる)
  LStream := TFileStream.Create(LFilePath, fmCreate);
  try
    // 対象の数値をストリームに書き込む
    LSingle := 1.23456E5;
    LStream.WriteData(LSingle);
  finally
    FreeAndNil(LStream);
  end;
end;

//=============================================================================
//  保存したデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LStream   : TFileStream;
  LSingle   : Single;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  // TFileStream の生成
  // 読み出しモードで生成
  LStream := TFileStream.Create(LFilePath, fmOpenRead);
  try
    // Single 型の値として取得
    LStream.ReadData(LSingle);

    // 取得した値を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    FreeAndNil(LStream);
  end;
end;


TFileStream は TFile を使用して生成することもできます.TFile を使用すると,TFile のメソッドを使用してファイルのタイムスタンプや属性等の取得や設定ができます.
TFile を使用するには uses に System.IOUtils が必要です.



リスト5
  // TFileStream の生成
  // System.IOUtils.TFile を使用する方法
  // 新規にファイルを作成するモードで生成 (既存ファイルは上書きとなる)
  LStream := TFile.Open(LFilePath, TFileMode.fmCreate);


  // TFileStream の生成
  // System.IOUtils.TFile を使用する方法
  // 読み出しモードで生成
  LStream := TFile.Open(LFilePath, TFileMode.fmOpen);




05_TBinaryWriter と TBinaryReader を使用した数値の読み書き


データをファイルに書き込む時は TBinaryWriter のストリームを使用して,データをファイルから読み込む時は TBinaryReader のストリームを使用する例でず.
TBinaryWriter のストリームにデータを書き込むとそのままファイルの内容も更新されます.読み出す時は TBinaryReader のストリームから直接読み込めます.TBinaryReader には,数値の型に応じた読み出し用のメソッドが用意されています.



リスト6
//=============================================================================
//  数値をファイルに保存する
//  4バイト(32ビット)の浮動小数点の値をファイルに保存
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath  : string;
  LBinWriter : TBinaryWriter;
  LSingle    : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  // TBinaryWriter の生成
  // 新規にファイルを作成するモードで生成 (既存ファイルは上書きとなる)
  LBinWriter := TBinaryWriter.Create(LFilePath);
  try
    // 対象の数値を書き込む
    LSingle := 1.23456E5;
    LBinWriter.Write(LSingle);
  finally
    FreeAndNil(LBinWriter);
  end;
end;

//=============================================================================
//  保存したデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath  : string;
  LBinReader : TBinaryReader;
  LSingle    : Single;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  // TBinaryReader の生成
  // 読み出しモードで生成
  LBinReader := TBinaryReader.Create(LFilePath);
  try
    // Single 型の値として取得
    LSingle := LBinReader.ReadSingle;

    // 取得した値を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    FreeAndNil(LBinReader);
  end;
end;




06_ファイル型 File of Byte を使用した数値の保存と読み出し


ファイル型のオブジェクトを使用して数値をディスクに保存します.保存した数値もファイル型のオブジェクトを使用して読み出して取得するサンプルです.ファイル型は Byte 型としています.




図3
ディスクに保存したデータを読み出して表示
  • 元の値は 5.4321E5
  • 4 バイトの浮動小数点型の値として取得
  • 最初の表示は単純に文字列に変換した値
  • 次は指数形式で表示

リスト7
//=============================================================================
//  数値をディスクに保存する
//  4 バイト(32 ビット)の浮動小数点の値をファイルに保存
//  ファイル型 File of Byte を使用する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LFile     : File of Byte;
  LSingle   : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  // 保存ファイル名をファイル型の変数に割り当てる
  AssignFile(LFile, LFilePath);
  try
    // 新規にファイルを作成して開く(既存ファイルは上書き)
    Rewrite(LFile);

    // データをファイルに書き込む
    LSingle := 5.4321E5;
    BlockWrite(LFile, LSingle, SizeOf(Single));
  finally
    // ファイルを閉じる
    CloseFile(LFile);
  end;
end;

//=============================================================================
//  ディスクに保存してあるデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//  ファイル型 File of Byte を使用する例
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LFile     : File of Byte;
  LSingle   : Single;
begin
  //保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  //ファイル名をファイル型の変数に割り当てる
  AssignFile(LFile, LFilePath);
  try
    // ファイルを開く
    Reset(LFile);

    // Single 型の変数に読み込む
    BlockRead(LFile, LSingle, SizeOf(Single));

    // 取得結果を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    // ファイルを閉じる
    CloseFile(LFile);
  end;
end;




07_ファイル型 File of Single を使用した数値の保存と読み出し


前項と同じく,ファイル型のオブジェクトを使用するサンプルですが,ファイル型を,扱う数値型と同じ型の Single 型としています.実行結果は前項のサンプルと同じです.



リスト8
//=============================================================================
//  数値をディスクに保存する
//  4バイト(32ビット)の浮動小数点の値をファイルに保存
//  ファイル型 File of Singlいe を使用する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LFile     : File of Single;
  LSingle   : Single;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  // 保存ファイル名をファイル型の変数に割り当てる
  AssignFile(LFile, LFilePath);
  try
    // 新規にファイルを作成して開く(既存ファイルは上書き)
    Rewrite(LFile);

    // データをファイルに書き込む
    LSingle := 5.4321E5;
    BlockWrite(LFile, LSingle, 1);
  finally
    // ファイルを閉じる
    CloseFile(LFile);
  end;
end;

//=============================================================================
//  ディスクに保存してあるデータを数値として取得
//  4バイト(32ビット)の浮動小数点の値として取得
//  ファイル型 File of Single を使用する例
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LFile     : File of Single;
  LSingle   : Single;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  // 保存ファイル名をファイル型の変数に割り当てる
  AssignFile(LFile, LFilePath);
  try
    // ファイルを開く
    Reset(LFile);

    // ファイルから Single 型の変数に読み込む
    BlockRead(LFile, LSingle, 1);

    // 取得結果を表示
    Memo1.Lines.Add(FloatToStr(LSingle));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LSingle));
  finally
    // ファイルを閉じる
    CloseFile(LFile);
  end;
end;




08_FileWrite / FileRead 関数を使用した数値の保存と読み出し


FielWrite 関数や FileRead 関数を使用するサンプルです.Double 型の数値の例です.
これらの関数類は,内部で Windows API の WriteFile, ReadFile 関数を使用しています.



リスト9
//=============================================================================
//  数値をディスクに保存する
//  8バイト(64ビット)の浮動小数点の値をファイルに保存
//  FileCreat, FileWrite を使用する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath : string;
  LhFile    : THandle;
  LValue    : Double;
begin
  // 保存先
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';

  Memo1.Lines.Clear;

  // 保存ファイル名のファイルを作成
  LhFile := FileCreate(LFilePath);
  try
    // データをファイルに書き込む
    LValue := 5.4321E5;
    FileWrite(LhFile, LValue, SizeOf(Double));
  finally
    // ファイルを閉じる
    FileClose(LhFile);
  end;
end;

//=============================================================================
//  ディスクに保存してあるデータを数値として取得
//  8バイト(64ビット)の浮動小数点の値として取得
//  FileOpen, FileRead を使用する例
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LFilePath : string;
  LhFile    : THandle;
  LValue    : Double;
begin
  LFilePath := ExtractFilePath(Application.ExeName) + 'Atest.bin';
  if not FileExists(LFilePath) then Exit;

  Memo1.Lines.Clear;

  // ファイルを開く
  LhFile := FileOpen(LFilePath, fmOpenRead);
  try
    // ファイルからデータを読み込む
    FileRead(LhFile, LValue, SizeOf(Double));

    // 取得結果を表示
    Memo1.Lines.Add(FloatToStr(LValue));
    Memo1.Lines.Add(FormatFloat('#.000E+00', LValue));
  finally
    // ファイルを閉じる
    FileClose(LhFile);
  end;
end;




09_メモリストリームのバイトデータを確認


本ページの最初のサンプルで 4 バイトの実数値である 1.23456E5 をディスクに保存しました.保存したファイルをバイナリエディタで表示したのが下図です.4 バイトのデータが確認できます.



図4
保存したデータをバイナリエディタで確認
  • 保存した数値は 4 バイトの1.23456E5

本ページと最初のサンプルと同じ 4 バイトの実数値 1.23456E5 をメモリストリームに書き込みます.書き込んだメモリストリームのデータを先頭から 1 バイトづつ読み出して表示したのが下図です.図の下のコードがその処理コードです.この図のバイトデータは,ディスク上のバイトデータと全く同じです. メモリストリームのデータはそのままディスクに保存されることが確認できます.



図5
メモリストリームに書き込まれたバイトデータ
  • 書き込んだ数値は 1.23456E5
  • このバイトデータはディスクに保存したバイトデータと全く同じ

リスト10
//=============================================================================
//  メモリストリームのバイトデータを取得して表示
//  Byte 型の変数に 1 バイト単位で読み込んで表示
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStream : TMemoryStream;
  LSingle : Single;
  LByte   : Byte;
  LIndex  : Integer;
begin
  Memo1.Lines.Clear;

  LStream := TMemoryStream.Create;
  try
    // 対象の数値をストリームに書き込む
    LSingle := 1.23456E5;
    LStream.WriteData(LSingle);


    // メモリストリームのバイトデータを表示
    // このバイトデータでディスクに書き込まれる
    LStream.Position := 0;
    for LIndex := 0 to LStream.Size - 1 do begin
      LStream.ReadData(LByte);
      Memo1.Lines.Add('$' + IntToHex(LByte, 2));
    end;
  finally
    FreeAndNil(LStream);
  end;
end;