热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

项目迭代开发手记--文件分割存储用例的实现过程(3)上午的迭代2完成后,我们获得了一个有完整压缩流功能的实现代码,这次迭代完成的代码是可用的,我们在迭代2中完成了我们既定的任务。在下午的

项目迭代开发手记--文件分割存储用例的实现过程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);

  try

DecompressionStream.ReadBuffer(Buffer^, Count); //将被压缩的图像流解压缩,

//然后存入 Buffer内存块中

    stream.Clear;

    stream.WriteBuffer(Buffer^, Count); //将原始图像流保存至 stream流中

    stream.Position := 0;

  finally

    FreeMem(Buffer); // 释放内存

  end;

end;

经过重构后,类TCompressStream无疑提高了重用性,同时有更好的结构。除去了把文件装载成流的功能后,TCompressStream职责变得更单一了。它对已任何形式获得得的流都可以进行压缩和解压缩。完成TLoadBinaryDataToDB重构我们开始考虑对流进行分割功能的实现。

在假定一个流被分割成5份,那么拼接时就要有一个顺序我们考虑在数据库增加一个顺序的字段来保存流各个块之间的分割顺序。

字段名

字段类型

字段长度

字段说明

 

FID

Number

 

主键

 

F_NAME

VarChar2

50

文件名称

 

F_SERIAL

Number

 

文件分割顺序号

 

F_BINARY_DATA

Long 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

    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完成的时候我们实现了对了流的分割压缩,文件分割存储用例到这里获得一个好的解决方案,通过小步的迭代前进我们可以在每一次迭代结束的时候获得可以使用的功能代码,剩下来就使考虑图档文件的格式问题了。其实更主要的通过这次开发我们让新加入的组员获得了一次很好的编程培训,更容易理解要实现一个功能的具体思路和步骤。


推荐阅读
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • 如何撰写适应变化的高效代码:策略与实践
    编写高质量且适应变化的代码是每位程序员的追求。优质代码的关键在于其可维护性和可扩展性。本文将从面向对象编程的角度出发,探讨实现这一目标的具体策略与实践方法,帮助开发者提升代码效率和灵活性。 ... [详细]
  • 深入探索HTTP协议的学习与实践
    在初次访问某个网站时,由于本地没有缓存,服务器会返回一个200状态码的响应,并在响应头中设置Etag和Last-Modified等缓存控制字段。这些字段用于后续请求时验证资源是否已更新,从而提高页面加载速度和减少带宽消耗。本文将深入探讨HTTP缓存机制及其在实际应用中的优化策略,帮助读者更好地理解和运用HTTP协议。 ... [详细]
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 在试用版软件中,为了提升用户体验并有效提醒用户剩余的使用次数,本文通过Java IO文件操作实现了一个试用版软件的使用次数提示机制。具体而言,每次启动软件时,程序会读取存储在文件中的剩余使用次数,并在每次执行后更新该数值。当用户启动软件时,系统会显示当前剩余的使用次数,确保用户清楚了解自己的试用状态。该机制不仅提高了软件的友好性,还增强了用户的购买意愿。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 利用 fopen、fwrite、fread、fseek 和 fclose 实现文件中整型数据的读写操作 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
author-avatar
善良历史代言人_749
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有