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

解决方案 »

  1.   

    直接用文件的话,那么得用个分隔符区别图片1跟图片2的边界,例如如果分隔标记是 1234,那么"1234abcd1234"中, 我用哪个函数得到abcd呢? 这样的话,存取效率不高吧?
      

  2.   

    存一个图片不是很简单的事情啊,图片名称可以存在数据库里,名称可采用十六进制度存取以保证图片的唯一性,在工程目录中建立一个img文件夹,专门存文件,我想这样比较方便。数据库只存文件属性。
      

  3.   

    如果图片不多, 写文件就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, 你所需要的关键部分都已经给出来了