M
media21
Unregistered / Unconfirmed
GUEST, unregistred user!
编译时出现Undeclared identifier: 'TCompressionStream' 请高手指教,多谢。
解决了再加分。
unit uEnStore;
interface
uses
uConst,SysUtils,Classes;// ,Windows,nCrc32,;
type
//单词库文件头
TEnStoreHead =packed record
Version:Byte32; //版本(4个字节):$1.2.0.0(2005-10-4日开始)
DataPos:Byte32; //数据区开始位置,恒为$00000014
WordsTotal :Byte32; //单词数据块的数量
ChunkTotal :Byte32; //所有的数据块数,减去单词数就是 存在的文章的数量
CRC32 :Byte32; //文件校验,恒为$78787878
end;
{
如下结构仅说明 存储的顺序结构,并不使用;实际存储是变长的。
如下一个chuck为一个单词块,从Word到Comment均为以 0 结束的字符串。
}
//一个单词,变长>4个字节。即一个chunk
TEnStoreWord =packed record
//具体建立此ID时,采用顺序编号的方式。
//ID :Integer; //本单词ID,应当为GUID,方便上下文间的连接关系,同时方便索引
//Length :Byte16; //本Chunk长度,不包括自身这2个字节及ID的4个字节!!!
Length :Byte32; //2005-9-28,修正
Verdancy :char; //陌生度
LastTime Double; //时间序列(个数对应于陌生度)
Word AnsiChar; //单词
PhoneticSymbolAnsiChar; //音标
Explanation AnsiChar; //解释
Comment AnsiChar; //2005-9-8,作为注释
Accessory Accessory; //附件,2005-10-6
//EnWordContext :TEnWordsContext; //上下文,2005-4-19
end;
TEnStore =class(TObject)
private
FStoreName:string;//储存文件名称。
FEnLib :TFileStream;
FHead :TEnStoreHead;
FStoreSize:Cardinal;//文件大小
procedure InitEnLib;
procedure OnCompressDecompress(Sender:TObject);
procedure CompressEc(AFileName:string);
procedure DeCompressEc(AFileName:string);
public
//constructor Create;
constructor Create(const AFileName:string;isDefault:Boolean);//override;//2005-9-5添加,为了能够导入另一个词库文件
destructor Destroy;override;
procedure Prepare;//将文件指针移到文件头的尾部
procedure GetOneWord(AEnWordEnWord);
procedure SaveWord(AEnWordEnWord);
procedure StartSaveWords;//申请内存缓冲
procedure EndSaveWords;//释放内存缓冲
procedure SaveHead;
property HeadInfo:TEnStoreHead read FHead;
property StoreFileName :string read FStoreName;
end;
implementation
uses ZLib,
Windows,
ShellAPI;
var//指示当前操作,是压缩还是解压缩
isForCompress:Boolean;
procedure TEnStore.CompressEc(AFileName:string);
var
memSrc,memDst :TMemoryStream;
[red]compressStream:TCompressionStream;[/red]
FileSize,fileVersion:Int64;
begin
//备份覆盖掉已经存在的文件
isForCompress :=True;
BackupEc(AFileName);
memSrc :=TMemoryStream.Create;
memDst :=TMemoryStream.Create;
try
memSrc.LoadFromFile(AFileName);
//校验
fileVersion :=SizeOf(TEnStoreHead);
fileVersion :=(fileVersion shl 32) or STORE_VER;
memSrc.ReadBuffer(FileSize,SizeOf(FileSize));
if FileSize<>fileVersion then//不是正常文件,拒绝压缩
Exit;
memSrc.Seek(0,soFromBeginning);
FileSize :=memSrc.Size;
compressStream :=TCompressionStream.Create(clFastest,memDst);
try
ShowProgress(Self,sptStart,SetProgressValue(FileSize,0,0));
compressStream.OnProgress :=OnCompressDecompress;
memSrc.Seek(0,soFromBeginning);
compressStream.CopyFrom(memSrc,memSrc.Size);
finally
compressStream.Destroy;
end;
memSrc.Clear;
memSrc.Write(FileSize,sizeof(FileSize));//保存原始文件大小
memDst.Seek(0,soFromBeginning);
memSrc.CopyFrom(memDst,memDst.Size);//保存压缩后的流
memSrc.Seek(0,soFromBeginning);//复位文件指针。
memSrc.SaveToFile(AFileName); //保存到新文件
finally
memSrc.Destroy;
memDst.Destroy;
end;
end;
//创建这个类之前,首先将Ec文件解压缩。
procedure TEnStore.DeCompressEc(AFileName:string);
var
memSrc:TMemoryStream;
DecompressStream:TDecompressionStream;
FileSize,fileVersion:Int64;
bufChar;
begin
//覆盖掉已经存在的文件
isForCompress :=False;
BackupEc(AFileName);
if FileExists(AFileName) then//文件必须首先存在,才能判断是否解压缩。
begin
memSrc :=TMemoryStream.Create;
try
memSrc.LoadFromFile(AFileName);
memSrc.ReadBuffer(FileSize,SizeOf(FileSize));
fileVersion :=SizeOf(TEnStoreHead);
fileVersion :=(fileVersion shl 32) or STORE_VER;
if FileSize=fileVersion then//上一次是非正常退出了,于是不再解压缩
Exit;
GetMem(buf,FileSize);
DecompressStream :=TDecompressionStream.Create(memSrc);
try
ShowProgress(Self,sptStart,SetProgressValue(FileSize,0,0));
DecompressStream.OnProgress :=OnCompressDecompress;
DecompressStream.ReadBuffer(buf^,FileSize);
memSrc.Clear;
memSrc.WriteBuffer(buf^,FileSize);
memSrc.Seek(0,soFromBeginning);
memSrc.SaveToFile(AFileName);
finally
FreeMem(buf);
DecompressStream.Destroy;
end;
finally
memSrc.Destroy;
end;
end;
end;
//压缩与解压缩的进度指示,2005-10-7
procedure TEnStore.OnCompressDecompress(Sender:TObject);
var hint:string;
begin//如此能够不断的刷新进度耗时,来产生这无法准确估计的进度提示
if isForCompress then hint:='压缩...'
else hint:='解压缩...';
ShowProgress(Self,sptEnd,SetProgressValue(0,0,0,hint));
end;
//------------------------------------------------------------------------------
constructor TEnStore.Create(const AFileName:string;isDefault:Boolean);
//仅仅为了导入另一个词库
begin
FStoreName :=AFileName;
DeCompressEc(FStoreName);
if not FileExists(FStoreName) then
begin
//创建 或 使用 默认词库文件
if isDefault then
begin
FStoreName :=strAppPath +strDefaultStoreFile;
if not FileExists(FStoreName) then
FEnLib :=TFileStream.Create(FStoreName,fmCreate)
else begin
FEnLib :=TFileStream.Create(FStoreName,fmOpenReadWrite+fmShareDenyWrite);
InitEnLib;
end;
end
else
FEnLib :=TFileStream.Create(FStoreName,fmCreate)
end
else begin
FEnLib :=TFileStream.Create(FStoreName,fmOpenReadWrite+fmShareDenyWrite);
InitEnLib;
end;
end;
destructor TEnStore.Destroy;
begin
FEnLib.Destroy;
CompressEc(FStoreName);
end;
type EStoreInValid=class(Exception);
procedure TEnStore.Prepare;//移动到数据开始位置
begin
if FEnLib<>nil then
FEnLib.Seek(Sizeof(FHead),soBeginning)
else
raise EStoreInValid.Create('严重错误:文件未正常打开');
end;
type EStoreVerFail=class(Exception);
procedure TEnStore.InitEnLib;//读出文件信息,并读出文件大小。
begin
FEnLib.Seek(0,soBeginning);
if Sizeof(FHead)<>FEnLib.Read(FHead,Sizeof(FHead)) then
raise EStoreVerFail.Create('单词库系统信息读取出错!');
//Check Version
if FHead.Version<>STORE_VER then raise EStoreVerFail.Create('单词库版本号不对!');
//读取文件大小
FStoreSize :=FEnLib.Seek(0,soEnd);
end;
{*
2005-4-1已能够正常读取单词
}
type EGetWordException=class(Exception);
procedure TEnStore.GetOneWord(AEnWordEnWord);
var
//len:Word;
len:Integer;//2005-9-28,升级数据库,单个Chunk长度改为4字节
i :Integer;
pt QueryEnWordTime;
cache:array of Char;
// pInt Integer;
theStrLen:Integer;
pStrStart,pCacheChar;
// ,pStr Char;
// pDbl Double;
begin
//FEnLib.Read(len,2);
if FEnLib.Position>=FStoreSize then raise EGetWordException.Create('读文件已经越界!');
FEnLib.Read(len,4);//2005-9-28,本着先写再读的原则来升级数据库
if len<5 then raise EGetWordException.Create('读单词出错,Chunk长度值太小!');
FEnLib.Read(AEnWord^.Verdancy,1);
if AEnWord^.Verdancy>0 then
begin
// Setlength(cache,8*AEnWord^.Verdancy);
// FEnLib.Read(cache[0],8*AEnWord^.Verdancy);
// pCache :=@cache[0];
//构造时间序列链表
i :=AEnWord^.Verdancy;
pt:=@(AEnWord^.LastTime);
pt^.qPre :=nil;
repeat
FEnLib.Read(pt^.qTime,8);
Dec(i);
if i<=0 then Break;
New(pt^.qPre);
pt :=pt^.qPre;
pt^.qPre :=nil;
until i=0;
end
else begin
AEnWord^.LastTime.qTime :=Now();
AEnWord^.LastTime.qPre :=nil;
end;
if len<(5+8*AEnWord^.Verdancy) then raise EGetWordException.Create('读单词出错,Chunk长度不对!');
Setlength(cache,len -5-8*AEnWord^.Verdancy);
FEnLib.Read(cache[0],len-5-8*AEnWord^.Verdancy);
pCache :=@cache[0];
with AEnWord^ do
try
i :=0;
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Word,pStrStart,theStrLen);
//{$define RtfDebug2005-9-28}
{$ifDef RtfDebug2005-9-28}
//if pNode^.EnWord.Word='entail' then log(CacheStr,cstrLogTxt);
{$endif}
Inc(i);
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Phonetic,pStrStart,theStrLen);
Inc(i);
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Explanation,pStrStart,theStrLen);
Inc(i);//2005-9-8,增加“附注”
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Comment,pStrStart,theStrLen);
finally
// pCache :=nil;
end;
// Integer(pInt) :=Integer(pCache);
// pStr :=@pCache[4];
// SetString(Word,pStr,pInt^);
//
// Inc(pCache,pInt^+4);
// Integer(pInt) :=Integer(pCache);
// Integer(pStr) :=Integer(@pCache[4]);
// SetString(Phonetic,pStr,pInt^);
//
// Inc(pCache,4+pInt^);
// Integer(pInt) :=Integer(pCache);
// Integer(pStr) :=Integer(@pCache[4]);
// SetString(Explanation,pStr,pInt^);
//
// //读出附注,根据压缩否来确定是否解压缩
// Inc(pCache,4+pInt^);
// Integer(pInt) :=Integer(pCache);
// Accessory.Size:=pInt^;
// Integer(pInt) :=Integer(@pCache[4]);
// Accessory.genre:=pInt^;
// if Accessory.genre=Integer(agNone) then//未压缩
// begin
// Integer(pStr) :=Integer(@pCache[8]);
// SetString(Comment,pStr,Accessory.Size)
// end
// else begin
// end;
// finally
// cache :=nil;
// pCache:=nil;
// end;
end;
//压缩存储。
//procedure TEnStore.CompressTo(AComment:string;ACacheChar);
//var
// StreamCompress:TCompressionStream;
// StreamStr :TStringStream;
// StreamMem :TMemoryStream;
//begin
// StreamStr :=TStringStream.Create(AComment);
// StreamMem :=TMemoryStream.Create;
// try
// StreamCompress :=TCompressionStream.Create(clFastest,StreamMem);
// try
// StreamCompress.CopyFrom(StreamStr,StreamStr.Size);
// finally
// StreamCompress.Destroy;
// end;
// StreamMem.Seek(0,soFromBeginning);
// StreamMem.SaveToFile('zlibtest.bin');
// StreamMem.Seek(0,soFromBeginning);
// StreamMem.ReadBuffer(ACache,StreamMem.Size);
// finally
// StreamStr.Destroy;
// StreamMem.Destroy;
// end;
//end;
//procedure TEnStore.DeCompressFrom(var AComment:string;ACacheChar);
//begin
//end;
//保存单词使用的缓冲区指针
var cache Char;
procedure TEnStore.SaveWord(AEnWordEnWord);//第一个单词节点
procedure SaveIt;
var
xt:Cardinal;
//yt:^Word;//2005-9-28,16K的大小已经不能够正确读出数据,不过如下算法倒是能够正常写入,就是这个总长度会被截断!
yt :^Cardinal;//pInt
pCacheChar;//pComment
wLen,pLen,eLen,cLen:Cardinal;//单词长、音标长、解释长、附注长
procedure SaveQueryTimes(const pTimeNodeQueryEnWordTime;ACacheChar);//递归实现时间链表反序遍历存储。
var
pTime Double;
begin
if pTimeNode^.qPre<>nil then
begin
Integer(pCache) :=Integer(ACache) +sizeof(double);
SaveQueryTimes(pTimeNode^.qPre,pCache);
Integer(pTime) :=Integer(ACache);
pTime^ :=pTimeNode^.qTime;
end
else begin
Integer(pTime) :=Integer(ACache);
pTime^ :=pTimeNode^.qTime;
end;
end;
begin
//计算本单词占用长度
Integer(yt) :=Integer(Cache);
pCache :=Cache;
with AEnWord^ do
begin
wLen :=Length(Word);
pLen :=Length(Phonetic);
eLen :=Length(Explanation);
cLen :=Length(Comment);
// yt^ :=5 +Verdancy *sizeof(Double)
// + wLen+1 + pLen+1 +eLen+1 +cLen+1;//2005-9-8
Inc(pCache,4);//因为Cardinal占用了4字节
Byte(pCache^):=Verdancy;//陌生度
inc(pCache,1);
if Verdancy>0 then//被删除的单词仅把陌生度记为0,不保存时间序列
SaveQueryTimes(@(LastTime),pCache);//逆序方式保存时间序列
xt :=5+Verdancy *sizeof(Double);//单词
pCache :=Cache;
inc(pCache,xt);//绝对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=wLen;//保存单词的长度
// inc(pCache,4);
StrCopy(pCache,PAnsiChar(Word));//保存单词
pCache[wLen] :=#0;
xt :=xt +1+wLen;//音标
inc(pCache,1+wLen);//相对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=pLen;//保存单词的长度
// inc(pCache,4);
DTrimRight(Phonetic);//2005-10-16添加
StrCopy(pCache,PAnsiChar(Phonetic));
pCache[plen] :=#0;
xt :=xt +1+plen;//解释
inc(pCache,1+plen);//相对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=eLen;//保存单词的长度
// inc(pCache,4);
StrCopy(pCache,PAnsiChar(Explanation));
pCache[elen] :=#0;
xt :=xt +1+elen;//附注,2005-9-8
if (xt +8+clen)<nOneChunkMaxLength then//否则不予存储!
begin//为了确保未超过限度值,2005-9-9
inc(pCache,1+elen);//相对偏移
//附注大于1024Kb的 就采用压缩存储
// FillChar(Accessory,SizeOf(Accessory),0);
// if cLen>1024 *1024 then
// begin
// pComment :=pCache;
// Inc(pCache,8);//后移8个字节,给Accessory 留出存储空间
// CompressBuf(PChar(Comment),cLen,Pointer(pCache),Accessory.Size);
// xt :=xt + 8+Accessory.Size;//总长度
// //写入类型
// Integer(pInt) :=Integer(pComment);
// pInt^ :=Accessory.Size;//Accessory.Size :=0;
// Integer(pInt) :=Integer(@pComment[4]);
// pInt^ :=Integer(agMem);//Accessory.Genre :=Integer(agMem);
// end
// else
// begin
// Integer(pInt) :=Integer(pCache);
// pInt^ :=0;//Accessory.Size :=0;
// Integer(pInt) :=Integer(pCache)+4;
// pInt^ :=Integer(agNone);//Accessory.Genre :=Integer(agNone);
// Inc(pCache,8);
StrCopy(pCache,PAnsiChar(Comment));
pCache[clen] :=#0;
xt :=xt + 1+clen;//总长度
// end;
end;
end;
Integer(yt) :=Integer(Cache);
yt^:=xt;
FEnLib.Write(Cache^,xt);//参数传递!非指针!2005-4-1
end;
begin
SaveIt;
Inc(FHead.ChunkTotal);
//通过音标来区分 是文章 还是单词
if not CheckIsArticle(AEnWord)then//是单词,不是文章
Inc(FHead.WordsTotal);
end;
procedure TEnStore.StartSaveWords;//申请内存缓冲
begin
GetMem(Cache,nOneChunkMaxLength);
FHead.ChunkTotal :=0;
FHead.WordsTotal :=0;
end;
procedure TEnStore.EndSaveWords;//释放内存缓冲
begin
FreeMem(Cache);
//必须确认已经保存数据库完毕
SetEndOfFile(FEnLib.Handle);//抛弃多余的部分,此时当保证Position位置的正确性
end;
procedure TEnStore.SaveHead;
begin
FHead.Version :=STORE_VER;
FHead.DataPos :=sizeof(FHead);
FHead.CRC32:=$78787878;
FEnLib.Seek(0,soBeginning);
FEnLib.Write(FHead,sizeof(FHead));
end;
end.
解决了再加分。
unit uEnStore;
interface
uses
uConst,SysUtils,Classes;// ,Windows,nCrc32,;
type
//单词库文件头
TEnStoreHead =packed record
Version:Byte32; //版本(4个字节):$1.2.0.0(2005-10-4日开始)
DataPos:Byte32; //数据区开始位置,恒为$00000014
WordsTotal :Byte32; //单词数据块的数量
ChunkTotal :Byte32; //所有的数据块数,减去单词数就是 存在的文章的数量
CRC32 :Byte32; //文件校验,恒为$78787878
end;
{
如下结构仅说明 存储的顺序结构,并不使用;实际存储是变长的。
如下一个chuck为一个单词块,从Word到Comment均为以 0 结束的字符串。
}
//一个单词,变长>4个字节。即一个chunk
TEnStoreWord =packed record
//具体建立此ID时,采用顺序编号的方式。
//ID :Integer; //本单词ID,应当为GUID,方便上下文间的连接关系,同时方便索引
//Length :Byte16; //本Chunk长度,不包括自身这2个字节及ID的4个字节!!!
Length :Byte32; //2005-9-28,修正
Verdancy :char; //陌生度
LastTime Double; //时间序列(个数对应于陌生度)
Word AnsiChar; //单词
PhoneticSymbolAnsiChar; //音标
Explanation AnsiChar; //解释
Comment AnsiChar; //2005-9-8,作为注释
Accessory Accessory; //附件,2005-10-6
//EnWordContext :TEnWordsContext; //上下文,2005-4-19
end;
TEnStore =class(TObject)
private
FStoreName:string;//储存文件名称。
FEnLib :TFileStream;
FHead :TEnStoreHead;
FStoreSize:Cardinal;//文件大小
procedure InitEnLib;
procedure OnCompressDecompress(Sender:TObject);
procedure CompressEc(AFileName:string);
procedure DeCompressEc(AFileName:string);
public
//constructor Create;
constructor Create(const AFileName:string;isDefault:Boolean);//override;//2005-9-5添加,为了能够导入另一个词库文件
destructor Destroy;override;
procedure Prepare;//将文件指针移到文件头的尾部
procedure GetOneWord(AEnWordEnWord);
procedure SaveWord(AEnWordEnWord);
procedure StartSaveWords;//申请内存缓冲
procedure EndSaveWords;//释放内存缓冲
procedure SaveHead;
property HeadInfo:TEnStoreHead read FHead;
property StoreFileName :string read FStoreName;
end;
implementation
uses ZLib,
Windows,
ShellAPI;
var//指示当前操作,是压缩还是解压缩
isForCompress:Boolean;
procedure TEnStore.CompressEc(AFileName:string);
var
memSrc,memDst :TMemoryStream;
[red]compressStream:TCompressionStream;[/red]
FileSize,fileVersion:Int64;
begin
//备份覆盖掉已经存在的文件
isForCompress :=True;
BackupEc(AFileName);
memSrc :=TMemoryStream.Create;
memDst :=TMemoryStream.Create;
try
memSrc.LoadFromFile(AFileName);
//校验
fileVersion :=SizeOf(TEnStoreHead);
fileVersion :=(fileVersion shl 32) or STORE_VER;
memSrc.ReadBuffer(FileSize,SizeOf(FileSize));
if FileSize<>fileVersion then//不是正常文件,拒绝压缩
Exit;
memSrc.Seek(0,soFromBeginning);
FileSize :=memSrc.Size;
compressStream :=TCompressionStream.Create(clFastest,memDst);
try
ShowProgress(Self,sptStart,SetProgressValue(FileSize,0,0));
compressStream.OnProgress :=OnCompressDecompress;
memSrc.Seek(0,soFromBeginning);
compressStream.CopyFrom(memSrc,memSrc.Size);
finally
compressStream.Destroy;
end;
memSrc.Clear;
memSrc.Write(FileSize,sizeof(FileSize));//保存原始文件大小
memDst.Seek(0,soFromBeginning);
memSrc.CopyFrom(memDst,memDst.Size);//保存压缩后的流
memSrc.Seek(0,soFromBeginning);//复位文件指针。
memSrc.SaveToFile(AFileName); //保存到新文件
finally
memSrc.Destroy;
memDst.Destroy;
end;
end;
//创建这个类之前,首先将Ec文件解压缩。
procedure TEnStore.DeCompressEc(AFileName:string);
var
memSrc:TMemoryStream;
DecompressStream:TDecompressionStream;
FileSize,fileVersion:Int64;
bufChar;
begin
//覆盖掉已经存在的文件
isForCompress :=False;
BackupEc(AFileName);
if FileExists(AFileName) then//文件必须首先存在,才能判断是否解压缩。
begin
memSrc :=TMemoryStream.Create;
try
memSrc.LoadFromFile(AFileName);
memSrc.ReadBuffer(FileSize,SizeOf(FileSize));
fileVersion :=SizeOf(TEnStoreHead);
fileVersion :=(fileVersion shl 32) or STORE_VER;
if FileSize=fileVersion then//上一次是非正常退出了,于是不再解压缩
Exit;
GetMem(buf,FileSize);
DecompressStream :=TDecompressionStream.Create(memSrc);
try
ShowProgress(Self,sptStart,SetProgressValue(FileSize,0,0));
DecompressStream.OnProgress :=OnCompressDecompress;
DecompressStream.ReadBuffer(buf^,FileSize);
memSrc.Clear;
memSrc.WriteBuffer(buf^,FileSize);
memSrc.Seek(0,soFromBeginning);
memSrc.SaveToFile(AFileName);
finally
FreeMem(buf);
DecompressStream.Destroy;
end;
finally
memSrc.Destroy;
end;
end;
end;
//压缩与解压缩的进度指示,2005-10-7
procedure TEnStore.OnCompressDecompress(Sender:TObject);
var hint:string;
begin//如此能够不断的刷新进度耗时,来产生这无法准确估计的进度提示
if isForCompress then hint:='压缩...'
else hint:='解压缩...';
ShowProgress(Self,sptEnd,SetProgressValue(0,0,0,hint));
end;
//------------------------------------------------------------------------------
constructor TEnStore.Create(const AFileName:string;isDefault:Boolean);
//仅仅为了导入另一个词库
begin
FStoreName :=AFileName;
DeCompressEc(FStoreName);
if not FileExists(FStoreName) then
begin
//创建 或 使用 默认词库文件
if isDefault then
begin
FStoreName :=strAppPath +strDefaultStoreFile;
if not FileExists(FStoreName) then
FEnLib :=TFileStream.Create(FStoreName,fmCreate)
else begin
FEnLib :=TFileStream.Create(FStoreName,fmOpenReadWrite+fmShareDenyWrite);
InitEnLib;
end;
end
else
FEnLib :=TFileStream.Create(FStoreName,fmCreate)
end
else begin
FEnLib :=TFileStream.Create(FStoreName,fmOpenReadWrite+fmShareDenyWrite);
InitEnLib;
end;
end;
destructor TEnStore.Destroy;
begin
FEnLib.Destroy;
CompressEc(FStoreName);
end;
type EStoreInValid=class(Exception);
procedure TEnStore.Prepare;//移动到数据开始位置
begin
if FEnLib<>nil then
FEnLib.Seek(Sizeof(FHead),soBeginning)
else
raise EStoreInValid.Create('严重错误:文件未正常打开');
end;
type EStoreVerFail=class(Exception);
procedure TEnStore.InitEnLib;//读出文件信息,并读出文件大小。
begin
FEnLib.Seek(0,soBeginning);
if Sizeof(FHead)<>FEnLib.Read(FHead,Sizeof(FHead)) then
raise EStoreVerFail.Create('单词库系统信息读取出错!');
//Check Version
if FHead.Version<>STORE_VER then raise EStoreVerFail.Create('单词库版本号不对!');
//读取文件大小
FStoreSize :=FEnLib.Seek(0,soEnd);
end;
{*
2005-4-1已能够正常读取单词
}
type EGetWordException=class(Exception);
procedure TEnStore.GetOneWord(AEnWordEnWord);
var
//len:Word;
len:Integer;//2005-9-28,升级数据库,单个Chunk长度改为4字节
i :Integer;
pt QueryEnWordTime;
cache:array of Char;
// pInt Integer;
theStrLen:Integer;
pStrStart,pCacheChar;
// ,pStr Char;
// pDbl Double;
begin
//FEnLib.Read(len,2);
if FEnLib.Position>=FStoreSize then raise EGetWordException.Create('读文件已经越界!');
FEnLib.Read(len,4);//2005-9-28,本着先写再读的原则来升级数据库
if len<5 then raise EGetWordException.Create('读单词出错,Chunk长度值太小!');
FEnLib.Read(AEnWord^.Verdancy,1);
if AEnWord^.Verdancy>0 then
begin
// Setlength(cache,8*AEnWord^.Verdancy);
// FEnLib.Read(cache[0],8*AEnWord^.Verdancy);
// pCache :=@cache[0];
//构造时间序列链表
i :=AEnWord^.Verdancy;
pt:=@(AEnWord^.LastTime);
pt^.qPre :=nil;
repeat
FEnLib.Read(pt^.qTime,8);
Dec(i);
if i<=0 then Break;
New(pt^.qPre);
pt :=pt^.qPre;
pt^.qPre :=nil;
until i=0;
end
else begin
AEnWord^.LastTime.qTime :=Now();
AEnWord^.LastTime.qPre :=nil;
end;
if len<(5+8*AEnWord^.Verdancy) then raise EGetWordException.Create('读单词出错,Chunk长度不对!');
Setlength(cache,len -5-8*AEnWord^.Verdancy);
FEnLib.Read(cache[0],len-5-8*AEnWord^.Verdancy);
pCache :=@cache[0];
with AEnWord^ do
try
i :=0;
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Word,pStrStart,theStrLen);
//{$define RtfDebug2005-9-28}
{$ifDef RtfDebug2005-9-28}
//if pNode^.EnWord.Word='entail' then log(CacheStr,cstrLogTxt);
{$endif}
Inc(i);
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Phonetic,pStrStart,theStrLen);
Inc(i);
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Explanation,pStrStart,theStrLen);
Inc(i);//2005-9-8,增加“附注”
theStrLen :=0;
pStrStart :=@(pCache);
while pCache<>#0 do
begin
Inc(theStrLen);
Inc(i);
end;
SetString(Comment,pStrStart,theStrLen);
finally
// pCache :=nil;
end;
// Integer(pInt) :=Integer(pCache);
// pStr :=@pCache[4];
// SetString(Word,pStr,pInt^);
//
// Inc(pCache,pInt^+4);
// Integer(pInt) :=Integer(pCache);
// Integer(pStr) :=Integer(@pCache[4]);
// SetString(Phonetic,pStr,pInt^);
//
// Inc(pCache,4+pInt^);
// Integer(pInt) :=Integer(pCache);
// Integer(pStr) :=Integer(@pCache[4]);
// SetString(Explanation,pStr,pInt^);
//
// //读出附注,根据压缩否来确定是否解压缩
// Inc(pCache,4+pInt^);
// Integer(pInt) :=Integer(pCache);
// Accessory.Size:=pInt^;
// Integer(pInt) :=Integer(@pCache[4]);
// Accessory.genre:=pInt^;
// if Accessory.genre=Integer(agNone) then//未压缩
// begin
// Integer(pStr) :=Integer(@pCache[8]);
// SetString(Comment,pStr,Accessory.Size)
// end
// else begin
// end;
// finally
// cache :=nil;
// pCache:=nil;
// end;
end;
//压缩存储。
//procedure TEnStore.CompressTo(AComment:string;ACacheChar);
//var
// StreamCompress:TCompressionStream;
// StreamStr :TStringStream;
// StreamMem :TMemoryStream;
//begin
// StreamStr :=TStringStream.Create(AComment);
// StreamMem :=TMemoryStream.Create;
// try
// StreamCompress :=TCompressionStream.Create(clFastest,StreamMem);
// try
// StreamCompress.CopyFrom(StreamStr,StreamStr.Size);
// finally
// StreamCompress.Destroy;
// end;
// StreamMem.Seek(0,soFromBeginning);
// StreamMem.SaveToFile('zlibtest.bin');
// StreamMem.Seek(0,soFromBeginning);
// StreamMem.ReadBuffer(ACache,StreamMem.Size);
// finally
// StreamStr.Destroy;
// StreamMem.Destroy;
// end;
//end;
//procedure TEnStore.DeCompressFrom(var AComment:string;ACacheChar);
//begin
//end;
//保存单词使用的缓冲区指针
var cache Char;
procedure TEnStore.SaveWord(AEnWordEnWord);//第一个单词节点
procedure SaveIt;
var
xt:Cardinal;
//yt:^Word;//2005-9-28,16K的大小已经不能够正确读出数据,不过如下算法倒是能够正常写入,就是这个总长度会被截断!
yt :^Cardinal;//pInt
pCacheChar;//pComment
wLen,pLen,eLen,cLen:Cardinal;//单词长、音标长、解释长、附注长
procedure SaveQueryTimes(const pTimeNodeQueryEnWordTime;ACacheChar);//递归实现时间链表反序遍历存储。
var
pTime Double;
begin
if pTimeNode^.qPre<>nil then
begin
Integer(pCache) :=Integer(ACache) +sizeof(double);
SaveQueryTimes(pTimeNode^.qPre,pCache);
Integer(pTime) :=Integer(ACache);
pTime^ :=pTimeNode^.qTime;
end
else begin
Integer(pTime) :=Integer(ACache);
pTime^ :=pTimeNode^.qTime;
end;
end;
begin
//计算本单词占用长度
Integer(yt) :=Integer(Cache);
pCache :=Cache;
with AEnWord^ do
begin
wLen :=Length(Word);
pLen :=Length(Phonetic);
eLen :=Length(Explanation);
cLen :=Length(Comment);
// yt^ :=5 +Verdancy *sizeof(Double)
// + wLen+1 + pLen+1 +eLen+1 +cLen+1;//2005-9-8
Inc(pCache,4);//因为Cardinal占用了4字节
Byte(pCache^):=Verdancy;//陌生度
inc(pCache,1);
if Verdancy>0 then//被删除的单词仅把陌生度记为0,不保存时间序列
SaveQueryTimes(@(LastTime),pCache);//逆序方式保存时间序列
xt :=5+Verdancy *sizeof(Double);//单词
pCache :=Cache;
inc(pCache,xt);//绝对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=wLen;//保存单词的长度
// inc(pCache,4);
StrCopy(pCache,PAnsiChar(Word));//保存单词
pCache[wLen] :=#0;
xt :=xt +1+wLen;//音标
inc(pCache,1+wLen);//相对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=pLen;//保存单词的长度
// inc(pCache,4);
DTrimRight(Phonetic);//2005-10-16添加
StrCopy(pCache,PAnsiChar(Phonetic));
pCache[plen] :=#0;
xt :=xt +1+plen;//解释
inc(pCache,1+plen);//相对偏移
// Integer(pInt) :=Integer(pCache);
// pInt^:=eLen;//保存单词的长度
// inc(pCache,4);
StrCopy(pCache,PAnsiChar(Explanation));
pCache[elen] :=#0;
xt :=xt +1+elen;//附注,2005-9-8
if (xt +8+clen)<nOneChunkMaxLength then//否则不予存储!
begin//为了确保未超过限度值,2005-9-9
inc(pCache,1+elen);//相对偏移
//附注大于1024Kb的 就采用压缩存储
// FillChar(Accessory,SizeOf(Accessory),0);
// if cLen>1024 *1024 then
// begin
// pComment :=pCache;
// Inc(pCache,8);//后移8个字节,给Accessory 留出存储空间
// CompressBuf(PChar(Comment),cLen,Pointer(pCache),Accessory.Size);
// xt :=xt + 8+Accessory.Size;//总长度
// //写入类型
// Integer(pInt) :=Integer(pComment);
// pInt^ :=Accessory.Size;//Accessory.Size :=0;
// Integer(pInt) :=Integer(@pComment[4]);
// pInt^ :=Integer(agMem);//Accessory.Genre :=Integer(agMem);
// end
// else
// begin
// Integer(pInt) :=Integer(pCache);
// pInt^ :=0;//Accessory.Size :=0;
// Integer(pInt) :=Integer(pCache)+4;
// pInt^ :=Integer(agNone);//Accessory.Genre :=Integer(agNone);
// Inc(pCache,8);
StrCopy(pCache,PAnsiChar(Comment));
pCache[clen] :=#0;
xt :=xt + 1+clen;//总长度
// end;
end;
end;
Integer(yt) :=Integer(Cache);
yt^:=xt;
FEnLib.Write(Cache^,xt);//参数传递!非指针!2005-4-1
end;
begin
SaveIt;
Inc(FHead.ChunkTotal);
//通过音标来区分 是文章 还是单词
if not CheckIsArticle(AEnWord)then//是单词,不是文章
Inc(FHead.WordsTotal);
end;
procedure TEnStore.StartSaveWords;//申请内存缓冲
begin
GetMem(Cache,nOneChunkMaxLength);
FHead.ChunkTotal :=0;
FHead.WordsTotal :=0;
end;
procedure TEnStore.EndSaveWords;//释放内存缓冲
begin
FreeMem(Cache);
//必须确认已经保存数据库完毕
SetEndOfFile(FEnLib.Handle);//抛弃多余的部分,此时当保证Position位置的正确性
end;
procedure TEnStore.SaveHead;
begin
FHead.Version :=STORE_VER;
FHead.DataPos :=sizeof(FHead);
FHead.CRC32:=$78787878;
FEnLib.Seek(0,soBeginning);
FEnLib.Write(FHead,sizeof(FHead));
end;
end.