全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2875
推到 Plurk!
推到 Facebook!

請問如何使用MemorySteam將內含動態陣列的結構存檔再讀出?

答題得分者是:jow
dky
一般會員


發表:12
回覆:30
積分:13
註冊:2004-06-24

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-07-01 16:43:26 IP:61.218.xxx.xxx 訂閱
程式碼如下
遇到的問題是當讀出時, 動態陣列大小為0
如果將test2.xAry 一樣設定為100, 讀出後,一樣歸0
[code delphi]
type
_test = record
a, b, c, d :Integer;
xAry :array of Boolean;
end;

var
test1, test2 :_test

procedure FormCreate(Sender: TObject);

begin
SetLength(test1.xAry, 100);
end;

procedure Button1Click(Sender: TObject);
var
pmem :TMemoryStream;
begin
pmem := TMemoryStream.Create;

pmem.Size := SizeOf(test1);

pmem.Position := 0;
pmem.Write(test1, pmem.Size);

pmem.SaveToFile('C:\1.dat');
FreeAndNil(pmem);

end;

procedure Button1Click(Sender: TObject);
var
pmem :TMemoryStream;
begin
pmem := TMemoryStream.Create;

pmem.LoadFromFile('C:\1.dat');
pmem.Position := 0;
pmem.Read(test2, pmem.Size);
FreeAndNil(pMem);
end;
[/code]
編輯記錄
dky 重新編輯於 2008-07-01 16:45:20, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-07-01 21:15:50 IP:123.193.xxx.xxx 未訂閱
隨手寫些測試碼,提供你參考...

[code delphi]
unit fMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
p_test = ^_test;
_test = record
a, b, c, d :Integer;
e: Char;
xAry :array of Boolean;
end;

p_test_packed = ^_test_packed;
_test_packed = packed record
a, b, c, d :Integer;
e: Char;
xAry :array of Boolean;
end;

TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
ListBox1: TListBox;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
private
public
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
A: _test;
begin
//比較 record 與 packed record 的差異
ShowMessage('SizeOf(_test)=' IntToStr(SizeOf(_test)));
ShowMessage('SizeOf(_test_packed)=' IntToStr(SizeOf(_test_packed)));

ShowMessage('SizeOf(A.xAry)=' IntToStr(SizeOf(A.xAry)));
SetLength(A.xAry, 100);
try
ShowMessage('LengthOf(A.xAry)=' IntToStr(Length(A.xAry)));
ShowMessage('SizeOf(A.xAry[])=' IntToStr(SizeOf(Boolean)*Length(A.xAry)));
finally
A.xAry := nil;
end;

end;

procedure TForm1.Button2Click(Sender: TObject);
var
I: Integer;
A, B: _test;
L: TStringList;
begin
//alignment: use for-loop
SetLength(A.xAry, 100);
try
for I := 0 to Length(A.xAry)-1 do
A.xAry[I] := Boolean(I mod 2);

SetLength(B.xAry, 100);
try
for I := 0 to Length(A.xAry)-1 do
B.xAry[I] := A.xAry[I];

//Show Result
L := TStringList.Create;
try
for I := 0 to Length(B.xAry)-1 do
if B.xAry[I] then L.Add(Format('%d: TRUE', [I]))
else L.Add(Format('%d: FALSE', [I]));
ListBox1.Items.Text := L.Text;
finally
FreeAndNil(L);
end;

finally
B.xAry := nil;
end;
finally
A.xAry := nil;
end;

end;

procedure TForm1.Button3Click(Sender: TObject);
var
I, Size: Integer;
A, B: _test;
L: TStringList;
begin
//alignment: memory move
SetLength(A.xAry, 100);
try
for I := 0 to Length(A.xAry)-1 do
A.xAry[I] := Boolean(I mod 2);

Size := SizeOf(Boolean) * Length(A.xAry);

SetLength(B.xAry, 100);
try
//alignment: memory move
Move(Pointer(A.xAry)^, Pointer(B.xAry)^, Size);

//Show Result
L := TStringList.Create;
try
for I := 0 to Length(B.xAry)-1 do
if B.xAry[I] then L.Add(Format('%d: TRUE', [I]))
else L.Add(Format('%d: FALSE', [I]));
ListBox1.Items.Text := L.Text;
finally
FreeAndNil(L);
end;

