delphi 初识内存流: 从设置用户头像到从数据库存取图片到的过程

发布时间 2023-05-09 18:25:13作者: 一曲轻扬

所谓"流", 就是一段数据或是一块内存;
在进行流操作时, 我们不必关心流中的数据到底是什么; 只需要知道流的大小和当前的指针位置. 所以流只有两个属性: 
Size、Position.
对流的操作, 不过就是读取和写入. 所以流最主要的方法就是 Read 和 Write.
在很多控件的使用中, 读取主要用 LoadFromStream; 写入主要用 SaveToStream. 

TStream 是一个抽象的基类, 不能直接生成对象. 在具体的应用中, 主要使用它的子孙类:
TFileStream: 文件流
TStringStream: 字符串流
TMemoryStream: 内存流
TResourceStream: 资源文件流
THandleStream: 是 TFileStream 的父类、TStream 的子类
TCustomMemoryStream: 是 TMemoryStream 和 TResourceStream 的父类、TStream 的子类
与流相关的常用类还有: TReader、TWriter、TCompressionStream、TDecompressionStream

 

Delphi 中的内存流(TMemoryStream)是一种特殊的流对象,它继承自 TCustomMemoryStream 类,可以将数据存储在内存中,而不是存储在文件或其他外部介质中。 内存流有以下特点:

  1. 可以通过向内存流写入数据来将数据保存到内存中;
  2. 可以从内存流中读取数据,并在需要时将其转换为其他数据类型;
  3. 内存流可以任意调整其大小,以容纳更多或更少的数据;
  4. 内存流可以在不使用额外存储空间的情况下随时进行扩展或缩小;
  5. 内存流可以用于在内存中缓存数据,以提高程序的性能。 使用内存流可以方便地将数据存储在内存中

TMemoryStream 的一些常用方法和属性如下:

  1. LoadFromFile 和 SaveToFile:从文件中加载数据或将数据保存到文件中。(常用)
  2. Read 和 Write:从流中读取数据或将数据写入流中。这些方法的参数是一个指针和一个长度。在使用这些方法之前,需要先使用 SetSize 方法设置流的大小。
  3. Seek:定位流中的位置。可以使用这个方法在流中移动指针,以便读取和写入数据。
  4. Size:获取流的大小。
  5. Capacity:获取或设置流的容量。容量是指流的最大大小,如果需要向流中写入更多的数据,可以使用 SetCapacity 方法来增加容量。
  6. Memory 和 MemorySize:获取流中数据的指针和数据的长度。

 一个简单示例:

var
  Stream: TMemoryStream;
  Data: array[0..255] of Byte;
begin
  Stream := TMemoryStream.Create;
  try
    // 写入数据
    Stream.Write(Data, SizeOf(Data));
    // 移动指针到开头
    Stream.Seek(0, soBeginning);
    // 读取数据
    Stream.Read(Data, SizeOf(Data));
  finally
    Stream.Free;
  end;
end;

需要注意的是,在使用 TMemoryStream 时,需要注意内存的使用情况,使用结束后要手动 free,避免出现内存泄漏等问题。同时,在写入和读取数据时,也要注意数据类型的匹配,避免出现类型转换错误等问题。

系统学习'流' ,请转到万一老师的博客:https://www.cnblogs.com/del/archive/2008/01/01/1022124.html

任务需求:

1.从数据库取回图像,并设置到控件上

2.上传图像到数据库

3.用户选择本地图片,进行头像预览(这个反而不是很重要)

数据库设计:

 

界面设计图:

 

 

 OpenPictureDialog1控件filter设置为: 全部 (*.png;*.jpg;*.jpeg)|*.png;*.jpg;*.jpeg  只允许用户选择两种图片类型. 其它控件设置就不展开了.

效果展示:

以下是主要代码

 private
    FMemoryStream: TMemoryStream;

 

第一个问题.把图像从数据库上取回到图片控件

procedure TForm1.GetImgClick(Sender: TObject);
begin
  with FDQUsers do
  begin
    Close;
    sql.Text := 'SELECT * FROM users where userid= 1';
    open;
    //ShowMessage(BoolToStr(IsEmpty, true));  //判断查询是否返回空集
    if not TBlobField(FieldByName('HeadImg')).IsNull then   //判断用户是否有设置头像
    begin
      FMemoryStream.Clear;  //先清除内存流空间
      TBlobField(FieldByName('HeadImg')).SaveToStream(FMemoryStream);    //把图像从数据库载入内存流
      FMemoryStream.Position := 0; //读取位置设置为0
      HeadImg.Picture.LoadFromStream(FMemoryStream);//显示到图片控件上
      labInfo.Caption := '头像已取回';
    end
    else
      labInfo.Caption := '无图片';
  end;
end;

第二个问题,把图像上传到数据库

