检查Zip文件的有效性

时间:2014-01-24 16:17:46

标签: delphi

当我尝试检查zip文件的有效性时,会引发一个异常,即该进程无法访问该文件,因为它正由另一个进程使用,但Open1.Click中的代码打开zip文件没有问题。 Valid1Click有什么问题吗?

procedure TForm1.Valid1Click(Sender: TObject);
{ Is the zip file valid. }
var
  iZipFile: TZipFile;
  iZipFilename: string;
  iValid: Boolean;
begin
  Screen.Cursor := crHourGlass;
  try
    { Create the TZipFile Class }
    iZipFile := TZipFile.Create;
    try
      if FileExists(ZipFilename1.Text) then
      begin
         iZipFilename := ZipFilename1.Text;
         { Open zip file for reading }
         iZipFile.Open(iZipFilename, zmRead);
         iValid := iZipFile.IsValid(iZipFilename);
         if iValid then
           MessageBox(0, 'The zip file is valid.', 'Check Zip File',
             MB_ICONINFORMATION or MB_OK)
         else
           MessageBox(0, 'The zip file is NOT valid.', 'Check Zip File',
              MB_ICONWARNING or MB_OK);
         end
         else
            begin
              MessageBox(0, 'The zip file does not exist.', 'Warning',
                MB_ICONWARNING or MB_OK);
            end;
         { Close the zip file }
         iZipFile.Close;
       finally
         iZipFile.Free;
       end;
     finally
        Screen.Cursor := crDefault;
     end;
end;

procedure TForm1.Open1Click(Sender: TObject);
{ Open zip file. }
var
  i: integer;
  iZipFile: TZipFile;
  iFilename: string;
  iDateTime: TDateTime;
  iCompressedSize: cardinal;
  iUnCompressedSize: cardinal;
  iCRC32: cardinal;
  iCompressionMethod: word;
  iFileComment: string;
  iListItem: TlistItem;
begin
  if OpenDialog1.Execute then
  begin
    if FileExists(OpenDialog1.FileName) then
    begin
      iZipFile := TZipFile.Create;
      try
        ListView1.Items.Clear;
        ZipFilename1.Text := OpenDialog1.FileName;
        try
          iZipFile.Open(ZipFilename1.Text, zmReadWrite);
          for i := 0 to iZipFile.FileCount - 1 do
          begin
            iFilename := iZipFile.FileNames[i];
            iListItem := ListView1.Items.Add;
            iListItem.Caption := iFilename;
            iDateTime := FileDateToDateTime
              (iZipFile.FileInfo[i].ModifiedDateTime);
            iListItem.SubItems.Add(DateTimeToStr(iDateTime)); { 0 }
            iCompressedSize := iZipFile.FileInfo[i].CompressedSize;
            iListItem.SubItems.Add(FormatByteSize(iCompressedSize)); { 1 }
            iUnCompressedSize := iZipFile.FileInfo[i].UncompressedSize;
            iListItem.SubItems.Add(FormatByteSize(iUnCompressedSize)); { 2 }
            iCRC32 := iZipFile.FileInfo[i].CRC32;
            iListItem.SubItems.Add(IntToStr(iCRC32)); { 3 }
            iCompressionMethod := iZipFile.FileInfo[i].CompressionMethod;
            iListItem.SubItems.Add
              (ZipCompressionToStr(iCompressionMethod)); { 4 }
            iFileComment := iZipFile.Comment;
            iListItem.SubItems.Add(iFileComment); { 5 }
          end;
          iZipFile.Close;
        except
          on E: Exception do
          begin
            ShowMessage(E.ClassName + #10#13 + E.Message);
          end;
        end;
      finally
        iZipFile.Free;
      end;
    end;
  end;

2 个答案:

答案 0 :(得分:3)

你有这些错误的方法:

iZipFile.Open(iZipFilename, zmRead);
iValid := iZipFile.IsValid(iZipFilename);

第一行锁定文件,因此第二行失败。在致电IsValid之前,您必须致电Open

话虽如此,由于您使用zmRead,因此IsValid的来电可能会再次打开该文件,因为对Open的调用使用了fmOpenRead。因此,我怀疑您正在使用的Delphi版本中的ZIP文件代码或文件流代码中可能存在错误。同样,在IsValid之前调用Open肯定会有效。

实际上,IsValid是一种类方法。你应该这样称呼它:

iValid := TZipFile.IsValid(iZipFilename);

最终会出现同样的问题,但是对于代码的读者来说,方法调用不依赖于实例的状态。

事实上,我个人只会取消对IsValid的电话,然后直接致电Open。如果失败,我相信会提出有意义的错误消息。


<强>更新

看起来您根本不想打开文件,只想检查其有效性。在这种情况下,您不需要实例,也不需要调用构造函数,只需使用TZipFile.IsValid一次调用。

procedure TForm1.Valid1Click(Sender: TObject);
begin
  Screen.Cursor := crHourGlass;
  try
    if FileExists(ZipFilename1.Text) then
    begin
      if TZipFile.IsValid(ZipFilename1.Text) then
        ...
  finally
    Screen.Cursor := crDefault;
  end;
end;

答案 1 :(得分:0)

正如David Heffernan最初所说:在TZipFile :: Open(文件名,模式)之后应该可以使用isValid,因为人们会期望打开一个只读文件不会阻止其他人阅读。

当使用基于fileNAME的Open方法(另一个存在用于从TFileStream读取f)时,它在内部创建一个fileStream,而当它 指定fmOpenRead时,它在打开此流时设置共享模式。

请参阅此博客文章,了解如何通过首先自己创建TFileStream来明确指定共享模式的示例: http://www.mfs-erp.org/blog/TZipFile-problem-accessing-open-files-even-with-TZipMode-zmRead