【问题标题】:System.IO.Compression Zip doesn't use UTCSystem.IO.Compression Zip 不使用 UTC
【发布时间】:2014-09-25 18:21:13
【问题描述】:

我刚开始在 .NET 4.5 中使用 System.IO.Compression,发现了一个问题。它使用本地修改时间存储文件,而不是通用 UTC 时间。

因此,如果您在一个时区压缩文件并在另一个时区解压缩它们,它会使用原始文件中的本地修改时间(例如下午 1 点),并以相同的修改时间(也是下午 1 点)提取文件,甚至虽然应该早或晚几个小时。

我假设在标准时间或夏令时压缩的文件会存在同样的问题,然后在另一个时间解压缩。

似乎在压缩过程中缺少设置,因为其他解压缩方法(WinZip,压缩文件夹提取)会产生相同的错误修改时间。

我测试过使用WinZip在不同时区压缩和解压文件,没有这个问题。它必须在内部使用 UTC 作为修改时间。

除了在 Zip 和 Unzip 期间构建我自己的时移例程之外,还有其他方法吗?

此项目不能使用任何外部应用程序或库。我们仅限于使用 .NET 函数。

【问题讨论】:

  • 您能否发布简短的示例代码来重现和演示该问题?
  • 我唯一能看到您可以访问的(在 .NET 4.5 中)是 ZipArchiveEntry.LastWriteTime,它的类型为 DateTimeOffset。因此,ZipArchive 代码应该具备正确写出信息所需的一切。如果没有某种方式来覆盖特定信息如何写入磁盘,我看不到任何解决方法。
  • 请注意,en.wikipedia.org/wiki/Zip_(file_format)#File_headers 似乎表明日期/时间只有 2 个字节;我看不出它如何写出可以在不同语言环境中以当地时间显示的内容。写出 UTC 日期/时间不会导致日期时间正确显示,它只会显示 UTC 时间(例如,我当地时间下午 3:38 的 19:38)。
  • ZIP 存档格式很古老。这些时间和日期字段以 MS-DOS 格式编码。 DOS 从来没有 UTC 的概念,它严格使用本地时间。
  • 我确实设法在 zip 文件根目录的文件中添加了一个与 UTC ("+07:00:00") 的偏移值。我提取它并将其与目标的偏移量(“+04:00:00”)进行比较,然后构建一个例程,通过偏移量差异更新所有解压缩文件。有效!对于这个项目来说已经足够了。今天的时间足够了。

标签: .net visual-studio-2013 zip utc system.io.compression


【解决方案1】:

正如 Hans Passant 在评论中提到的,zip 文件格式使用 MS-DOS Date & Time 结构。

这个结构被定义为两个独立的unsigned short 值,如下所示:

wFatDate

The MS-DOS date. The date is a packed value with the following format.
Bits    Description
0-4     Day of the month (1–31)
5-8     Month (1 = January, 2 = February, and so on)
9-15    Year offset from 1980 (add 1980 to get actual year)

wFatTime

The MS-DOS time. The time is a packed value with the following format.
Bits    Description
0-4     Second divided by 2
5-10    Minute (0–59)
11-15   Hour (0–23 on a 24-hour clock)

在创建 MS-DOS 时,这些计算机上还没有使用时区(不过,自 1970 年以来,Unix 就已经有了这个概念。)使用 MS-DOS 的人通常在办公室或家里,而没有使用 MS-DOS。通过计算机与其他国家的人交流,更不用说其他国家了。那时内网也很贵。

创建 zip 文件格式的公司错误地使用了 FAT 文件系统日期格式并卡住了。所以 zip 文件是使用本地时间创建的(不是必须的,但至少这是预期的行为。)

不过,zip 格式提供了添加 extensions(来自发布评论的 @user3342816 的链接)的方法,包括各种时间戳。​​

0x000a        NTFS (Win9x/WinNT FileTimes)
0x000d        Unix

