项目迭代开发手记--文件分割存储用例的实现过程(3)

2016-02-19 14:17 3 1 收藏

清醒时做事,糊涂时读书,大怒时睡觉,无聊时关注图老师为大家准备的精彩内容。下面为大家推荐项目迭代开发手记--文件分割存储用例的实现过程(3),无聊中的都看过来。

【 tulaoshi.com - 编程语言 】

项目迭代开发手记--文件分割存储用例的实现过程(3)       上午的迭代2完成后,我们获得了一个有完整压缩流功能的实现代码,这次迭代完成的代码是可用的,我们在迭代2中完成了我们既定的任务。在下午的小组讨论中,我们继续考虑下一阶段的迭代目标,由于没有决定图档文件的格式,我们决定先不考虑图片格式的问题,先实现文件的分割功能。文件的分割主要是考虑当图档文件太大的时,数据库提交性能会变得非常慢,分割的目的就是改进提交的性能。迭代3:对向数据库提交的二进制流进行分割压缩;那么从数据库提取的时候要进行解压和拼接操作,以获得原始图档数据。在分割功能的设计和编码前,我们重新审视了上午的代码——那个压缩类TLoadBinaryDataToDB,发觉该类似乎职责太多,它要负责把文件装载成流,然后才对流进行压缩和解压缩,我们发现UnCompressStream函数有更好的通用性,只要是压缩的流就可以对其进行解压。而压缩功能在这个类里似乎只能对通过文件装载的流进行压缩,如果流是以另一种形式获得的,不是以文件装载的形式,那么我们不知道该如何对该流进行压缩。这里似乎违背了功能单一的职责,类既负责了流的装载,又负责流的压缩;于是我们对该类进行了重构已获得结构更好的的类,以增加类的重用性。重构后的类只有两个公用的方法 CompressStream 和 UnCompressStream 它们都已流为参数,通过对传入流的处理来实现压缩和解压缩功能。 procedure TCompressStream.CompressStream(var stream: TMemoryStream);var  iSize: Integer;  lDestStream: TMemoryStream;  lCompressionStream: TCompressionStream;begin  lDestStream := TMemoryStream.Create;  lCompressionStream := TCompressionStream.Create(clMax, lDestStream);  try    iSize := stream.Size; //获得图像流的原始尺寸stream.SaveToStream(lCompressionStream); //将原始图像流进行压缩,// lDestStream中保存着压缩后的图像流    lCompressionStream.Free;    stream.Clear;    stream.WriteBuffer(iSize, SizeOf(iSize)); //写入原始图像的尺寸    stream.CopyFrom(lDestStream, 0); //写入经过压缩的图像流  finally    lDestStream.Free  end;end; 解压缩函数procedure TCompressStream.UnCompressStream(var stream: TMemoryStream);var  DecompressionStream: TDecompressionStream;  Buffer: PChar;  Count: Integer;begin  stream.ReadBuffer(Count, SizeOf(Count));   GetMem(Buffer, Count); //根据图像尺寸大小为将要读入的原始图像流分配内存块  DecompressionStream := TDecompressionStream.Create(stream);  tryDecompressionStream.ReadBuffer(Buffer^, Count); //将被压缩的图像流解压缩,//然后存入 Buffer内存块中    stream.Clear;    stream.WriteBuffer(Buffer^, Count); //将原始图像流保存至 stream流中    stream.Position := 0;  finally    FreeMem(Buffer); // 释放内存  end;end;经过重构后,类TCompressStream无疑提高了重用性,同时有更好的结构。除去了把文件装载成流的功能后,TCompressStream职责变得更单一了。它对已任何形式获得得的流都可以进行压缩和解压缩。完成TLoadBinaryDataToDB重构我们开始考虑对流进行分割功能的实现。在假定一个流被分割成5份,那么拼接时就要有一个顺序我们考虑在数据库增加一个顺序的字段来保存流各个块之间的分割顺序。字段名字段类型字段长度字段说明 FIDNumber 主键 F_NAMEVarChar250文件名称 F_SERIALNumber 文件分割顺序号 F_BINARY_DATALong Row 二进制数据 同样我们考虑把这个功能封装在一个类里面。我们实现了一个叫TStreamIncise的类,在设计这个类时,我们为了更好的增加对这类要设计成什么样子进行了很好的讨论,首先我们模拟了如何使用该类。   for I := 0 to IncisedCount - 1 do    begin      StreamIncise.GetInciseStream(lStream); //获得分割流      ClientDataSet2.Append;      ClientDataSet2.FieldByName('F_ID').Value := I; //取序列号      ClientDataSet2.FieldByName('F_NAME').Value := FFileFullName;      ClientDataSet2.FieldByName('F_SERIAL').Value := I; // 取每次分割的序列号      lCompressionStream.CompressStream(lStream);      (ClientDataSet2.FieldByName('F_BINARY_DATA') as TBlobField).LoadFromStream(lStream);      ClientDataSet2.Post;end;我们用代码估计了类的调用方式,通过这样的模拟代码我们获得了以下信息1)               要获得文件的被分割数,就是说如果使用上面的模拟代码,我们必须先获得流的分割数。2)               TStreamIncise流在执行前先获得要处理流,同时设定分割块的大小。 我们用FInciseSize 来保存分割快的大小值,FStreamSize 保存流的大小值,FRemainSize保存每次分割后的剩余值。FInciseSize 在初始化函数 Create 中初始化。FInciseSize := 50000; //设置分割的大小 LoadFromStream 把原始的流装载过来。procedure TStreamIncise.LoadFromStream(stream: TMemoryStream);begin  FMemoryStream := stream; // 保存一个流的引用  FStreamSize := stream.Size;  FRemainSize := FStreamSize;end; GetIncisedCount 获得装载的原始流要被分割的数量。function TStreamIncise.GetIncisedCount: Integer;begin  Result := FStreamSize div FInciseSize + 1;end;SetStreamDefault 用来把获得流设置到初始位置。procedure TStreamIncise.SetStreamDefault;begin  if Assigned(FMemoryStream) then  FMemoryStream.Position :=0;end; 核心的函数是GetInciseStream 通过调用它用户获得分割好后的流。 procedure TStreamIncise.GetInciseStream(inciseStream: TMemoryStream);var  iMaxError: Integer;  Count: Integer;  Buffer: PChar;begin  Count := GetBufferCount;  GetMem(Buffer, Count);  try    FMemoryStream.ReadBuffer(Buffer^, Count);    InciseStream.Clear;    inciseStream.WriteBuffer(Buffer^, Count);    InciseStream.Position := 0;    FRemainSize := FRemainSize - Count;  finally    FreeMem(Buffer);  end;end;这里GetBufferCount 每次返回分割块的大小,当剩余的流大小不够5000 时它返回剩下流的长度。function TStreamIncise.GetBufferCount: Integer;begin  Result := FInciseSize;  if FRemainSize FInciseSize then    Result := FRemainSize;end; 最终我们获得了一个可以这样调用的分割类:procedure TForm1.Button8Click(Sender: TObject);var  StreamIncise: TStreamIncise;  I: Integer;  lStream: TMemoryStream;  lCompressionStream: TCompressStream;begin  StreamIncise := TStreamIncise.Create;  lStream := TMemoryStream.Create;  lCompressionStream := TCompressStream.Create;  StreamIncise.LoadFromStream(FStream);  StreamIncise.SetStreamDefault;  try    for I := 0 to StreamIncise.IncisedCount - 1 do    begin      StreamIncise.GetInciseStream(lStream); //获得分割流      ClientDataSet2.Append;      ClientDataSet2.FieldByName('F_ID').Value := I; //取序列号      ClientDataSet2.FieldByName('F_NAME').Value := FFileFullName;      ClientDataSet2.FieldByName('F_SERIAL').Value := I; // 取每次分割的序列号      lCompressionStream.CompressStream(lStream);      (ClientDataSet2.FieldByName('F_BINARY_DATA') as TBlobField).LoadFromStream(lStream);      ClientDataSet2.Post;    end;  finally    StreamIncise.Free;    lStream.Free;    lCompressionStream.Free;  end;end;最后我们增加了InciseSize 属性,让程序员在创建类以后可以自己修改分割块的大小。通过这样的调用,我们就可以把分割类具体的保存业务的耦合解开,从而增加了分割类下次被重用的可能性。在查阅资料过程中我们也找到一些分割的例子,只是都跟具体的业务耦合得很紧密,要重用该代码除了粘贴复制以外基本上没有他法。
  
  这样当迭代3完成的时候我们实现了对了流的分割压缩,文件分割存储用例到这里获得一个好的解决方案,通过小步的迭代前进我们可以在每一次迭代结束的时候获得可以使用的功能代码,剩下来就使考虑图档文件的格式问题了。其实更主要的通过这次开发我们让新加入的组员获得了一次很好的编程培训,更容易理解要实现一个功能的具体思路和步骤。