finally
B.xAry := nil;
end;
finally
A.xAry := nil;
end;

end;

procedure TForm1.Button4Click(Sender: TObject);
var
pBool: ^Boolean;

I, Size, Len, Len2: Integer;
A: _test;
L: TStringList;
M: TMemoryStream;
begin
//write to file
M := TMemoryStream.Create;
try
SetLength(A.xAry, 100);
try
Size := SizeOf(Boolean) * Length(A.xAry);
for I := 0 to Length(A.xAry)-1 do
A.xAry[I] := Boolean(I mod 2);

M.Write(Pointer(A.xAry)^, Size);
M.SaveToFile('1.DAT');
finally
A.xAry := nil;
end;
finally
FreeAndNil(M);
end;

//Show Result use TMemoryStream
if FileExists('1.DAT') then
begin
M := TMemoryStream.Create;
try
M.LoadFromFile('1.DAT');
pBool := M.Memory;
L := TStringList.Create;
try
Len := M.Size div SizeOf(Boolean);
Len2 := Len;
while (pBool <> nil) and (Len > 0) do
begin
if pBool^ then L.Add(Format('%d: TRUE', [Len2-Len]))
else L.Add(Format('%d: FALSE', [Len2-Len]));
Inc(pBool);
Dec(Len);
end;
ListBox1.Items.Text := L.Text;
finally
FreeAndNil(L);
end;
finally
FreeAndNil(M);
end;
end;

end;

procedure TForm1.Button5Click(Sender: TObject);
var
I, Size: Integer;
A, B: _test;
L: TStringList;
M: TMemoryStream;
begin
//write to file
M := TMemoryStream.Create;
try
SetLength(A.xAry, 100);
try
Size := SizeOf(Boolean) * Length(A.xAry);
for I := 0 to Length(A.xAry)-1 do
A.xAry[I] := Boolean(I mod 2);
M.Write(Pointer(A.xAry)^, Size);
M.SaveToFile('1.DAT');
finally
A.xAry := nil;
end;
finally
FreeAndNil(M);
end;

if FileExists('1.DAT') then
begin
SetLength(B.xAry, 100);
try
Size := SizeOf(Boolean) * Length(B.xAry);
M := TMemoryStream.Create;
try
M.LoadFromFile('1.DAT');
M.Read(Pointer(B.xAry)^, Size);
finally
FreeAndNil(M);
end;

//Show Result
L := TStringList.Create;
try
for I := 0 to Length(B.xAry)-1 do
if B.xAry[I] then L.Add(Format('%d: TRUE', [I]))
else L.Add(Format('%d: FALSE', [I]));
ListBox1.Items.Text := L.Text;
finally
FreeAndNil(L);
end;


finally
B.xAry := nil;
end;
end;


end;

end.
[/code]
dky
一般會員


發表:12
回覆:30
積分:13
註冊:2004-06-24

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-07-02 11:19:01 IP:61.218.xxx.xxx 訂閱
感謝您的回覆

我找到問題點了, 動態Array的部份,要另外write到MemoryStream裡,不過當我把array of Boolean 改成 array Of String 時, 可以正確的把資料抓出,但是在把array 內容顯示出來時,都會出現錯誤"Invalid pointer operation"

在delphi 裡,是可以看到資料有進入到array裡, 程式碼如下


[code delphi]

p_xt = ^_xt;
_xt = record
a, b :Integer;
xAry :array of String;
c :String;
end;

procedure TfMain.Button6Click(Sender: TObject);
var
i, Size: Integer;
at, bt: _xt;
pMem: TMemoryStream;
begin
Listbox2.Clear;
Listbox3.Clear;

Edit4.Text := '';
Edit5.Text := '';
Edit6.Text := '';

at.a := StrToInt(Edit1.Text);
at.b := StrToInt(Edit2.Text);
at.c := Edit3.Text;

pMem := TMemoryStream.Create;
try
SetLength(at.xAry, 100);
try
for i := 0 to Length(at.xAry) -1 do
begin
at.xAry[i] := IntToStr(GetTickCount) '@' IntToStr(i);
Listbox2.AddItem(at.xAry[i], nil);
end;
Size := SizeOf(String) *Length(at.xAry);

