Search code examples
delphidelphi-xe4

How to read TZipFile.FileComment as a string?


When you try to read a TZipFile.FileComment the compiler reports that this will not compile: [dcc64 Error] Unit1.pas(451): E2010 Incompatible types: 'string' and 'System.TArray'

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

So... how do you read a TZipFile comment and assign it to a string? This seems strange because I can successfully write the zipfile comment as follows:

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

If you try to read the comment with:

iFileComment := iZipFile.FileComment[i];

every file in the zip file has the same comment, even though only one file actually has a filecomment.

The comments are added by this:

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;

EDIT

I am now setting and writing the filecomments with iZipFile.FileComment[Index] as suggested. When I set one file's comment and open the zip file in a working zip app only the single file that I set appears with the comment... In this TZipFile project when I load the same zip file, every file has the same comment but I can not see why. All the other fields operate as you would expect except for the filecomment field.

Here is the code that opens the zip file:

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;

Solution

  • You read it back the same way you write it, in reverse:

    // 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 would match the index of the individual file within the zip archive. In other words, the first file would be at index 0, the second at index 1, etc., wit the last being at index FileCount - 1.

    Here's a working example. I created a dummy zip file named Test.zip containing a few old .png files I've used in answers here (as seen in the image below):

    List of files in zip displayed in Windows Explorer

    I then used the below code to add comments to each file and read them back, writing them to the console:

    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.
    

    Here's the output it produced:

    Screen capture of console output displaying file comments from code above

    Here's the zip file comments it added, as displayed in 7Zip:

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