来源:http://www.tulaoshi.com/n/20160219/1606654.html

延伸阅读
标签: Web开发
ASP开发中存储过程应用详解|调用,参数,存储,数据库,输出,编译,mycomm,输入,userid,代码 ASP与存储过程(Stored Procedures)的文章不少,但是我怀疑作者们是否真正实践过。我在初学时查阅过大量相关资料,发现其中提供的很多方法实际操作起来并不是那么回事。对于简单的应用,这些资料也许是有帮助的,但仅限于此,因为它们根本就是千篇...
    立项是软件开发的首要步骤,但常常被开发者轻视。立项主要目的是开发正确的产品,是软件开发成功的第一前提。“良好的开端是成功的一半”,那么错误的开端将是什么样的结局呢?结果可想而知了。我在立项过程中很多思想来源于林锐先生的“软件工程与项目管理解析”一书,在此向我的偶像表示敬意。 一、产品构思、立项调查与形...
标签: Web开发
     我不是一个很有经验的程序员,在做项目的过程中会遇到很多的问题,在数据库中使用分页就是我做项目中遇到的一个问题.我从网上查了很多资料,有很多种方法.但我觉的创建临时数据表是最简单的方法,在我做Membership扩展时发现原来微软也是这样用的,你可一随便打开一个Membership的存储过程看看.    &nbs...
    人们常问:“需求、设计、编程、测试四者究竟哪个重要?” 这个问题不好回答。四者都是软件开发过程中必不可少的环节,光做好其中一个环节并不能产生好的系统,但是做坏了其中任何一个环节,必定对系统产生坏的影响。若站在风险管理的角度讲,也许需求开发与管理是最重要的环节。因为需求是产品的根源,对产品需求的认识是...
    当立项建议经评审通过后,软件公司的机构领导接着会任命项目经理,由项目经理去筹备项目。财务部门、人力资源部门为新团队的组建提供必要的财力和人力资源。 作为以合作的形式开发共享软件,人力和财力的筹备就成为项目组织者一个人要操心的事了。粗略计算一下如果以聘用的形式组建开发团队,普通成员需3人,每人每月工资200...

经验教程

889

收藏

13
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部