一個.zip檔案文件並不是一個真正的Windows文件系統的目錄,你正在試圖做的,根本不會工作,所以什麼。另外,.zip存檔文件甚至沒有真正的目錄。它具有名稱的存檔條目,其中這些名稱可以包含路徑分隔符字符(不像Windows文件系統上的路徑,如NTFS或FAT)。
如果名稱中包含路徑分隔符,則歸檔操作工具(如Windows的內置.zip處理功能或像7zip這樣的程序將條目名稱視爲包含完整的目錄路徑),並使用路徑分隔符字符確定存儲在真實文件系統中時條目的虛擬路徑。
對於Windows資源管理器(即Windows的GUI外殼),當您雙擊一個.zip存檔文件時,它將打開它並在與常規文件系統窗口完全相同的窗口中顯示內容。但事實並非如此,您不能使用像Directory
和File
這樣的常用文件系統導航類來訪問它。
如果您想將存檔視爲其中包含目錄,則由您來檢查存檔中的所有條目名稱並在存儲器中構建一個表示目錄結構的數據結構(例如樹)隱含在檔案中的所有條目中。您可以通過一次構建整個樹來完成此任務,也可以只查看每個條目名稱的第一個路徑組件,並將其視爲歸檔根目錄中文件項沒有任何路徑的項目分隔符字符,而目錄項至少有一個。
通過遞歸地解析條目名稱,您可以按照這種方式導航.zip存檔。
或者,只需使用ExtractToDirectory()
方法將.zip存檔內容臨時複製到實際文件系統上的某個位置,然後就可以在那裏使用常規文件系統導航類。
這裏是我上面描述的第二類實現的一個例子。即給定的起始路徑,它將處理歸檔輸入和識別單個虛擬目錄和/或文件項,在通過該路徑指定的目錄有效是:
[Flags]
public enum EntryInfoTypes
{
Directory = 1,
File = 2,
DirectoryOrFile = Directory | File
}
public static class ZipDirectoryExtensions
{
private static readonly char[] _pathSeparators =
new[] { Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar };
public static IEnumerable<ZipDirectoryInfo> EnumerateDirectories(
this ZipArchive archive, string path)
{
return archive.EnumerateDirectories(path, SearchOption.TopDirectoryOnly);
}
public static IEnumerable<ZipDirectoryInfo> EnumerateDirectories(
this ZipArchive archive, string path, SearchOption searchOption)
{
return archive.EnumerateEntryInfos(path, searchOption, EntryInfoTypes.Directory)
.Cast<ZipDirectoryInfo>();
}
public static IEnumerable<ZipFileInfo> EnumerateFiles(
this ZipArchive archive, string path)
{
return archive.EnumerateFiles(path, SearchOption.TopDirectoryOnly);
}
public static IEnumerable<ZipFileInfo> EnumerateFiles(
this ZipArchive archive, string path, SearchOption searchOption)
{
return archive.EnumerateEntryInfos(path, searchOption, EntryInfoTypes.File)
.Cast<ZipFileInfo>();
}
public static IEnumerable<ZipEntryInfo> EnumerateEntryInfos(
this ZipArchive archive, string path, EntryInfoTypes entryInfoTypes)
{
return archive.EnumerateEntryInfos(
path, SearchOption.TopDirectoryOnly, entryInfoTypes);
}
public static IEnumerable<ZipEntryInfo> EnumerateEntryInfos(this ZipArchive archive,
string path, SearchOption searchOption, EntryInfoTypes entryInfoTypes)
{
// Normalize input path, by removing any path separator character from the
// beginning, and ensuring one is present at the end. This will ensure that
// the path variable format matches the format used in the archive and which
// is also convenient for the implementation of the algorithm below.
if (path.Length > 0)
{
if (_pathSeparators.Contains(path[0]))
{
path = path.Substring(1);
}
if (!_pathSeparators.Contains(path[path.Length - 1]))
{
path = path + Path.AltDirectorySeparatorChar;
}
}
HashSet<string> found = new HashSet<string>();
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (path.Length > 0 && !entry.FullName.StartsWith(path))
{
continue;
}
int nextSeparator = entry.FullName.IndexOfAny(_pathSeparators, path.Length);
if (nextSeparator >= 0)
{
string directoryName = entry.FullName.Substring(0, nextSeparator + 1);
if (found.Add(directoryName))
{
if (entryInfoTypes.HasFlag(EntryInfoTypes.Directory))
{
yield return new ZipDirectoryInfo(directoryName);
}
if (searchOption == SearchOption.AllDirectories)
{
foreach (ZipEntryInfo info in
archive.EnumerateEntryInfos(
directoryName, searchOption, entryInfoTypes))
{
yield return info;
}
}
}
}
else
{
if (entryInfoTypes.HasFlag(EntryInfoTypes.File))
{
yield return new ZipFileInfo(entry.FullName);
}
}
}
}
}
public class ZipEntryInfo
{
public string Name { get; }
public ZipEntryInfo(string name)
{
Name = name;
}
}
public class ZipDirectoryInfo : ZipEntryInfo
{
public ZipDirectoryInfo(string name) : base(name) { }
}
public class ZipFileInfo : ZipEntryInfo
{
public ZipFileInfo(string name) : base(name) { }
}
注:
- 這一點很重要要記住,即使有這個實現,你也不是真的處理實際的目錄。這只是瀏覽檔案的便利。尤其是,對於歸檔條目,您永遠無法獲得類似.NET的實際
DirectoryInfo
類的任何內容,因爲可能看起來像單個目錄的內容實際上只是一個或多個歸檔條目路徑的一部分。諸如Attributes
,CreationTime
和類似的屬性沒有任何意義。如果你想,你可以可能雖然包括像Name
和Parent
()(當然,我的Name
屬性重命名爲FullName
,所以它更好地匹配DirectoryInfo
類)。
- 我將它實現爲擴展方法,因爲我發現調用代碼更具可讀性。
- 有助手類型分別表示文件和目錄條目。當然,你可以傳回字符串,但是這會讓實現可以返回兩種條目的基本方法困難得多。
- 我包含了不同方法的重載,爲
SearchOption
參數提供默認值。我想我可以在方法聲明中設置默認值;舊習難改。 :)
- 以上是關於簡單的實現,我可以拿出來,但在一個小的成本效率。遞歸的每個級別枚舉歸檔條目的整個集合,因爲它搜索當前路徑中的條目。通過維護存在的所有條目的
HashSet<string>
,可以顯着提高效率,當條目匹配並且被有效使用時刪除條目。這會使代碼顯着複雜化,所以我把它作爲讀者的練習。
是'C:\ Users \ xx \ Desktop \ Folder \ E_sa_sub.zip'文件還是目錄? 'GetDirectories()'不可能在'.zip'文件中尋找路徑。如果'C:\ Users \ xx \ Desktop \ Folder \ E_sa_sub.zip \ E_sa_sub \ subbb問題是E_sa_sub.zip'是'.zip'文件,那麼您需要傳遞目錄'C:\ Users \ xx \ Desktop \ Folder \ E_sa_sub.zip \ E_sa_sub \',例如通過使用'new DirectoryInfo(Path.GetDirectoryName(path));'請給我們目錄結構。 –