国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

項(xiàng)目迭代開發(fā)手記--文件分割存儲(chǔ)用例的實(shí)現(xiàn)過程(3)

2019-11-18 18:13:18
字體:
供稿:網(wǎng)友
項(xiàng)目迭代開發(fā)手記--文件分割存儲(chǔ)用例的實(shí)現(xiàn)過程(3)
      
上午的迭代2完成后,我們獲得了一個(gè)有完整壓縮流功能的實(shí)現(xiàn)代碼,這次迭代完成的代碼是可用的,我們?cè)诘?中完成了我們既定的任務(wù)。在下午的小組討論中,我們繼續(xù)考慮下一階段的迭代目標(biāo),由于沒有決定圖檔文件的格式,我們決定先不考慮圖片格式的問題,先實(shí)現(xiàn)文件的分割功能。文件的分割主要是考慮當(dāng)圖檔文件太大的時(shí),數(shù)據(jù)庫提交性能會(huì)變得非常慢,分割的目的就是改進(jìn)提交的性能。
迭代3:
對(duì)向數(shù)據(jù)庫提交的二進(jìn)制流進(jìn)行分割壓縮;那么從數(shù)據(jù)庫提取的時(shí)候要進(jìn)行解壓和拼接操作,以獲得原始圖檔數(shù)據(jù)。
在分割功能的設(shè)計(jì)和編碼前,我們重新審視了上午的代碼——那個(gè)壓縮類TLoadBinaryDataToDB,發(fā)覺該類似乎職責(zé)太多,它要負(fù)責(zé)把文件裝載成流,然后才對(duì)流進(jìn)行壓縮和解壓縮,我們發(fā)現(xiàn)UnComPRessStream函數(shù)有更好的通用性,只要是壓縮的流就可以對(duì)其進(jìn)行解壓。而壓縮功能在這個(gè)類里似乎只能對(duì)通過文件裝載的流進(jìn)行壓縮,如果流是以另一種形式獲得的,不是以文件裝載的形式,那么我們不知道該如何對(duì)該流進(jìn)行壓縮。這里似乎違背了功能單一的職責(zé),類既負(fù)責(zé)了流的裝載,又負(fù)責(zé)流的壓縮;于是我們對(duì)該類進(jìn)行了重構(gòu)已獲得結(jié)構(gòu)更好的的類,以增加類的重用性。
重構(gòu)后的類只有兩個(gè)公用的方法 CompressStream 和 UnCompressStream 它們都已流為參數(shù),通過對(duì)傳入流的處理來實(shí)現(xiàn)壓縮和解壓縮功能。
 
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); //將原始圖像流進(jìn)行壓縮,
// lDestStream中保存著壓縮后的圖像流
    lCompressionStream.Free;
    stream.Clear;
    stream.WriteBuffer(iSize, SizeOf(iSize)); //寫入原始圖像的尺寸
    stream.CopyFrom(lDestStream, 0); //寫入經(jīng)過壓縮的圖像流
  finally
    lDestStream.Free
  end;
end;
 
解壓縮函數(shù)
procedure TCompressStream.UnCompressStream(var stream: TMemoryStream);
var
  DecompressionStream: TDecompressionStream;
  Buffer: PChar;
  Count: Integer;
begin
  stream.ReadBuffer(Count, SizeOf(Count));
  GetMem(Buffer, Count); //根據(jù)圖像尺寸大小為將要讀入的原始圖像流分配內(nèi)存塊
  DecompressionStream := TDecompressionStream.Create(stream);
  try
DecompressionStream.ReadBuffer(Buffer^, Count); //將被壓縮的圖像流解壓縮,
//然后存入 Buffer內(nèi)存塊中
    stream.Clear;
    stream.WriteBuffer(Buffer^, Count); //將原始圖像流保存至 stream流中
    stream.Position := 0;
  finally
    FreeMem(Buffer); // 釋放內(nèi)存
  end;
end;
經(jīng)過重構(gòu)后,類TCompressStream無疑提高了重用性,同時(shí)有更好的結(jié)構(gòu)。除去了把文件裝載成流的功能后,TCompressStream職責(zé)變得更單一了。它對(duì)已任何形式獲得得的流都可以進(jìn)行壓縮和解壓縮。完成TLoadBinaryDataToDB重構(gòu)我們開始考慮對(duì)流進(jìn)行分割功能的實(shí)現(xiàn)。
在假定一個(gè)流被分割成5份,那么拼接時(shí)就要有一個(gè)順序我們考慮在數(shù)據(jù)庫增加一個(gè)順序的字段來保存流各個(gè)塊之間的分割順序。
字段名
字段類型
字段長度
字段說明
 
FID
Number
 
主鍵
 
F_NAME
VarChar2
50
文件名稱
 
F_SERIAL
Number
 
文件分割順序號(hào)
 
F_BINARY_DATA
Long Row
 
二進(jìn)制數(shù)據(jù)
 