pMem.Write(at, SizeOf(at));
pMem.Write(Pointer(at.xAry)^, Size);

pMem.SaveToFile('C:\1.DAT');
finally
at.xAry := nil;
end;
finally
FreeAndNil(pMem);
end;

if FileExists('C:\1.DAT') then
begin
try
pMem := TMemoryStream.Create;
try
pMem.LoadFromFile('C:\1.DAT');
pMem.Position := 0;
pMem.Read(bt, SizeOf(bt));
Size := SizeOf(String) *Length(bt.xAry);
pMem.Read(Pointer(bt.xAry)^, Size);

for i := 0 to Length(bt.xAry) -1 do
begin
Listbox3.AddItem(bt.xAry[i], nil);
end;

Edit4.Text := IntToStr(bt.a);
Edit5.Text := IntToStr(bt.b);
Edit6.Text := bt.c;

finally
FreeAndNil(pMem);
end;

finally
bt.xAry := nil;
end;
end;
end;

[/code]

感謝 m(_ _)m
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-07-02 12:07:52 IP:203.70.xxx.xxx 未訂閱

Size := SizeOf(String) *Length(at.
xAry);

SizeOf(string) = ??
Length(at.xAry[i]) = ??

除非將每個at.xAry[]字串長度加以記錄,並循序寫入/讀出,
否則應該先估計可能用到字串資料的最大長度
並使用short string來操作你的 record.


個人看法,僅供參考...



編輯記錄
jow 重新編輯於 2008-07-02 12:10:07, 註解 無‧
dky
一般會員


發表:12
回覆:30
積分:13
註冊:2004-06-24

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-07-02 12:43:43 IP:61.218.xxx.xxx 訂閱
搞定了, 因為自己對資料型態不熟,改成shortstring後就正常了,附上正確的(?)程式碼給需要的版友


[code delphi]

p_xt = ^_xt;
_xt = record
a, b :Integer;
xAry :array of ShortString;
c :ShortString;
end;

procedure TfMain.Button6Click(Sender: TObject);
var
i, Size, tmp: Word;
at, bt: _xt;
pMem: TMemoryStream;
begin
Listbox2.Clear;
Listbox3.Clear;

Edit4.Text := '';
Edit5.Text := '';
Edit6.Text := '';

at.a := StrToInt(Edit1.Text);
at.b := StrToInt(Edit2.Text);
at.c := Edit3.Text;

pMem := TMemoryStream.Create;
try
SetLength(at.xAry, 100);
try
for i := 0 to Length(at.xAry) -1 do
begin
at.xAry[i] := IntToStr(GetTickCount) '@' IntToStr(i);
Listbox2.AddItem(at.xAry[i], nil);
end;
Size := SizeOf(ShortString) *Length(at.xAry);
tmp := Length(at.xAry);
pMem.Write(at, SizeOf(at));
pMem.Write(tmp, SizeOf(Word));
pMem.Write(Pointer(at.xAry)^, Size);

pMem.SaveToFile('C:\1.DAT');
finally
at.xAry := nil;
end;
finally
FreeAndNil(pMem);
end;

if FileExists('C:\1.DAT') then
begin
try
pMem := TMemoryStream.Create;
tmp := 0;
try
pMem.LoadFromFile('C:\1.DAT');
pMem.Position := 0;
pMem.Read(bt, SizeOf(bt));
pMem.Read(tmp, SizeOf(Word));
Size := SizeOf(ShortString) *tmp;
SetLength(bt.xAry, tmp);
pMem.Read(Pointer(bt.xAry)^, Size);

for i := 0 to Length(bt.xAry) -1 do
begin
Listbox3.AddItem(bt.xAry[i], nil);
end;

Edit4.Text := IntToStr(bt.a);
Edit5.Text := IntToStr(bt.b);
Edit6.Text := bt.c;

finally
FreeAndNil(pMem);
end;

finally
bt.xAry := nil;
end;
end;
end;
[/code]
系統時間:2017-10-20 18:41:10
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!