procedure TForm1.UpdateImgClick(Sender: TObject);   //上传头像到数据库
begin
  with FDQUsers do
  begin
    close;
    sql.Text := 'Update users set headimg=:headimg where userid=1'; //:headimg是占位符
    ParamByName('headimg').LoadFromStream(FMemoryStream, ftBlob); // 填充:headimg占位符,从内存流中上传
    ExecSQL;
    labInfo.Caption := '头像已更新到数据库'
  end;
end;

第三个问题:

procedure TForm1.SetImgClick(Sender: TObject);   //设置头像
var
  FileName: string;
begin
  if OpenPictureDialog1.Execute then
  begin
    FileName := OpenPictureDialog1.FileName;
    HeadImg.Picture.LoadFromFile(FileName);

    FMemoryStream.Clear;
    FMemoryStream.LoadFromFile(FileName); //把本地图片存到内存流中
    FMemoryStream.Position := 0;
    labInfo.Caption := '头像已从本地设置'
  end;
end;

 

 

 

 

以下是全部代码:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf,
  FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
  FireDAC.Phys, FireDAC.Phys.SQLite, FireDAC.Phys.SQLiteDef,
  FireDAC.Stan.ExprFuncs, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS,
  FireDAC.DApt.Intf, FireDAC.DApt, FireDAC.Phys.SQLiteWrapper.Stat, Vcl.ExtDlgs,
  Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client, scGPFontControls,
  scControls, scGPControls, scGPImages, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    UserInfoPanel: TscGPPanel;
    HeadImg: TscGPImage;
    UwerNamePnl: TscGPLabel;
    GetImg: TscGPButton;
    UpdateImg: TscGPButton;
    SetImg: TscGPButton;
    AppBar: TscGPPanel;
    btnClose: TscGPCharGlyphButton;
    LabTitle: TscGPLabel;
    P_ErrInfo: TscGPPanel;
    labInfo: TscGPLabel;
    scGPImage1: TscGPImage;
    scGPButton2: TscGPButton;
    FDConnection1: TFDConnection;
    FDQUsers: TFDQuery;
    FDQUsersUserID: TFDAutoIncField;
    FDQUsersUserName: TWideMemoField;
    FDQUsersPassword: TWideMemoField;
    FDQUsersGroupID: TIntegerField;
    FDQUsersIsDisabled: TIntegerField;
    FDQUsersLoginTime: TWideMemoField;
    FDQUsersMAC: TWideMemoField;
    FDQUsersLockTime: TIntegerField;
    DSUsers: TDataSource;
    FDPhysSQLiteDriverLink1: TFDPhysSQLiteDriverLink;
    OpenPictureDialog1: TOpenPictureDialog;
    FDQUsersHeadImg: TBlobField;
    procedure btnCloseClick(Sender: TObject);
    procedure GetImgClick(Sender: TObject);
    procedure UpdateImgClick(Sender: TObject);
    procedure SetImgClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FMemoryStream: TMemoryStream;
  public
    { Public declarations }

  end;

var
  Form1: TForm1;

implementation
{$R *.dfm}

procedure TForm1.btnCloseClick(Sender: TObject);
begin
  FMemoryStream.Free;
  Close;
end;

procedure TForm1.GetImgClick(Sender: TObject);
begin
  with FDQUsers do
  begin
    Close;
    sql.Text := 'SELECT * FROM users where userid= 1';
    open;
    //ShowMessage(BoolToStr(IsEmpty, true));  //判断查询是否返回空集
    if not TBlobField(FieldByName('HeadImg')).IsNull then   //判断用户是否有设置头像
    begin
      FMemoryStream.Clear;  //先清除内存流空间
      TBlobField(FieldByName('HeadImg')).SaveToStream(FMemoryStream);    //把图像从数据库载入内存流
      FMemoryStream.Position := 0; //读取位置设置为0
      HeadImg.Picture.LoadFromStream(FMemoryStream); //显示到图片控件上
      labInfo.Caption := '头像已取回';
    end
    else
      labInfo.Caption := '无图片';
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMemoryStream := TMemoryStream.Create;
end;

procedure TForm1.SetImgClick(Sender: TObject);   //设置头像
var
  FileName: string;
begin
  if OpenPictureDialog1.Execute then
  begin
    FileName := OpenPictureDialog1.FileName;
    HeadImg.Picture.LoadFromFile(FileName);

    FMemoryStream.Clear;
    FMemoryStream.LoadFromFile(FileName); //把本地图片存到内存流中
    FMemoryStream.Position := 0;
    labInfo.Caption := '头像已从本地设置'
  end;
end;

procedure TForm1.UpdateImgClick(Sender: TObject);   //上传头像到数据库
begin
  with FDQUsers do
  begin
    close;
    sql.Text := 'Update users set headimg=:headimg where userid=1'; //:headimg是占位符
    ParamByName('headimg').LoadFromStream(FMemoryStream, ftBlob); // 填充:headimg占位符,从内存流中上传
    ExecSQL;
    labInfo.Caption := '头像已更新到数据库'
  end;
end;

end.