如何将TZipFile.FileComment读作字符串?

时间:2014-01-24 17:19:48

标签: delphi delphi-xe4

当您尝试读取TZipFile.FileComment时,编译器报告这将无法编译: [dcc64错误] Unit1.pas(451):E2010不兼容的类型:'string'和'System.TArray'

var
  iFileComment: string;
...
iFileComment := iZipFile.FileInfo[i].FileComment;

那么......你如何阅读TZipFile注释并将其分配给字符串?这看起来很奇怪,因为我可以成功编写zipfile注释,如下所示:

iZipFile.FileComment[ListView1.ItemIndex] := FileComment1.Text;

如果您尝试阅读评论:

iFileComment := iZipFile.FileComment[i];

zip文件中的每个文件都有相同的注释,即使只有一个文件实际上有文件注释。

评论由此添加:

procedure TForm1.SetFileComment1Click(Sender: TObject); var  
iZipFile: TZipFile;   iListItem: TlistItem; 
begin   
  if ListView1.ItemIndex <> -1 then   
  begin
     iZipFile := TZipFile.Create;
     try
       { Open zip file for writing }
       iZipFile.Open(ZipFilename1.Text, zmReadWrite);
       iZipFile.FileComment[ListView1.ItemIndex] := FileComment1.Text;
       { Close the zip file }
       iZipFile.Close;
       { Update the listview }
       ListView1.Items.BeginUpdate;
       try
         iListItem := ListView1.Items.Item[ListView1.ItemIndex];
         iListItem.SubItems[5] := FileComment1.Text;
       finally
         ListView1.Items.EndUpdate;
       end;
     finally
       iZipFile.Free;
     end;   
  end   
  else   
  begin
    MessageBox(0, 'A filename is not selected. Please select a filename.',
       'Warning', MB_ICONINFORMATION or MB_OK);
  end; 
end;

修改

我现在按照建议使用iZipFile.FileComment [Index]设置和编写文件评论。 当我设置一个文件的注释并在工作的zip应用程序中打开zip文件时,只有我设置的单个文件带有注释...在这个TZipFile项目中,当我加载相同的zip文件时,每个文件都有相同的注释但我看不出原因。除了filecomment字段之外,所有其他字段都按预期运行。

以下是打开zip文件的代码:

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
          { Open zip file for reading }
          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.FileComment[i];
            iListItem.SubItems.Add(iFileComment); { 5 }
          end;
          { Close the zip file }
          iZipFile.Close;
        except
          on E: Exception do
          begin
            ShowMessage(E.ClassName + #10#13 + E.Message);
          end;
        end;
      finally
        iZipFile.Free;
      end;
    end;
  end;
end;

3 个答案:

答案 0 :(得分:4)

你以与写作相同的方式阅读它,反过来:

// Write the comment
iZipFile.FileComment[Index] := 'This is a zip file comment';

// Read it back
sComment := iZipFile.FileComment[Index];
WriteLn(sComment);             // Outputs "This is a zip file comment"

Index将匹配zip存档中单个文件的索引。换句话说,第一个文件位于索引0,第二个文件位于索引1,等等,最后一个文件位于索引FileCount - 1

这是一个有效的例子。我创建了一个名为Test.zip的虚拟zip文件,其中包含我在答案中使用的一些旧的.png文件(如下图所示):

List of files in zip displayed in Windows Explorer

然后我使用下面的代码为每个文件添加注释并将其读回,并将它们写入控制台:

program Project1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, System.Zip;

var
  Zip: TZipFile;
  i: Integer;
begin
  Zip := TZipFile.Create;
  Zip.Open('D:\TempFiles\Test.zip', zmReadWrite);
  for i := 0 to Zip.FileCount - 1 do
    Zip.FileComment[i] := Format('This is file %d', [i]);
  Zip.Free;  // Flushes changes to disk automatically

  // Create a new instance, just to make it clear.
  Zip := TZipFile.Create;
  Zip.Open('D:\TempFiles\Test.zip', zmReadWrite);
  for i := 0 to Zip.FileCount - 1 do
    WriteLn(Zip.FileNames[i] + ':'#9 + Zip.FileComment[i]);
  Zip.Free;
  ReadLn;
end.

这是它产生的输出:

Screen capture of console output displaying file comments from code above

这是它添加的zip文件评论,如7Zip:

中所示

Screen capture of 7Zip window with zip file names and comments

答案 1 :(得分:4)

在XE2中,TZipHeader.FileComment被声明为RawByteString,可以直接分配给String(使用类型转换来避免编译器警告):

iFileComment := String(iZipFile.FileInfo[i].FileComment);

但是,在XE4中,TZipHeader.FileComment被声明为TBytes。您不能直接将TBytes分配给String(反之亦然),而是编译错误。

如果您查看XE4中TZipFile.GetFileComment()的实现,则会使用TZipFile.TBytesToString()TBytes转换为StringTZipFile.TBytesToString()使用SysUtils.TEncoding.GetString()进行实际转化,使用代码页65001或437,具体取决于TZipFile.UTF8Support属性的值。

获取/设置每个文件注释的正确方法是使用TZipFile.FileComments[]属性,如Ken演示。它不仅为您处理字符串&lt; - &gt;字节转换,而且还会在访问数据之前检查zip是否已打开。

答案 2 :(得分:0)

很抱歉重新提出这个旧问题,但没有一个答案实际上解决了 zip文件中的每个文件都有相同的评论问题。

原因是TZipFile.ReadCentralHeader

中的错误

打开zip文件时ReadCentralHeader将所有zip目录条目读入内部记录列表,但无法清除每个条目之间用于填充列表的临时记录。

如果文件注释ReadCentralHeader首先读取FileCommentLength值,但如果此值为零,则它不会设置FileComment值的值,因此保留上一个条目的值。

可能的解决方法是在阅读FileCommentLength属性时考虑FileComment[]值:

Comment := Copy(ZipFile.FileComment[Index], 1, ZipFile.FileInfo[Index].FileCommentLength);