同樣我們考慮把這個(gè)功能封裝在一個(gè)類里面。我們實(shí)現(xiàn)了一個(gè)叫TStreamIncise的類,在設(shè)計(jì)這個(gè)類時(shí),我們?yōu)榱烁玫脑黾訉?duì)這類要設(shè)計(jì)成什么樣子進(jìn)行了很好的討論,首先我們模擬了如何使用該類。
 
  for I := 0 to IncisedCount - 1 do
    begin
      StreamIncise.GetInciseStream(lStream); //獲得分割流
      ClientDataSet2.Append;
      ClientDataSet2.FieldByName('F_ID').Value := I; //取序列號(hào)
      ClientDataSet2.FieldByName('F_NAME').Value := FFileFullName;
      ClientDataSet2.FieldByName('F_SERIAL').Value := I; // 取每次分割的序列號(hào)
      lCompressionStream.CompressStream(lStream);
      (ClientDataSet2.FieldByName('F_BINARY_DATA')
 as TBlobField).LoadFromStream(lStream);
      ClientDataSet2.Post;
end;
我們用代碼估計(jì)了類的調(diào)用方式,通過這樣的模擬代碼我們獲得了以下信息
1)               要獲得文件的被分割數(shù),就是說如果使用上面的模擬代碼,我們必須先獲得流的分割數(shù)。
2)               TStreamIncise流在執(zhí)行前先獲得要處理流,同時(shí)設(shè)定分割塊的大小。
 
我們用FInciseSize 來保存分割快的大小值,F(xiàn)StreamSize 保存流的大小值,F(xiàn)RemainSize保存每次分割后的剩余值。FInciseSize 在初始化函數(shù) Create 中初始化。
FInciseSize := 50000; //設(shè)置分割的大小
 
LoadFromStream 把原始的流裝載過來。
procedure TStreamIncise.LoadFromStream(stream: TMemoryStream);
begin
  FMemoryStream := stream; // 保存一個(gè)流的引用
  FStreamSize := stream.Size;
  FRemainSize := FStreamSize;
end;
 
GetIncisedCount 獲得裝載的原始流要被分割的數(shù)量。
function TStreamIncise.GetIncisedCount: Integer;
begin
  Result := FStreamSize div FInciseSize + 1;
end;
SetStreamDefault 用來把獲得流設(shè)置到初始位置。
procedure TStreamIncise.SetStreamDefault;
begin
  if Assigned(FMemoryStream) then  FMemoryStream.Position :=0;
end;
 
核心的函數(shù)是GetInciseStream 通過調(diào)用它用戶獲得分割好后的流。
 
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 每次返回分割塊的大小,當(dāng)剩余的流大小不夠5000 時(shí)它返回剩下流的長度。
function TStreamIncise.GetBufferCount: Integer;
begin
  Result := FInciseSize;
  if FRemainSize < FInciseSize then
    Result := FRemainSize;
end;
 
最終我們獲得了一個(gè)可以這樣調(diào)用的分割類:
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; //取序列號(hào)
      ClientDataSet2.FieldByName('F_NAME').Value := FFileFullName;
      ClientDataSet2.FieldByName('F_SERIAL').Value := I; // 取每次分割的序列號(hào)
      lCompressionStream.CompressStream(lStream);
      (ClientDataSet2.FieldByName('F_BINARY_DATA')
 as TBlobField).LoadFromStream(lStream);
      ClientDataSet2.Post;
    end;
  finally
    StreamIncise.Free;
    lStream.Free;
    lCompressionStream.Free;
  end;
end;
最后我們?cè)黾恿薎nciseSize 屬性,讓程序員在創(chuàng)建類以后可以自己修改分割塊的大小。
通過這樣的調(diào)用,我們就可以把分割類具體的保存業(yè)務(wù)的耦合解開,從而增加了分割類下次被重用的可能性。在查閱資料過程中我們也找到一些分割的例子,只是都跟具體的業(yè)務(wù)耦合得很緊密,要重用該代碼除了粘貼復(fù)制以外基本上沒有他法。

這樣當(dāng)?shù)?完成的時(shí)候我們實(shí)現(xiàn)了對(duì)了流的分割壓縮,文件分割存儲(chǔ)用例到這里獲得一個(gè)好的解決方案,通過小步的迭代前進(jìn)我們可以在每一次迭代結(jié)束的時(shí)候獲得可以使用的功能代碼,剩下來就使考慮圖檔文件的格式問題了。其實(shí)更主要的通過這次開發(fā)我們讓新加入的組員獲得了一次很好的編程培訓(xùn),更容易理解要實(shí)現(xiàn)一個(gè)功能的具體思路和步驟。

上一篇:兩個(gè)字符串分割函數(shù)引出的奇怪問題

下一篇:抓屏技巧二三例

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 萨嘎县| 嘉祥县| 奈曼旗| 奉化市| 桐柏县| 百色市| 高邑县| 裕民县| 囊谦县| 九龙城区| 仁化县| 双江| 措勤县| 元氏县| 五寨县| 启东市| 台江县| 维西| 泸水县| 孟津县| 延吉市| 瑞昌市| 太仆寺旗| 平罗县| 赫章县| 阿巴嘎旗| 高密市| 湖口县| 佛冈县| 南京市| 镇远县| 印江| 陆丰市| 鄯善县| 嘉善县| 莱阳市| 和顺县| 台北县| 百色市| 盐山县| 广元市|