TStringList加object到13000多时就不加不了了,请高手帮忙,如何加到几万?(100分)

M

mytree

Unregistered / Unconfirmed
GUEST, unregistred user!
TStringList加object到13000多时就不加不了了,请高手帮忙,如何加到几万?
 
你可以查看一下TstringList的源码,分析一下吧
 
应该是没办法的,除非你自己写基类,TStringList的父类是TList,你看看它的员码就知道了
数据个数是有限制的
 
2G空间,你一个OBJECT多大啊?
 
TstringList加入的只是对象指针而已,即四个字节。13000*4才多少呀,
看我这段代码,运行了一下,一点问题都没有,所以在检查检查你的程序吧。
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
t: TStringList;
begin
t:= TStringList.Create;
for i:= 1 to 20000 do begin
t.AddObject(IntToStr(i), TObject(i));
Caption := IntToStr(i);
Application.ProcessMessages;
end;
t.Free;
end;
 
sweetgun:非常谢谢,我忘记告诉你了,我用的是Delphi1,你的代码在delphi5中没问题,
可在Delphi1中到了16368就出错了:“List index out of Bounds”.
谢谢大家:我再去查查源码。
 
请教outer_star: 2G空间是什么意思啊?

 
to sweetgun:
我觉得STRINGLIST的count为整型的呀,他的max 应该是65535 怎么会突破这个极限了呢?
 
chenliang_fly:谢谢,我查了Tlist的源码(delphi1.0),是有64k的限制,但是可以改吗?
听别人说是cpu段的限制。
 
你自己使用内存流不行吗?
 
Delphi1 ? 利害利害
 
吓我一跳,我经常这样使用TObject,没考虑过会有这个限制。如果真是这样,
我的程序岂不是有“隐患”???
 
to mytree:
Delphi 1.0是16位的,所以它可寻址的数组大小上限为2^16-1=65535 Bytes,而你的数组元素大小为
4Bytes,所以元素数量上限为 16K-1。你可以用双重指针列表实现大内存使用(数组中的元素是指向数据
Buffer的指针,在每个Buffer中存放64K数据,读取数据时要判断要取的数据在哪个Buffer中)。
不知mikedeakins兄的内存流在Delphi1.0中能不能突破64K。
 
creation-zy:能否在说的详细一些?Thanks a lot!!!
 
const
ObjNumInBuf=8192
//每个缓冲区可以容纳的TObject数量
BufferSize=ObjNumInBuf*SizeOf(TObject);
type
TMyStringList=class
private
FArraySize,FCapacity:Integer;
FCount:Integer;
FBufPointerArray:array of Pointer
//缓冲区指针数组
public
property ArraySize:Integer read FArraySize;
property Count:Integer read FCount;
property Capacity:Integer read FCapacity;
function AddObject(A:TObject):Integer;
function SetObject(Index:Integer;A:TObject):Boolean;
function GetObject(Index:Integer):TObject;
//呵呵,还没有 Insert 和 Delete 方法——在数组中做很麻烦——要挨个Move
constructor Create(ASize:Integer);
destructor Destroy
override;
end;

implementation

{ TMyStringList }

function TMyStringList.AddObject(A: TObject):Integer;
begin
Result:=-1;
if FCount>=FCapacity then
exit;
Result:=FCount;
PInteger(Integer(FBufPointerArray[FCount div ObjNumInBuf])
+(FCount mod ObjNumInBuf)*SizeOf(TObject))^:=Integer(A);
Inc(FCount);
end;

constructor TMyStringList.Create(ASize:Integer);
var
i:Integer;
begin
if ASize>0 then
FArraySize:=ASize
else
FArraySize:=1;
FCapacity:=FArraySize*ObjNumInBuf;
GetMem(FBufPointerArray,SizeOf(Pointer)*FArraySize)
//指针数组
FillChar(FBufPointerArray[0],SizeOf(Pointer)*FArraySize,0);
try
for i:=0 to FArraySize-1 do
GetMem(FBufPointerArray,BufferSize)
//给各个缓冲区分配空间
except
Abort
//如果出错,则产生异常,自动Free
end;
end;

destructor TMyStringList.Destroy;
var
i:Integer;
begin
for i:=0 to FArraySize-1 do
if FBufPointerArray<>nil then
FreeMem(FBufPointerArray);
FreeMem(FBufPointerArray);
inherited;
end;

