所谓"流", 就是一段数据或是一块内存;
在进行流操作时, 我们不必关心流中的数据到底是什么; 只需要知道流的大小和当前的指针位置. 所以流只有两个属性:
Size、Position.
对流的操作, 不过就是读取和写入. 所以流最主要的方法就是 Read 和 Write.
在很多控件的使用中, 读取主要用 LoadFromStream; 写入主要用 SaveToStream.
TMemoryStream(内存流) 入门
举个例子: (建立新工程, 添加两个 Memo、两个 Button)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 =class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
mStream: TStream;
{声明一个流对象}
procedure TForm1.FormCreate(Sender: TObject);
begin
mStream := TMemoryStream.Create;{TStream 是抽象类, 只能通过其子类实例化; 这里我们用了内存流来生成实例}
Memo1.Lines.Text :='ABCDEFGHIJKLMNOPQRSTUVWXYZ';{给 Memo1 个初始值}
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.SaveToStream(mStream); {把 Memo1 中的内容写入到流}
ShowMessage(IntToStr(mStream.Size)); {26, 当前流的大小}
ShowMessage(IntToStr(mStream.Position));{26, 当前流的指针}
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
mStream.Position :=4; {调整流的当前指针位置}
Memo2.Lines.LoadFromStream(mStream);
{读出流中的内容到 Memo2}{ 现在 Memo2 中的内容应该是: EFGHIJKLMNOPQRSTUVWXYZ 如果 Position 是 0,memo2 读出的内容会是: ABCDEFGHIJKLMNOPQRSTUVWXYZ 如果 Position 等于 Size, 在这里如果是 26, Memo2 就读不出什么了. }
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
mStream.Free;{流释放时, 所用内存当然也会同时释放}
end;
end.
内存流读取文件
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation{$R *.dfm}
var
mStream: TMemoryStream;
procedure TForm1.FormCreate(Sender: TObject);//程序开始先创建一个准备要测试的文件
var
strList: TStringList;
begin
strList := TStringList.Create;
strList.Add('aaaaaaaa');
strList.Add('bbbbbbbb');
strList.Add('cccccccc');
strList.Add('dddddddd');
strList.SaveToFile('c:\temp\test.txt');
strList.Free; {同时建立内存流}
mStream := TMemoryStream.Create;
end;
procedure TForm1.Button1Click(Sender: TObject);//通过流读文件到 Memo
begin
mStream.LoadFromFile('c:\temp\test.txt');{把文件读入内存流}
Memo1.Lines.LoadFromStream(mStream); {把内存流载入 Memo1}
end;
procedure TForm1.Button2Click(Sender: TObject);//用字符指针读取流中的内容
var
pc: PChar;
begin
pc := mStream.Memory;{把字符指针指向内存流}
ShowMessage(pc[0]);{a; 第一个字符}
ShowMessage(pc[10]);{b; 这个第二行的第一个字符; 每行8个字再加换行与回车共10个字符}
ShowMessage(pc[20]);{c} ShowMessage(pc[30]);{d}
end;
procedure TForm1.Button3Click(Sender: TObject);//从流读入到缓冲区
var
buffer: array[0..2]of Char;{定义个字符缓冲区}
begin
mStream.Seek(0, soFromBeginning);
mStream.Read(buffer,SizeOf(buffer));
ShowMessage(buffer);{aaa}
mStream.Seek(10, soFromBeginning);
mStream.Read(buffer, SizeOf(buffer));
ShowMessage(buffer); {bbb}
mStream.Seek(20, soFromBeginning);
mStream.Read(buffer, SizeOf(buffer));
ShowMessage(buffer); {ccc}
mStream.Seek(30, soFromBeginning);
mStream.Read(buffer, SizeOf(buffer));
ShowMessage(buffer); {ddd}
{关于 Seek 函数: 参数1: Offset 是偏移量; 参数2: Origin 是指针的基准位置, 有三个选值: soFromBeginning、soFromCurrent、soFromEnd soFromBeginning: 以开始为基准, 此时参数 Offset 要 >= 0; soFromCurrent: 以当前位置为基准; soFromEnd: 以结束为基准; 此时参数 Offset 要 <= 0; 返回: 指针新位置}
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
mStream.Free;
end;
end.
TFileStream读写
TStream 是一个抽象的基类, 不能直接生成对象. 在具体的应用中, 主要使用它的子孙类:
TFileStream: 文件流
TStringStream: 字符串流
TMemoryStream: 内存流
TResourceStream: 资源文件流
THandleStream: 是 TFileStream 的父类、
TStream 的子类TCustomMemoryStream: 是 TMemoryStream 和 TResourceStream 的父类、
TStream 的子类与流相关的常用类还有: TReader、TWriter、TCompressionStream、TDecompressionStream
来一个文件流的例子:
procedure TForm1.Button1Click(Sender: TObject);
var
getStream,setStream: TFileStream; {声明一个文件流}
getPath,setPath:string;
begin
getPath := 'c:\temp\get.jpg';{需要这个文件存在}
setPath :='c:\temp\set.jpg';{这个会自动建立}
ifnot FileExists(getPath)then
begin
ShowMessage('找不到我们要测试的图片文件: ' + getPath);
Exit;
end;
getStream := TFileStream.Create(getPath, fmOpenReador fmShareExclusive);
setStream := TFileStream.Create(setPath, fmCreate);{建立文件流需要两个参数: 参数 1 是路径, 参数 2 是打开模式}
getStream.Position :=0;{流指针移到开始, 复制时从这里开始}
setStream.CopyFrom(getStream, getStream.Size);{Copy 流}{CopyFrom 的参数 2 是要复制的内容大小; 如果为 0 , 不管指针在什么位置都会复制所有内容}{CopyFrom 返回实际拷贝的字节数}
{这时硬盘上就有 set.jpg 文件, 与 get.jpg 一么一样}{其实就是复制文件, 不过这里我们是用文件流实现的}
getStream.Free;
setStream.Free;
end;
TFileStream 打开模式与共享模式:
分类
参数
说明
打
开
模
式
fmCreate |
建立文件, 如果存在则打开它。 |
fmOpenRead |
只读打开 |
fmOpenWrite |
只写打开 |
fmOpenReadWrite |
读写打开 |
共
享
模
式
fmShareCompat |
共享模式, 兼容 Dos |
fmShareExclusive |
不允许别人以任何方式打开 |
fmShareDenyWrite |
允许别人以只写方式打开 |
fmShareDenyRead |
允许别人以只读方式打开 |
fmShareDenyNone |
允许别人以任何方式打开 |
遍历读取流中的所有数据
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;{需要添加两个 Memo 用于显示}
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}//先制造一个测试文件
procedure TForm1.FormCreate(Sender: TObject);
var
strList: TStringList;
begin
strList := TStringList.Create;
strList.Add('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
strList.SaveToFile('c:\temp\test.txt'); strList.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ms: TMemoryStream;
c: Char; s1,s2: string;
begin
ms := TMemoryStream.Create;
ms.LoadFromFile('c:\temp\test.txt');{读入内存流}
s1 :=''; s2 :='';
ms.Position :=0; {指针到开始}
while ms.Position < ms.Sizedo {循环读出}
begin
ms.Read(c,1); {每读出一个字节, 指针会自动移到新的位置}
s1 := s1 + c +' '; {用文本记录}
s2 := s2 + IntToHex(Byte(c),2) +' ';{用两位数的十六进制记录}
end;
Memo1.Lines.Text := s1;
Memo2.Lines.Text := s2;{Memo1 会显示: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }{Memo2 会显示: 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 0D 0A}
ms.Free;
end;
end.
序列化
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}//添加一个 Memo1 然后修改其内容
procedure TForm1.Button1Click(Sender: TObject);
begin
WriteComponentResFile('c:\temp\memo.dat', Memo1);{只此一句就可以把当前的 Memo 的状态序列化到文件}
end;
//反序列化, 读回
procedure TForm1.Button2Click(Sender: TObject);
begin
ReadComponentResFile('c:\temp\memo.dat', Memo1);{一句话就可以读回, 不管是经过了什么操作(甚至是关机)}
end;{ 这好像和流没什么关系, 其实这就是流的典型操作, WriteComponentResFile 和 ReadComponentResFile 分别调用了流类的 WriteComponentRes 与 ReadComponentRes 方法. 下面用更直接的流的方式重新实现一次:}
//序列化
procedure TForm1.Button3Click(Sender: TObject);
var
stream: TStream;
const strPath ='c:\temp\m.dat';
begin
stream := TFileStream.Create(strPath, fmCreate);
stream.WriteComponentRes(Memo1.ClassName, Memo1);{WriteComponentRes 有两个参数: 文件名和组件名}
stream.Free;
end;
//反序列化
procedure TForm1.Button4Click(Sender: TObject);
var
stream: TStream;
const strPath ='c:\temp\m.dat';
begin
stream := TFileStream.Create(strPath, fmOpenRead);
stream.ReadComponentRes(Memo1);{ReadComponentRes 只有一个参数: 组件名}
stream.Free;
end;
end.
用流读写结构化文件
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo; {添加 Memo 显示内容}
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TRec = record {定义一个记录}
name:string[8];
age: Word;
end;//写入
procedure TForm1.Button1Click(Sender: TObject);
var
rec: TRec;
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
rec.name := '张三';
rec.age :=8;
ms.Write(rec, SizeOf(rec));
rec.name :='李四';
rec.age :=81;
ms.Write(rec, SizeOf(rec));
rec.name :='王二麻子';
rec.age :=18;
ms.Write(rec, SizeOf(rec));
ms.SaveToFile('c:\temp\rec.dat');
ms.Free;
end;
//读取
procedure TForm1.Button2Click(Sender: TObject);
var
rec: TRec;
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
ms.LoadFromFile('c:\temp\rec.dat');
Memo1.Clear;
ms.Position :=0;
while ms.Position < ms.Sizedo
begin
ms.Read(rec, SizeOf(rec));
Memo1.Lines.Add(rec.name +' ' + IntToStr(rec.age));
end;{Memo1 的显示结果会是: 张三 8 李四 81 王二麻子 18 }
ms.Free;
end;
end.
压缩与解压缩
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
Zlib; {压缩流 TCompressionStream 与解压缩流 TDecompressionStream 来自 Zlib 单元}//压缩
procedure TForm1.Button1Click(Sender: TObject);
var
cs: TCompressionStream;{定义压缩流}
fs,ms:TMemoryStream;{fs 是要压缩的流; ms 是接收压缩后文件的流}
num: Integer; {原始文件大小}
begin{第一步: 调入要压缩的文件, 并获取大小}
fs := TMemoryStream.Create;
fs.LoadFromFile('c:\temp\test.txt');{文件要存在啊}
num := fs.Size;{第二步: 建立接收的流, 并先写入原始文件大小}
ms := TMemoryStream.Create;
ms.Write(num, SizeOf(num));{第三步: 压缩}
cs := TCompressionStream.Create(clMax, ms);{参数1是压缩比; 参数2是接收流}
fs.SaveToStream(cs);{传入要压缩的数据}
cs.Free; {压缩流 Free 后才真正完成压缩, 所以提前 Free}{第四步: 保存}
ms.SaveToFile('c:\temp\test.zipx');{第五步: 释放}
ms.Free; fs.Free;{压缩比参数: clNone 无压缩 clFastest 快速 clDefault 默认 clMax 最大比例}
end;
//解压缩
procedure TForm1.Button2Click(Sender: TObject);
var
ds: TDecompressionStream;{解压流}
fs,ms: TMemoryStream; {fs 是准备要解压的流; ms 是接受解压数据的流}
num: Integer; {接受文件压缩前的大小}
begin{第一步: 准要解压的文件}
fs := TMemoryStream.Create;
fs.LoadFromFile('c:\temp\test.zipx');{必须是上一个压缩方法生成的文件}{第二步: 读出文件压缩前的大小}
fs.Position :=0; fs.ReadBuffer(num,SizeOf(num));{第三步: 准备好要接收的流, 并设置需要的大小}
ms := TMemoryStream.Create; ms.SetSize(num);{第四步: 解压}
ds := TDecompressionStream.Create(fs);{参数是要解压的流}{第五步: 把解压后的数据读出存放到已准备好接收的流}
ds.Read(ms.Memory^, num);{第六步: 保存}
ms.SaveToFile('c:\temp\test2.txt');
ds.Free;
ms.Free;
fs.Free;
end;
end.
压缩与解压缩的函数
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
Zlib;//压缩函数
procedure Zip(var fs: TMemoryStream);
var
cs: TCompressionStream;
ms: TMemoryStream;
num: Integer;
begin
ifnot(Assigned(fs)and (fs.Size>0))then
Exit;
num := fs.Size;
ms := TMemoryStream.Create;
cs := TCompressionStream.Create(clMax, ms);
try
fs.SaveToStream(cs);
cs.Free; //ms.Position := 0;
fs.Clear;
fs.WriteBuffer(num, sizeof(num));
fs.CopyFrom(ms,0);
finally
ms.Free;
end;
end;
//解压函数
procedure UnZip(var fs: Tmemorystream);
var
ds: TDecompressionStream;
ms: TMemoryStream;
num: Integer;
begin
ifnot(Assigned(fs)and (fs.Size>0))then
Exit;
fs.Position :=0;
fs.ReadBuffer(num,sizeof(num));
ms := TMemoryStream.Create;
ds := TDecompressionStream.Create(fs);
try
ms.SetSize(num);
ds.Read(ms.Memory^, num); //ms.Position := 0;
fs.Clear;
fs.CopyFrom(ms,0);
finally
ds.Free;
ms.Free;
end;
end;
//压缩测试
procedure TForm1.Button1Click(Sender: TObject);
var
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
ms.LoadFromFile('c:\temp\test.txt');
Zip(ms);
ms.SaveToFile('c:\temp\test.zipx');
end;
//解压测试
procedure TForm1.Button2Click(Sender: TObject);
var
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
ms.LoadFromFile('c:\temp\test.zipx');
UnZip(ms);
ms.SaveToFile('c:\temp\test2.txt');
end;
end.
分割与合并文件函数
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}//分割文件的函数{参数 1 是要分割的文件名; 参数 2 是要风格文件的大小, 单位是 KB}{分割后的文件名扩展名用序号替换}
function SplitFile(const FileName:string; Size: Cardinal): Boolean;
var
fStream: TFileStream;{原始文件}
toStream: TMemoryStream;{分文件}
p,i: Integer; {p 记录当前指针位置; i 记录这是第几个分的文件}
begin
Result := False;
Size := Size * 1024; {把大小的单位转换为字节}
fStream := TFileStream.Create(FileName, fmOpenRead);
p :=0;
i :=0;
toStream := TMemoryStream.Create;
while p < fStream.Size do
begin
toStream.Clear; {清空上次数据}
fStream.Position := p;{放好指针位置}
if fStream.Size-p < Sizethen
Size := fStream.Size-p;{最后一个时, 有多少算多少}
toStream.CopyFrom(fStream, Size);{复制}
toStream.SaveToFile(FileName +'.' + IntToStr(i)); {保存}
Inc(i);
p := p + Size;
end;
fStream.Free;
toStream.Free;
Result := True;
end;
//合并文件, 参数是其中一个分文件名
function MergeFile(const FileName:string):Boolean;
var
ms: TMemoryStream; {读取分文件}
fs: TFileStream;{合并后的文件}
path:string;
i: Integer;
begin
path := ChangeFileExt(FileName,'');{去掉序号扩展名}
ShowMessage(path);
i :=0;
ms := TMemoryStream.Create;
fs := TFileStream.Create(path, fmCreate);
while FileExists(path +'.' + IntToStr(i))do
begin
ms.LoadFromFile(path +'.' + IntToStr(i));
fs.CopyFrom(ms,0);{TFileStream 不需要 SetSize; 但如果用 TMemoryStream 就需要}
Inc(i);
end;
ms.Free;
fs.Free;
end;
//测试分割
procedure TForm1.Button1Click(Sender: TObject);
begin
SplitFile('c:\temp\test.txt',10);
end;
//测试合并
procedure TForm1.Button2Click(Sender: TObject);
begin
MergeFile('c:\temp\test.txt.0');
end;
end.
分享到:
相关推荐
delphi读取文件流delphi读取文件流 tfilestream利用字节数组复制文件
Delphi API使用手册Delphi API使用手册
1、下载后分别解压CEF4Delphi-master和cef_binary_101.0.18+g367b4a0+chromium-101.0.4951.67_windows32.tar 2、安装CEF4Delphi-master 3、将cef_binary_101.0.18+g367b4a0+...4、编译demo文件夹下文件即可使用demo了
Delphi中frame的使用Delphi中frame的使用Delphi中frame的使用Delphi中frame的使用Delphi中frame的使用
可以在DELPHI XE里安装使用的串口控件,使用的方法也等同于在旧版delphi,如 7。 安装方法:Component -> install component,按提示操作
在Delphi环境下使用Redis,支持发布订阅等,在常用的delphi开发环境下都能编译通过,本实例在Delphi7环境下编译通过
The current version of the program can process files (GUI and console applications), compiled by Delphi compilers of versions Delphi2 – Delphi XE3. Final project goal is development of the program ...
可以在DELPHI7下正常使用,里面有详细的说明使用方法.
Delphi使用技巧 Delphi使用技巧 Delphi使用技巧 Delphi使用技巧
Delphi DBGridEh 使用资料
delphi7使用IXMLHTTPRequest实现RESTful的访问及返回json数据的解析,推送消息段HMACSHA1加密编码
Delphi2007的IDE速度相比BDS2006,只能用一个字形容:“快”!例如我目前安装了如下控件:Appcontrols、Ehlib、Raize、Sdac、TmsPack等等,机器是IBM ThinkPad X32,1G内存,在初次开机的情况下,启动delphi2007大约...
Delphi中sql语句的使用总结 Delphi中sql语句的使用总结 Delphi中sql语句的使用总结
Delphi使用 Delphi使用 Delphi使用 Delphi使用 Delphi使用
Delphi 6 使用编程教程.pdf Delphi 6 使用编程教程.pdf
delphi dbexpress 入门 使用基础
在做delphi UI界面的时候,经常会碰到需要用到透明背景的png图片,原生代码无法满足,这里写了一个例子供大家参考,安装完控件之后,dephi原来的Image控件就支持png了
delphi2010 使用unidac连接sqlite的例子
delphi线程使用的例子,适合delphi新手学习使用。。。。