📄 zipfile.cs
字号:
// ZipFile.cs
//
// Copyright (C) 2001 Mike Krueger
// Copyright (C) 2004 John Reilly
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library. Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
//
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module. An independent module is a module which is not derived from
// or based on this library. If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so. If you do not wish to do so, delete this
// exception statement from your version.
using System;
using System.Collections;
using System.IO;
using System.Text;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using ICSharpCode.SharpZipLib.Zip.Compression;
namespace ICSharpCode.SharpZipLib.Zip
{
/// <summary>
/// This class represents a Zip archive. You can ask for the contained
/// entries, or get an input stream for a file entry. The entry is
/// automatically decompressed.
///
/// This class is thread safe: You can open input streams for arbitrary
/// entries in different threads.
/// <br/>
/// <br/>Author of the original java version : Jochen Hoenicke
/// </summary>
/// <example>
/// <code>
/// using System;
/// using System.Text;
/// using System.Collections;
/// using System.IO;
///
/// using ICSharpCode.SharpZipLib.Zip;
///
/// class MainClass
/// {
/// static public void Main(string[] args)
/// {
/// ZipFile zFile = new ZipFile(args[0]);
/// Console.WriteLine("Listing of : " + zFile.Name);
/// Console.WriteLine("");
/// Console.WriteLine("Raw Size Size Date Time Name");
/// Console.WriteLine("-------- -------- -------- ------ ---------");
/// foreach (ZipEntry e in zFile) {
/// DateTime d = e.DateTime;
/// Console.WriteLine("{0, -10}{1, -10}{2} {3} {4}", e.Size, e.CompressedSize,
/// d.ToString("dd-MM-yy"), d.ToString("t"),
/// e.Name);
/// }
/// }
/// }
/// </code>
/// </example>
public class ZipFile : IEnumerable
{
string name;
string comment;
Stream baseStream;
bool isStreamOwner = true;
ZipEntry[] entries;
/// <summary>
/// Opens a Zip file with the given name for reading.
/// </summary>
/// <exception cref="IOException">
/// An i/o error occurs
/// </exception>
/// <exception cref="ZipException">
/// The file doesn't contain a valid zip archive.
/// </exception>
public ZipFile(string name)
{
isStreamOwner = true;
this.baseStream = File.OpenRead(name);
this.name = name;
try {
ReadEntries();
}
catch {
Close();
throw;
}
}
/// <summary>
/// Opens a Zip file reading the given FileStream
/// </summary>
/// <exception cref="IOException">
/// An i/o error occurs.
/// </exception>
/// <exception cref="ZipException">
/// The file doesn't contain a valid zip archive.
/// </exception>
public ZipFile(FileStream file)
{
this.baseStream = file;
this.name = file.Name;
try {
ReadEntries();
}
catch {
entries = null;
throw;
}
}
/// <summary>
/// Opens a Zip file reading the given Stream
/// </summary>
/// <exception cref="IOException">
/// An i/o error occurs
/// </exception>
/// <exception cref="ZipException">
/// The file doesn't contain a valid zip archive.<br/>
/// The stream provided cannot seek
/// </exception>
public ZipFile(Stream baseStream)
{
this.baseStream = baseStream;
this.name = null;
try {
ReadEntries();
}
catch {
entries = null;
throw;
}
}
/// <summary>
/// Get/set a flag indicating if the underlying stream is owned by the ZipFile instance.
/// If the flag is true then the stream will be closed when <see cref="Close">Close</see> is called.
/// </summary>
/// <remarks>
/// The default value is true in all cases.
/// </remarks>
bool IsStreamOwner
{
get { return isStreamOwner; }
set { isStreamOwner = value; }
}
/// <summary>
/// Read an unsigned short in little endian byte order.
/// </summary>
/// <exception cref="IOException">
/// An i/o error occurs.
/// </exception>
/// <exception cref="EndOfStreamException">
/// The file ends prematurely
/// </exception>
int ReadLeShort()
{
return baseStream.ReadByte() | baseStream.ReadByte() << 8;
}
/// <summary>
/// Read an int in little endian byte order.
/// </summary>
/// <exception cref="IOException">
/// An i/o error occurs.
/// </exception>
/// <exception cref="System.IO.EndOfStreamException">
/// The file ends prematurely
/// </exception>
int ReadLeInt()
{
return ReadLeShort() | ReadLeShort() << 16;
}
/// <summary>
/// Search for and read the central directory of a zip file filling the entries
/// array. This is called exactly once by the constructors.
/// </summary>
/// <exception cref="System.IO.IOException">
/// An i/o error occurs.
/// </exception>
/// <exception cref="ICSharpCode.SharpZipLib.Zip.ZipException">
/// The central directory is malformed or cannot be found
/// </exception>
void ReadEntries()
{
// Search for the End Of Central Directory. When a zip comment is
// present the directory may start earlier.
//
// TODO: The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
// This should be compatible with both SFX and ZIP files but has only been tested for Zip files
// Need to confirm this is valid in all cases.
// Could also speed this up by reading memory in larger blocks?
if (baseStream.CanSeek == false) {
throw new ZipException("ZipFile stream must be seekable");
}
long pos = baseStream.Length - ZipConstants.ENDHDR;
if (pos <= 0) {
throw new ZipException("File is too small to be a Zip file");
}
long giveUpMarker = Math.Max(pos - 0x10000, 0);
do {
if (pos < giveUpMarker) {
throw new ZipException("central directory not found, probably not a zip file");
}
baseStream.Seek(pos--, SeekOrigin.Begin);
} while (ReadLeInt() != ZipConstants.ENDSIG);
int thisDiskNumber = ReadLeShort();
int startCentralDirDisk = ReadLeShort();
int entriesForThisDisk = ReadLeShort();
int entriesForWholeCentralDir = ReadLeShort();
int centralDirSize = ReadLeInt();
int offsetOfCentralDir = ReadLeInt();
int commentSize = ReadLeShort();
byte[] zipComment = new byte[commentSize];
baseStream.Read(zipComment, 0, zipComment.Length);
comment = ZipConstants.ConvertToString(zipComment);
/* Its seems possible that this is too strict, more digging required.
if (thisDiskNumber != 0 || startCentralDirDisk != 0 || entriesForThisDisk != entriesForWholeCentralDir) {
throw new ZipException("Spanned archives are not currently handled");
}
*/
entries = new ZipEntry[entriesForWholeCentralDir];
baseStream.Seek(offsetOfCentralDir, SeekOrigin.Begin);
for (int i = 0; i < entriesForWholeCentralDir; i++) {
if (ReadLeInt() != ZipConstants.CENSIG) {
throw new ZipException("Wrong Central Directory signature");
}
int versionMadeBy = ReadLeShort();
int versionToExtract = ReadLeShort();
int bitFlags = ReadLeShort();
int method = ReadLeShort();
int dostime = ReadLeInt();
int crc = ReadLeInt();
int csize = ReadLeInt();
int size = ReadLeInt();
int nameLen = ReadLeShort();
int extraLen = ReadLeShort();
int commentLen = ReadLeShort();
int diskStartNo = ReadLeShort(); // Not currently used
int internalAttributes = ReadLeShort(); // Not currently used
int externalAttributes = ReadLeInt();
int offset = ReadLeInt();
byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
baseStream.Read(buffer, 0, nameLen);
string name = ZipConstants.ConvertToString(buffer, nameLen);
ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy);
entry.CompressionMethod = (CompressionMethod)method;
entry.Crc = crc & 0xffffffffL;
entry.Size = size & 0xffffffffL;
entry.CompressedSize = csize & 0xffffffffL;
entry.Flags = bitFlags;
entry.DosTime = (uint)dostime;
if (extraLen > 0) {
byte[] extra = new byte[extraLen];
baseStream.Read(extra, 0, extraLen);
entry.ExtraData = extra;
}
if (commentLen > 0) {
baseStream.Read(buffer, 0, commentLen);
entry.Comment = ZipConstants.ConvertToString(buffer, commentLen);
}
entry.ZipFileIndex = i;
entry.Offset = offset;
entry.ExternalFileAttributes = externalAttributes;
entries[i] = entry;
}
}
/// <summary>
/// Closes the ZipFile. If the stream is <see cref="IsStreamOwner">owned</see> then this also closes the underlying input stream.
/// Once closed, no further instance methods should be called.
/// </summary>
/// <exception cref="System.IO.IOException">
/// An i/o error occurs.
/// </exception>
public void Close()
{
entries = null;
if ( isStreamOwner ) {
lock(baseStream) {
baseStream.Close();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -