文件

类型文件

类型文件的声明方式如下:

1
2
var 
fileDesc : file of 类型;

文件的类型可以是基本类型,也可以是记录等。

文件变量其实只是一个指针,使用前应该使用 AssignFile() 先跟外部的文件名建立关联。

一些操作文件的例程:

  • Reset : 打开存在的文件
  • ReWrite : 新建并打开文件,如果文件已存在则先删除再新建打开
  • Append : 打开文件并以追加模式写
  • CloseFile : 关闭文件,断开文件变量与外部文件的联系
  • Read : 读文件到参数指定的记录
  • Write : 将参数指定的记录写入文件

Read、Write 的用法大致可以参考以下声明:

1
2
procedure Read(var F: file; v1 [, v2, v3, ... ]);
procedure Write(var F: file; v1 [, v2, v3, ... ]);

读写文件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Type
TRec = record
ch1:AnsiChar;
ch2:AnsiChar;
end;
var
Rec1, Rec2: TRec;
n: integer;
path: string;
F: file of TRec; // 声明 TRec 类型的文件
begin
Rec1.ch1 := 'A';
Rec1.ch2 := 'B';
writeln('请输入文件名: ');
Readln(path);
AssignFile(F, path); // 关联外部文件
if FileExists(path) then // 判断文件是否存在
Reset(F)
else //若不存在则新建这个文件
Rewrite(F);
for n := 1 to 9 do
Write(F, Rec1); // 连续写入 9 个 Rec1 变量值
Rec2.ch1 := '-';
Rec2.ch2 := '-';
Write(F,Rec2); // 将 Rec2 的值写入 F 指向的文件
CloseFile(F); // 断开关联
writeln('文件操作完毕');
readln;
end.

非类型文件

非类型文件就是不指定类型的 file 类型。

非类型文件的声明方式如下:

1
2
var 
fileDesc : file;

使用于类型文件的所有例程(过程与函数),都适用于非类型文件。

此外,还有两个函数专用于非类型文件:

1
2
function BlockRead(var f: File, var buffer, count: LongInt) : LongInt;
function BlockWrite(var f: File, var buffer, count: LongInt) : LongInt;

上面是 BlockRead 是将 count 个字节读取到 buffer 中,返回实际读取字节数。
BlockWrite 是将 buffercount 个字节写入到文件 ,返回实际写入字节数。

读写文件的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var
sourcename, targetname: string;
FSource, FTarget: file;
Buf: array[0..1] of AnsiChar;
begin
try
writeln('请分别输入文件名: ');
Readln(sourcename);
Readln(targetname);
AssignFile(FSource, sourcename);
AssignFile(FTarget, targetname);
Reset(FSource);
Rewrite(FTarget);
while eof(FSource) = False do
begin
BlockRead(FSource, Buf, 1);
BlockWrite(FTarget, Buf, 1);
end;
CloseFile(FSource);
CloseFile(FTarget);
except
writeln('error');
end;
writeln('文件操作完毕');
readln;
end

文本文件

文本文件使用 TextFile 声明:

1
2
var
fileDesc: TextFile;

适用于类型文件和非类型文件的所有过程、函数,同样也适用于文本文件。此外,有一点差异的是,reset 打开的文本文件为只读文件,rewriteappend 打开的文本文件为只写文件。

另外两个例程 WriteLnReadLn 用于操作文本文件, WriteLn 直接向文本文件中写入一行内容, ReadLn 则直接从文本文件中读取一行内容。

文件流

TStream

所有的流都是基于 TStream 基类,常见的方法如下:

1
2
3
4
5
6
7
8
function Read(var Buffer; Count: Longint): Longint; virtual; abstract;
function Write(const Buffer; Count: Longint): Longint; virtual; abstract;
function Seek(Offset: Longint; Origin: Word): Longint; overload; virtual;
procedure ReadBuffer(var Buffer; Count: Longint);
procedure WriteBuffer(const Buffer; Count: Longint);
function CopyFrom(Source: TStream; Count: Int64): Int64;
property Position: Int64 read GetPosition write SetPosition;
property Size: Int64 read GetSize write SetSize64;
  • Position 属性标识了读写指针的位置。
  • Size 属性则标识了流所占用的内存的大小。
  • 当读写指针处于流的末端时,这两个属性值相等。

