有经验的高手请进来

fair_play 2006-10-03 12:04:57
请教大家一个问题:我想把一些图片,用FileStream变成二进制后,一个个字节地存入硬盘中,有两个要求1 是能高效地取出每张图片的字节码,然后重新还原出图片,,2 图片所在的介质,是可移植的,就是说,我把“图片库”文件COPY到另一台机子的程序中,程序就能用那个新的图片库了。我目前想到的,能不能把图片存入dll文件中,但dll中还原图片,不知速度怎么样。如果用access文件,一个个字节地取,可能花的时间很多的。SQL Server等就不现实了,因为把图片库移值到另一台机子上很不方便。请教各位,还有什么更好的解决方案呢?

先谢谢了。
...全文
265 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
spirit_sheng 2006-10-12
  • 打赏
  • 举报
回复
如果图片不多, 写文件就OK了; 如果图片很多, 可以考虑使用数据库
以下方案是对于图片不是很多, 一次全部读入的内存的情况下的代码

比较好的方法是你构造自己的列表类, 这样类型安全, 如类声明

的关键部分可以如下:

type
TGraphicItem = class
private
FKey: String;
FGraphic: TGraphic;
public
property Key: String read FKey write FKey;
property Graphic: TGraphic read FGraphic write FGraphic;
procedure ReadFromStream(AStream: TStream);
procedure WriteToStream(AStream: TStream);
end;

TGraphicList = class(TObjectList)
public
property Items[Index: Integer]: TGraphicItem read GetItem write SetItem; default;
procedure LoadFromStream(AStream: TStream);
procedure SaveToStream(AStream: TStream);
procedure LoadFromFile(const AFileName: String);
procedure SaveToFile(const AFileName: String);
end;

// LoadFromFile 实现如下所示
// 注意, 此处使用的是TFileStream, 不要使用TMemoryStream, 因为使用TMemoryStream
// 会浪费更多的内存空间
procedure TGraphicList.LoadFromFile(const AFileName: String);
var
tmpStream: TFileStream;
begin
tmpStream := TFileStream.Create(AFileName, fmOpenRead);
try
LoadFromStream(tmpStream);
finally
tmpStream.Free;
end;
end;

// SaveToFile 的实现方法如下
procedure TGraphicList.SaveToFile(const AFileName: String);
var
tmpStream: TFileStream;
begin
tmpStream := TFileStream.Create(AFileName, fmCreate);
try
SaveToStream(tmpStream);
finally
tmpStream.Free;
end;
end;

// SaveToStream 实现如下
procedure TGraphicList.SaveToStream(AStream: TStream);
var
i: Integer;
tmpCount: Integer;
begin
tmpCount := Count;
AStream.WriteBuffer(tmpCount, sizeof(tmpCount));
for i := 0 to tmpCount - 1 do
Items[i].WriteToStream(AStream);
end;

// LoadFromStream 实现如下
procedure TGraphicList.LoadFromStream(AStream: TStream);
var
tmpCount: Integer;
i: Integer;
tmpItem: TGraphicItem;
begin
Clear; // 注意此处如果OwnsObjects属性为True时, 其自动释放了列表中的所有对象
// 如果OwnsObjects为False时, 则需要则需要在此句之前增加释放列表中的所有对象的代码
AStream.ReadBuffer(tmpCount, sizeof(tmpCount));
for i := tmpCount - 1 downto 0 do
begin
tmpItem := TGraphicItem.Create;
try
tmpItem.ReadFromStream(AStream);
Add(tmpItem);
except
tmpItem.Free;
raise;
end;
end;
end;

对于图像的保存, 可以保存图象的二进制数据, 因为这样其数据量较小
对于TGraphicItem, 必须保存Key, 二进制数据, 图像类型的标识(此处, 我使用类名)
对于字符串的保存, 先保存长度, 再保存内容
对于二进制数据的保存, 也先保存其长度, 再保存内容

字符串的写入和读取函数如下
procedure WriteStringToStream(AStream: TStream; const AValue: String);
var
iLen: Integer;
begin
iLen := length(AValue);
AStream.WriteBuffer(iLen, sizeof(iLen));
if iLen > 0 then
AStream.WriteBuffer(AValue[1], iLen);
end;

function ReadStringFromStream(AStream: TStream): String;
var
iLen: Integer;
begin
AStream.ReadBuffer(iLen, sizeof(iLen));
SetLength(Result, iLen);
if iLen > 0 then
AStream.ReadBuffer(Result[1], iLen);
end;

二进制数据的写入的读取函数如下
procedure WriteStreamToStream(AStream: TStream; sub: TMemoryStream);
var
iLen: Integer;
begin
iLen := sub.Size;
AStream.WriteBuffer(iLen, sizeof(iLen));
if iLen > 0 then
AStream.WriteBuffer(sub.Memory^, iLen);
end;

procedure ReadStreamFromStream(AStream: TStream; sub: TMemoryStream);
var
iLen: Integer;
begin
AStream.ReadBuffer(iLen, sizeof(iLen));
sub.SetSize(iLen);
if iLen > 0 then
AStream.ReadBuffer(sub.Memory^, iLen);
end;

对于各项的读取和写入, 实现如下
procedure TGraphicItem.WriteToStream(AStream: TStream);
var
sub: TMemoryStream;
begin
WriteStringToStream(AStream, FKey);
WriteStringToStream(AStream, FGraphic.ClassName);
sub := TMemoryStream.Create;
try
FGraphic.SaveToStream(sub);
WriteStreamToStream(AStream, sub);
finally
sub.free;
end;
end;

procedure TGraphicItem.WriteToStream(AStream: TStream);
var
sub: TMemoryStream;
tmpClassName: String;
tmpClass: TGraphicClass;
begin
FKey := ReadStringFromStream(AStream);
tmpClassName := ReadStringFromStream(AStream);
tmpClass := TGraphicClass(GetClass(tmpClassName));
if tmpClass = nil then
raise Exception.Create('graphic type not support'); // 此处最好用你自己声明的异常

if Assigned(FGraphic) then
FreeAndNil(FGraphic);

FGraphic := tmpClass.Create;
sub := TMemoryStream.Create;
try
ReadStreamFromStream(AStream, sub);
sub.Position := 0;
FGraphic.LoadFromStream(sub);
finally
sub.Free;
end;
end;

至此OK, 你所需要的关键部分都已经给出来了

fair_play 2006-10-11
  • 打赏
  • 举报
回复
up
hnAngle 2006-10-05
  • 打赏
  • 举报
回复
存一个图片不是很简单的事情啊,图片名称可以存在数据库里,名称可采用十六进制度存取以保证图片的唯一性,在工程目录中建立一个img文件夹,专门存文件,我想这样比较方便。数据库只存文件属性。
spirit_sheng 2006-10-04
  • 打赏
  • 举报
回复
不是用分隔符
考虑以下方法, 比如, 对于每个图片, 先存长度(即在文件中的大小), 再存数据
在恢复时, 先读取长度, 然后读取指定长度的数据就可以了
fair_play 2006-10-04
  • 打赏
  • 举报
回复
up
fair_play 2006-10-03
  • 打赏
  • 举报
回复
直接用文件的话,那么得用个分隔符区别图片1跟图片2的边界,例如如果分隔标记是 1234,那么"1234abcd1234"中, 我用哪个函数得到abcd呢? 这样的话,存取效率不高吧?
postren 2006-10-03
  • 打赏
  • 举报
回复
直接用文件就ok了,没那么麻烦

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