お知らせ

電子会議

ライブラリ

FDelphi サイト全文検索

Delphi FAQ一覧

サンプル蔵



FDelphi FAQ
15番会議室「FAQ編纂委員会」に寄せられた「よくある質問の答え」

[Q]
Sizeof はちょっとわかりにくい関数と思いますが、特に TStream や TFileStream で使うとき、どういう使い方ができますか?

[A]
(1) Sizeofが、宣言された変数の割り当てバイト数を示すことは、

const
  acStr: array [0..20] of char='これはchar配列(18)';
  aStr: String[25]='これはShortString(21)';
var
  aStr1: ShortString;

という場合のような、char配列や、ShortStringの場合には明らかで、Stream
への書き込みを、例えば、char配列で、

  M:=TMemoryStream.Create;
  M.Write(acStr,Sizeof(acStr));   (*1)

と行なって、先頭から1バイトずつ読むことができます。

(2) ところが、ShortStringの場合、

  M.Write(aStr,Sizeof(aStr));     (*2)

とすると、文字数バイトである、aStr[0]から書き込まれますので、読むとき
に注意が必要です。

(3) さらに、(*1)、(*2)は、実は、無駄、というより、読んではいけない部
分を書き込んでいます。この場合、使っていない末尾の何文字かを余分に書
き込んでしまっているからです。従って、(*1)の場合はStrLenを使った方が
よいと思います。(*2)の場合、aStr1: ShortStringを使って

  M.Write(aStr,Length(aStr)+1);    (*2')
    {先頭の文字数バイトを含んで書き込む}
  M.Seek(0,0);
  M.Read(aStr1,Length(aStr)+1);    (*2'')

とすれば、Write(aStr1); で問題なくコンソールに表示されます(下例のよ
うに{$APPTYPE CONSOLE}でコンパイルした場合)。

(4) PCharではどうでしょう。これは、「逆参照」読み書きが必要です。そし
て、この場合、Sizeofの使いようがありません。Sizeof(pcStr)=4、Sizeof(
pcStr^)=1 いずれでも、このバイト数しか書き込まれません。従って、

  pcStr: PChar;

  M.Write(pcStr^,StrLen(pcStr){+1}); {+1で、末端ヌルを含む}

とすべきです。

(5) AnsiString の場合は、

  xStr,yStr: AnsiString;

  M.Write(xStr,Sizeof(xStr));   {*5}
  M.Seek(0,0);
  M.Read(yStr,Sizeof(xStr));

でも、
  M.Write(xStr,Length(xStr));   {**5}
  M.Seek(0,0);
  M.Read(yStr,Length(xStr));

でも、yStrに期待通りの文字列が読まれます。書き込まれたM.Sizeを見ると、
{*5}は4バイト、{**5}は Length(xStr)バイトなんですが。
 

[例]
{------- AStream.dpr: ここから ----------------------------}
{以下の例は、説明の都合上、コードが必ずしも最適化されていません。}
program AStream;

{$APPTYPE CONSOLE}
       {これ、気に入りました。テストランにはもってこいですね}
uses
  Classes,SysUtils;

var
  M: TMemoryStream;
  ch: char;
  pcStr: PChar;
  Str,xStr: String;
  i,j,Len: integer;

{(1a) char配列−SizeOf}
const
  acStr: array [0..20] of char='これはchar配列(18)';
  aStr: String[25]='これはShortString(21)';

{acStrを使って、}

{後で呼び出し。MemoryStreamから取り出して表示}
{=========================================================}
procedure ExtractFromMemoryStream;
begin
  ch:=#0;
  M.Write(ch,1);  {読み出す目印}

  Len:=0; Str:=''; ch:=' ';
  M.Seek(0,0);
  while ch<>#0 do begin
    M.Read(ch,1);
    inc(Len);
    Str:=Str+ch;
  end;
  dec(Len);
  SetLength(Str,Len);
end; {ExtractFromMemoryStream}

{!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
begin
  M:=TMemoryStream.Create;
  Writeln('Sizeof(acStr)=',Sizeof(acStr)); {21}
    {宣言で割り当てた大きさということ}
  M.Write(acStr,Sizeof(acStr));

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {18}
  Writeln('M.Size=',M.Size);               {22}
  Write(Str);      {表示:これはchar配列(18)_}
                   {?は1バイト、_はカーソル}
  Readln;
  M.Free;

{(1b) char配列−StrLen}

  M:=TMemoryStream.Create;
  Writeln('StrLen(acStr)=',StrLen(acStr)); {18}
  M.Write(acStr,StrLen(acStr));

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {18}
  Writeln('M.Size=',M.Size);               {19}
  Write(Str);      {表示:これはchar配列(18)_}
  Readln;
  M.Free;

{(2a) ShortString−SizeOf}
{constのaStrを使って、}

  M:=TMemoryStream.Create;
  Writeln('Sizeof(aStr)=',Sizeof(aStr));   {26}
    {これも宣言したサイズ}
  M.Write(aStr,Sizeof(aStr));

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {22}
  Writeln('M.Size=',M.Size);               {27}
  Write(Str);      {表示:?これはShortString(21)_}
  Readln;
  M.Free;

{(2b) ShortString−Length}
  M:=TMemoryStream.Create;
  Writeln('Length(aStr)=',Length(aStr));   {21}
  M.Write(aStr,Length(aStr));

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {21}
  Writeln('M.Size=',M.Size);               {22}
  Write(Str);      {表示:?これはShortString(21_}
  Readln;
  M.Free;

{(3a) PChar−Sizeof}
  pcStr:=StrAlloc(20);
  StrCopy(pcStr,'これはPChar(15)');

  M:=TMemoryStream.Create;
  Writeln('Sizeof(pcStr)=',Sizeof(pcStr)); {4}
    {PCharは4バイト}
  M.Write(pcStr^,Sizeof(pcStr));
    {PChar変数をStreamで使うときは「逆参照」する}
    {Sizeof(pcStr)では、4バイトしか書き込まれない}
    {Sizeof(pcStr^)は1バイト}

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {4}
  Writeln('M.Size=',M.Size);               {5}
  Write(Str);      {表示:これ_}
  Readln;
  M.Free;
  StrDispose(pcStr);

{(3b) PChar−StrLen}
  pcStr:=StrAlloc(20);
  StrCopy(pcStr,'これはPChar(15)');

  M:=TMemoryStream.Create;
  Writeln('StrLen(pcStr)=',StrLen(pcStr)); {15}
  M.Write(pcStr^,StrLen(pcStr));
    {PChar変数をStreamで使うときは「逆参照」する}

  {実際読んでみて表示}
  ExtractFromMemoryStream;
  Writeln('Len=',Len);                     {15}
  Writeln('M.Size=',M.Size);               {16}
  Write(Str);      {表示:これはPChar(15)_}
  Readln;
  M.Free;
  StrDispose(pcStr);

{(4a) AnsiString−Sizeof}
  {xStrに256文字以上、ここでは、640文字を確保}
  Str:='これはAnsiString:abcdefghijklmnopqrstuvwxyz';
  xStr:=''; Len:=0;
  j:=14;
  for i:=1 to j do begin
    xStr:=xStr+IntToStr(i)+Str;
    inc(Len,Length(IntToStr(i)));
  end;
  xStr:=xStr+'('+IntToStr(j*Length(Str)+Len+5)+')';
    {総文字数を()に入れて末尾に表示させようとしている}

  M:=TMemoryStream.Create;
  Writeln('Sizeof(xStr)=',Sizeof(xStr));   {4}
  M.Write(xStr,Sizeof(xStr));

  {実際読んでみて表示}
  {ExtractFromMemoryStream;} {不可}
  M.Seek(0,0);
  M.Read(xStr,Sizeof(xStr));
  Str:=xStr;
  Len:=Length(Str);

  Writeln('Len=',Len);                     {640}
  Writeln('M.Size=',M.Size);               {641}
  Write(Str);      {表示:1これは..(略)..z(640)_}
  Readln;
  M.Free;

{(4b) AnsiString−Length}
  M:=TMemoryStream.Create;
  Writeln('Length(xStr)=',Length(xStr));   {640}
  M.Write(xStr,Length(xStr));

  {実際読んでみて表示}
  {ExtractFromMemoryStream;} {不可}
  M.Seek(0,0);
  M.Read(xStr,Length(xStr));
  Str:=xStr;
  Len:=Length(Str);

  Writeln('Len=',Len);                     {640}
  Writeln('M.Size=',M.Size);               {641}
  Write(Str);      {表示:1これは..(略)..z(640)_}
  Readln;
  M.Free;
end.
{------- ここまで ----------------------------------------}


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum FDELPHIに寄せられる質問の中から、よくある質問への回答を FDELPHIのメンバーがまとめたものです。 したがって、これらの回答はボーランド株式会社がサポートする公式のものではなく、掲示されている内容についての問い合わせは受けられない場合があります。

Copyright 1996-1998 Delphi Users' ForumFAQ編纂委員会