NTFS 块是这样描述的:

     -PKWARE Win95/WinNT Extra Field:
      ==============================

      The following description covers PKWARE's "NTFS" attributes
      "extra" block, introduced with the release of PKZIP 2.50 for
      Windows. (Last Revision 20001118)

      (Note: At this time the Mtime, Atime and Ctime values may
      be used on any WIN32 system.)
      [Info-ZIP note: In the current implementations, this field has
      a fixed total data size of 32 bytes and is only stored as local
      extra field.]

      Value         Size        Description
      -----         ----        -----------
      0x000a        Short       Tag (NTFS) for this "extra" block type
      TSize         Short       Total Data Size for this block
      Reserved      Long        for future use
      Tag1          Short       NTFS attribute tag value #1
      Size1         Short       Size of attribute #1, in bytes
      (var.)        SubSize1    Attribute #1 data
      .
      .
      .
      TagN          Short       NTFS attribute tag value #N
      SizeN         Short       Size of attribute #N, in bytes
      (var.)        SubSize1    Attribute #N data

      For NTFS, values for Tag1 through TagN are as follows:
      (currently only one set of attributes is defined for NTFS)

      Tag        Size       Description
      -----      ----       -----------
      0x0001     2 bytes    Tag for attribute #1
      Size1      2 bytes    Size of attribute #1, in bytes (24)
      Mtime      8 bytes    64-bit NTFS file last modification time
      Atime      8 bytes    64-bit NTFS file last access time
      Ctime      8 bytes    64-bit NTFS file creation time

      The total length for this block is 28 bytes, resulting in a
      fixed size value of 32 for the TSize field of the NTFS block.

      The NTFS filetimes are 64-bit unsigned integers, stored in Intel
      (least significant byte first) byte order. They determine the
      number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch",
      which is "01-Jan-1601 00:00:00 UTC".

Unix 块也包括两个时间戳:

     -PKWARE Unix Extra Field:
      ========================

      The following is the layout of PKWARE's Unix "extra" block.
      It was introduced with the release of PKZIP for Unix 2.50.
      Note: all fields are stored in Intel low-byte/high-byte order.
      (Last Revision 19980901)

      This field has a minimum data size of 12 bytes and is only stored
      as local extra field.

      Value         Size        Description
      -----         ----        -----------
      0x000d        Short       Tag (Unix0) for this "extra" block type
      TSize         Short       Total Data Size for this block
      AcTime        Long        time of last access (UTC/GMT)
      ModTime       Long        time of last modification (UTC/GMT)
      UID           Short       Unix user ID
      GID           Short       Unix group ID
      (var)         variable    Variable length data field

      The variable length data field will contain file type
      specific data.  Currently the only values allowed are
      the original "linked to" file names for hard or symbolic
      links, and the major and minor device node numbers for
      character and block device nodes.  Since device nodes
      cannot be either symbolic or hard links, only one set of
      variable length data is stored.  Link files will have the
      name of the original file stored.  This name is NOT NULL
      terminated.  Its size can be determined by checking TSize -
      12.  Device entries will have eight bytes stored as two 4
      byte entries (in little-endian format).  The first entry
      will be the major device number, and the second the minor
      device number.

      [Info-ZIP note: The fixed part of this field has the same layout as
      Info-ZIP's abandoned "Unix1 timestamps & owner ID info" extra field;
      only the two tag bytes are different.]

正如我们所见,NTFS 和 Unix 块清楚地将它们的时间戳定义为使用 UTC。 NTFS 日期比 Unix 时间戳 (1s) 具有更高的精度 (100ms),由于它使用 64 位,它的生存时间也更长(有关 32 位时间戳的更多详细信息,请参阅Year 2038 Problem)。

【讨论】:

  • Extended Timestamp Extra Field 至少可以追溯到 1997 年。NTFS 时间戳于 1999 年发布。opensource.apple.com/source/zip/zip-6/unzip/unzip/proginfo/…
  • @user3342816 哦!很棒的文件。我添加了两个带有时间戳的块的详细信息(我想还有更多,但这可能是目前使用最多的两个)。
猜你喜欢
  • 2019-04-02
  • 1970-01-01
  • 2010-09-16
  • 2013-06-18
  • 1970-01-01
  • 2019-06-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
相关资源
最近更新 更多