function TMyStringList.GetObject(Index: Integer): TObject;
begin
Result:=nil;
if (Index<0) or (Index>FCount-1) then
exit;
Result:=TObject(PInteger(Integer(FBufPointerArray[Index div ObjNumInBuf])
+(Index mod ObjNumInBuf)*SizeOf(TObject))^);
end;

function TMyStringList.SetObject(Index: Integer
A: TObject): Boolean;
begin
Result:=false;
if (Index<0) or (Index>FCount-1) then
exit;
Result:=true;
PInteger(Integer(FBufPointerArray[Index div ObjNumInBuf])
+(Index mod ObjNumInBuf)*SizeOf(TObject))^:=Integer(A);
end;

使用例子:
procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
begin
with TMyStringList.Create(4) do //可容纳4*8192个TObject
begin
try
for i:=1 to 3*8192 do
begin
Caption:=IntToStr(Integer(GetObject(AddObject(TObject(i)))));
Application.ProcessMessages;
end;
finally
Free;
end;
end;
end;
 
creation-zy:鞠躬!
可是在delphi1中没有动态数组,所以
FBufPointerArray:array of Pointer
//缓冲区指针数组
不能编译。
 
晕!

FBufPointerArray:pointer
//缓冲区指针数组

function TMyStringList.AddObject(A: TObject):Integer;
...
PInteger(PInteger(Integer(FBufPointerArray)+4*(FCount div ObjNumInBuf))^
+(FCount mod ObjNumInBuf)*SizeOf(TObject))^:=Integer(A);
...

constructor TMyStringList.Create(ASize:Integer);
...
FillChar(FBufPointerArray^,SizeOf(Pointer)*FArraySize,0);
try
for i:=0 to FArraySize-1 do
begin
GetMem(P,BufferSize)
//给各个缓冲区分配空间
PInteger(Integer(FBufPointerArray)+i*4)^:=Integer(P);
end;
except
...

destructor TMyStringList.Destroy;
...
for ...
Integer(P):=PInteger(Integer(FBufPointerArray)+4*i)^;
if P<>nil then
FreeMem(P);
...

function TMyStringList.GetObject(Index: Integer): TObject;
...
Result:=TObject(PInteger(PInteger(Integer(FBufPointerArray)+4*(Index div ObjNumInBuf))^
+(Index mod ObjNumInBuf)*SizeOf(TObject))^);

function TMyStringList.SetObject(Index: Integer
A: TObject): Boolean;
...
PInteger(PInteger(Integer(FBufPointerArray)+4*(Index div ObjNumInBuf))^
+(Index mod ObjNumInBuf)*SizeOf(TObject))^:=Integer(A);

OK?
 
老大,有“情况”。
运行到constructor TMyStringList.Create(ASize:Integer);中的
PInteger(Integer(FBufPointerArray)+i*4)^:=Integer(P);
就出错了:"General protection fault in module project1.exe at 0001:0DC4"
 
to mytree:
很抱歉,我无能为力。
找到一篇文章: http://www.mindspring.com/~cityzoo/tips/hugearr.txt
它是用TMemoryStream实现的。看来mikedeakins兄的方法是可行的。


附 http://www.mindspring.com/~cityzoo/tips/hugearr.txt 的主要内容:

I have needed to allocate and get pointers to memory greater than 64k. To
allocate the memory you can call GlobalAlloc/GlobalLock to get the memory
from the system.

An easier way may be to use TMemoryStream. With this class you can allocate
any amount of memory and Read/Write from it easily. The problem is getting
a pointer to any point in the file. Peter Below sent me some email on
getting a pointer:

(please note that I have changed his code to make it a function and I need
to do some more testing to verify all this)

function GetPtr(stream: TMemoryStream
offset: Longint): Pointer;
begin
Result := Ptr(PtrRec(stream.Memory).seg+SelectorInc*HiWord(offset),LoWord(offset));
end;
 
佩服,佩服!你居然还在用Delphi1。以前有一个问TStringList最大支持多少行的问题,你
去看看?说不定那儿有答案,1.0与5.0毕竟有许多不同。
 

Similar threads

回复
0
查看
854
不得闲
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部