【问题标题】:Check Validity of a Zip File检查 Zip 文件的有效性
【发布时间】:2014-01-24 16:17:46
【问题描述】:

当我尝试检查 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;

【问题讨论】:

    标签: delphi


    【解决方案1】:

    你把这些线弄错了:

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

    第一行锁定文件,因此第二行失败。您必须先致电IsValid,然后再致电Open

    话虽如此,既然你使用了zmRead,那么对IsValid 的调用应该可以再次打开文件,因为对Open 的调用使用了fmOpenRead。所以我怀疑您使用的Delphi版本中的ZIP文件代码或文件流代码可能存在错误。尽管如此,在Open 之前调用IsValid 肯定会起作用。

    其实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;
    

    【讨论】:

    • 开始看起来甚至根本不需要 open 甚至 iZipFile := TZipFile.Create;?
    • 啊,我以为您想阅读该文件。如果您只想检查有效性,那么您根本不需要实例。
    【解决方案2】:

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

    当使用基于 fileNAME 的 Open 方法时(另一个用于从 TFileStream 中读取 f),它在内部创建一个 fileStream,虽然它确实指定了 fmOpenRead,但它确实没有在打开此流时设置共享模式。

    有关如何通过首先自己创建一个 TFileStream 并在其中明确指定共享模式来避免这种情况的示例,请参阅此博客文章: https://www.digon.be/community/blog/TZipFile-problem-accessing-open-files-even-with-TZipMode-zmRead

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-16
      • 2011-08-18
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 2020-12-10
      • 2011-07-11
      • 1970-01-01
      相关资源
      最近更新 更多