文件流

文件流 TFileStream 重点成员:

1
2
3
4
5
6
7
8
TFileStream = class(TStream)
...
constructor Create(const AFileName: string; Mode: Word); overload;
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
function Seek(const Offset: Int64; Origin: TSeekOrigin):Int64; override;
...
end;

构造函数的 Mode 表示打开模式:

模式 表示意思
fmCreate 只写模式,文件不存在则先创建,文件存在则先清空文件的原内容
fmOpenRead 只读模式
fmOpenWrite 以只写方式打开文件,且写入的内容会取代文件原本的内容
fmOpenReadWrite 打开的文件可读也可写
以下为共享模式:
fmShareCompat 兼容 DOS 的,无用
fmShareExclusive 打开文件并独占文件,其它程序无法访问
fmShareDenyWrite 其它程序只能通过只读方式打开文件
fmShareDenyRead 其它程序只能通过只写方式打开文件
fmShareDenyNone 不对文件作任何限定

SeekOffset 参数表示读写指针移动的字节数,从哪里开始移动由 TSeekOrigin 决定。 TSeekOrigin 参数值有三种:

  • soFromBegining
  • soFromCurrent
  • soFromEnd

Offset 的值可以为负数,例如: Seek(-4, soFromEnd);

使用举例:

1
2
3
Stream := TFileStream.Create(target,fmCreate);
Stream.Write(pchar(str)^, length(str));
Stream.Free;

内存流

文件流 TMemoryStream 重点成员:

1
2
3
4
5
6
7
8
9
10
11
12
13
TMemoryStream = class(TStream)
...
function Write(const Buffer; Count: Longint): Longint; override;
function Read(var Buffer; Count: Longint): Longint; override;
function Seek(Offset: Longint; Origin: Word): Longint; override;
procedure Clear;
procedure LoadFromStream(Stream: TStream);
procedure LoadFromFile(const FileName: string);
procedure SaveToStream(Stream: TStream);
procedure SaveToFile(const FileName: string);
property Memory: Pointer read FMemory;
...
end;
  • Clear 方法用于清空内存流中的所有内容。
  • Memory 为一个 pointer 类型的指针,指向内存流在内存中的位置

注意:

  • 在使用 LoadFromX 时,内存流中原来的内容会被丢弃
  • 使用 SaveToX 时文件的原有内容也会被覆盖

使用举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
uses
SysUtils, Classes;
var
source, target: String;
o1, o2: TMemoryStream;
begin
writeln('输入源文件名: ');
readln(source);
writeln('输入目标文件名: ');
readln(target);
o1 := TMemoryStream.Create;
o1.LoadFromFile(source);
o2 := TMemoryStream.Create;
o2.LoadFromStream(o1);
o1.WriteBuffer(o2.Memory^, o2.Size); //不能用 LoadFromStream
o1.SaveToFile(target);
FreeAndNil(o1);
FreeAndNil(o2);
writeln('ok');
readln;
end.

字符串流

字符串流 TStringStream 继承于内存流,此外,字符串流中需要注意的新方法有:

1
2
3
function ReadString(Count: Longint): string;
procedure WriteString(const AString: string);
property DataString: string read FDataString;

使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var
Stream: TStringStream;
begin
Stream := TStringStream.Create;
Stream.WriteString('d');
Stream.WriteString('e');
Stream.WriteString('l');
Stream.WriteString('p');
Stream.WriteString('h');
Stream.WriteString('i');
writeln(Stream.DataString); // 取当前字符串内容
FreeAndNil(Stream);
readln;
end.

直接操作文件

Delphi 提供了一组 API 可以直接操作文件,不需要文件类型的变量:

1
2
3
4
5
6
function FileOpen(const FileName: string): Integer;
function FileCreate(const FileName: string): Integer; overload;
function FileRead(Handle: Integer; var Buffer; Count: Cardinal): Integer;
function FileSeek(Handle: Integer; Offset: Int64; Origin: Integer): Integer;
function FileWrite(Handle: Integer; const Buffer; Count: Cardinal): Integer;
procedure FileClose(Handle: Integer);