.NET组件支持读取ZIP中某个目录下所有文件名,读取某个文件内容到变量吗?不需要写入硬盘? 比如把EXCEL ABC.XLSX格式数据和图片目录一起打包。 用NPOI等组件读取ZIP中的ABC.XLSX文件内存字节数据?
✅ 完全支持!.NET 原生支持内存中操作ZIP文件
.NET 提供了强大的 System.IO.Compression.ZipArchive
类来完全在内存中处理ZIP文件,无需写入硬盘。
🚀 核心实现方案
1. 读取ZIP中特定目录的所有文件名
cs
using System.IO.Compression;
public List<string> GetFilesInZipDirectory(byte[] zipData, string targetDirectory)
{
var fileNames = new List<string>();
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
// 确保目录格式正确(以/结尾)
var searchPath = targetDirectory.TrimEnd('/') + "/";
foreach (var entry in archive.Entries)
{
// 检查是否在目标目录中且不是目录本身
if (!entry.FullName.EndsWith("/") &&
entry.FullName.StartsWith(searchPath, StringComparison.OrdinalIgnoreCase))
{
fileNames.Add(entry.FullName);
}
}
}
return fileNames;
}
2. 读取ZIP中特定文件内容到内存变量
cs
public byte[] ReadFileFromZip(byte[] zipData, string filePathInZip)
{
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
var entry = archive.GetEntry(filePathInZip);
if (entry != null)
{
using (var entryStream = entry.Open())
using (var resultStream = new MemoryStream())
{
entryStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
}
return null;
}
3. 读取文本文件内容
cs
public string ReadTextFileFromZip(byte[] zipData, string filePathInZip, Encoding encoding = null)
{
encoding = encoding ?? Encoding.UTF8;
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
var entry = archive.GetEntry(filePathInZip);
if (entry != null)
{
using (var entryStream = entry.Open())
using (var reader = new StreamReader(entryStream, encoding))
{
return reader.ReadToEnd();
}
}
}
return null;
}
📦 完整示例:读取打包的Excel和图片
cs
public class ZipExcelReader
{
public void ProcessPackagedExcel(byte[] zipData)
{
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
// 1. 查找Excel文件
var excelEntry = archive.Entries.FirstOrDefault(e =>
e.Name.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase));
if (excelEntry != null)
{
// 2. 读取Excel文件到内存字节数组
byte[] excelData;
using (var excelStream = excelEntry.Open())
using (var ms = new MemoryStream())
{
excelStream.CopyTo(ms);
excelData = ms.ToArray();
}
// 3. 使用NPOI读取Excel数据(完全在内存中)
ProcessExcelWithNPOI(excelData);
}
// 4. 读取images目录下的所有图片
var imageEntries = archive.Entries.Where(e =>
e.FullName.StartsWith("images/", StringComparison.OrdinalIgnoreCase) &&
!e.FullName.EndsWith("/"));
foreach (var imageEntry in imageEntries)
{
byte[] imageData;
using (var imageStream = imageEntry.Open())
using (var ms = new MemoryStream())
{
imageStream.CopyTo(ms);
imageData = ms.ToArray();
}
Console.WriteLine($"图片: {imageEntry.FullName}, 大小: {imageData.Length} bytes");
// 处理图片数据...
}
}
}
private void ProcessExcelWithNPOI(byte[] excelData)
{
using (var memoryStream = new MemoryStream(excelData))
{
// 使用NPOI读取内存中的Excel数据
var workbook = new NPOI.XSSF.UserModel.XSSFWorkbook(memoryStream);
var sheet = workbook.GetSheetAt(0);
// 读取单元格数据
for (int i = 0; i < sheet.LastRowNum; i++)
{
var row = sheet.GetRow(i);
if (row != null)
{
var cell = row.GetCell(0);
if (cell != null)
{
Console.WriteLine($"单元格[{i},0]: {cell.ToString()}");
}
}
}
}
}
}
🔧 实用工具类
cs
public static class ZipMemoryHelper
{
// 获取ZIP中所有文件的树形结构
public static Dictionary<string, List<string>> GetZipStructure(byte[] zipData)
{
var structure = new Dictionary<string, List<string>>();
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
foreach (var entry in archive.Entries)
{
if (entry.FullName.EndsWith("/")) continue; // 跳过目录条目
var directory = Path.GetDirectoryName(entry.FullName)?.Replace("\\", "/");
if (string.IsNullOrEmpty(directory)) directory = "/";
if (!structure.ContainsKey(directory))
{
structure[directory] = new List<string>();
}
structure[directory].Add(Path.GetFileName(entry.FullName));
}
}
return structure;
}
// 检查ZIP中是否包含特定文件
public static bool ZipContainsFile(byte[] zipData, string filePath)
{
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
return archive.GetEntry(filePath) != null;
}
}
// 批量读取多个文件
public static Dictionary<string, byte[]> ReadMultipleFiles(byte[] zipData, params string[] filePaths)
{
var results = new Dictionary<string, byte[]>();
using (var memoryStream = new MemoryStream(zipData))
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read))
{
foreach (var filePath in filePaths)
{
var entry = archive.GetEntry(filePath);
if (entry != null)
{
using (var entryStream = entry.Open())
using (var ms = new MemoryStream())
{
entryStream.CopyTo(ms);
results[filePath] = ms.ToArray();
}
}
}
}
return results;
}
}
🎯 使用示例
cs
// 示例:从文件加载ZIP数据到内存
byte[] zipData = File.ReadAllBytes("package.zip");
// 1. 读取目录结构
var structure = ZipMemoryHelper.GetZipStructure(zipData);
foreach (var dir in structure)
{
Console.WriteLine($"目录: {dir.Key}");
foreach (var file in dir.Value)
{
Console.WriteLine($" - {file}");
}
}
// 2. 读取Excel文件并用NPOI处理
if (ZipMemoryHelper.ZipContainsFile(zipData, "data/workbook.xlsx"))
{
byte[] excelData = ReadFileFromZip(zipData, "data/workbook.xlsx");
// 使用NPOI处理内存中的Excel数据
using (var ms = new MemoryStream(excelData))
{
var workbook = new NPOI.XSSF.UserModel.XSSFWorkbook(ms);
// ... NPOI操作
}
}
// 3. 批量读取图片文件
var images = ZipMemoryHelper.ReadMultipleFiles(zipData,
"images/photo1.jpg",
"images/photo2.png",
"images/photo3.gif");
foreach (var image in images)
{
Console.WriteLine($"{image.Key}: {image.Value.Length} bytes");
}
💡 关键优势
-
零磁盘IO:所有操作都在内存中进行
-
高性能:避免了文件系统开销
-
线程安全:每个操作使用独立的MemoryStream
-
资源管理:正确使用using语句确保资源释放
⚠️ 注意事项
-
大文件需要注意内存使用量
-
ZipArchive是只读的,修改需要创建新的ZIP
-
确保正确处理中文文件名编码
.NET 原生支持使得内存中处理ZIP文件变得非常简单高效!