如何在Xamarin for Android中压缩文件?

3

我有一个函数,可以根据传递的文件字符串数组创建一个zip文件。该函数成功创建了zip文件和其中的zip entry文件,但这些zip entry文件是空的。我已经尝试了几种不同的方法 - 下面是最接近正常工作的函数代码:

    public static bool ZipFile(string[] arrFiles, string sZipToDirectory, string sZipFileName)
    {
        if (Directory.Exists(sZipToDirectory))
        {
            FileStream fNewZipFileStream;
            ZipOutputStream zos;

            try {
                fNewZipFileStream = File.Create(sZipToDirectory + sZipFileName);
                zos = new ZipOutputStream(fNewZipFileStream);

                for (int i = 0; i < arrFiles.Length; i++) {
                    ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
                    zos.PutNextEntry(entry);

                    FileStream fStream = File.OpenRead(arrFiles[i]);
                    BufferedStream bfStrm = new BufferedStream(fStream);

                    byte[] buffer = new byte[bfStrm.Length];
                    int count;
                    while ((count = bfStrm.Read(buffer, 0, 1024)) != -1) {
                        zos.Write(buffer);
                    }

                    bfStrm.Close();
                    fStream.Close();
                    zos.CloseEntry();
                }
                zos.Close();
                fNewZipFileStream.Close();
                return true;
            }
            catch (Exception ex)
            {
                string sErr = ex.Message;
                return false;
            }
            finally
            {
                fNewZipFileStream = null;
                zos = null;
            }
        }
        else
        {
            return false;
        }
    }

我认为这与字节流处理有关。我尝试了处理流的代码,但它陷入了无限循环:

while ((count = fStream.Read(buffer, 0, 1024)) != -1) {
        zos.Write(buffer, 0, count);
}
fStream.Close();
4个回答

3
我找到了一个相当简单的解决方案 - 我使用了静态文件类的ReadAllBytes方法。
ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
zos.PutNextEntry(entry);

byte[] fileContents = File.ReadAllBytes(arrFiles[i]);
zos.Write(fileContents);
zos.CloseEntry();

2

FileStream 上使用 Read() 方法会返回已读取到的字节数,如果流的末尾已经到达则返回 0。它永远不会返回 -1。

来自 MSDN

已读取到缓冲区的总字节数。如果请求的字节数目前不可用,则此数值可能小于请求的字节数;或者当流的末尾被读取时返回零

我会将您的代码修改为以下内容:

System.IO.FileStream fos = new System.IO.FileStream(sZipToDirectory + sZipFileName, FileMode.Create);
Java.Util.Zip.ZipOutputStream zos = new Java.Util.Zip.ZipOutputStream(fos);

byte[] buffer = new byte[1024];
for (int i = 0; i < arrFiles.Length; i++) {

    FileInfo fi = new FileInfo (arrFiles[i]);
    Java.IO.FileInputStream fis = new Java.IO.FileInputStream(fi.FullName);

    ZipEntry entry = new ZipEntry(arrFiles[i].Substring(arrFiles[i].LastIndexOf("/") + 1));
    zos.PutNextEntry(entry);

    int count = 0;
    while ((count = fis.Read(buffer)) > 0) {
        zos.Write(buffer, 0, count);
    }

    fis.Close();
    zos.CloseEntry();
}

这段代码与我过去在Android上创建zip档案所用的代码几乎完全相同。


Matt,感谢您的回复。fstream.Read方法不仅需要一个参数,所以我将其写成了fStream.Read(buffer, 0, 1024)。我会尝试一下看看是否有效。 - Ian P
啊,很抱歉。我使用了Java.IO.FileInputStream来读取文件,而不是.NET的。 - matthewrdev
所以 FileStream fStream = File.OpenRead(arrFiles[i]) 将变成 var fStream = new Java.IO.FileInputStream(arrFiles[i])。这将允许您使用 fStream.Read(buffer, 0, 1024) - matthewrdev
Matt,还是不行。我尝试了不同的组合,包括FileStream fStream = File.OpenRead(arrFiles[i])和var fStream = new Java.IO.FileInputStream(arrFiles[i]),以及fStream.Read(buffer)和fStream.Read(buffer, 0, 1024)。使用Java.IO.FileInputStream时,fStream.Read(buffer)和fStream.Read(buffer, 0, 1024)都是-1,因此它无法到达zos.Write,而旧的FileStream中,fStream.Read(buffer)和fStream.Read(buffer, 0, 1024)都是0,所以它进入了zos.Write,但进入了一个(看似)无限循环。 - Ian P
Ian,又来更新了。我把用于压缩的代码原封不动地复制了一遍,只改了变量名称。让我知道你的进展如何。 - matthewrdev
Matt,谢谢你的跟进。我用静态文件类的ReadAllBytes方法成功让它工作了。我在下面发表了代码。最好的祝福。 - Ian P

0

你可以使用SharpZip吗?它非常容易使用。

这里是我写的一篇博客文章,介绍如何提取zip文件。

    private static void upzip(string url)
    {
        WebClient wc = new WebClient();
        wc.DownloadFile(url, "temp.zip");  
        //unzip
        ZipFile zf = null;
        try
        {
            zf = new ZipFile(File.OpenRead("temp.zip"));
            foreach (ZipEntry zipEntry in zf)
            {
                string fileName = zipEntry.Name;
                byte[] buffer = new byte[4096];
                Stream zipStream = zf.GetInputStream(zipEntry);
                using (FileStream streamWriter = File.Create( fileName))
                {
                    StreamUtils.Copy(zipStream, streamWriter, buffer);
                }
            }

        }
        finally
        {
            if (zf != null)
            {
                zf.IsStreamOwner = true;
                zf.Close();
            }
        }

    }

谢谢回复,但是我想要把文件压缩起来,而不是解压缩,而且我更喜欢不使用第三方组件或库。问候 - Ian P

0
private void ZipFolder(string[] _files, string zipFileName)
    {
        using var memoryStream = new MemoryStream();
        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach (var item in _files)
            {
                var demoFile = archive.CreateEntry(Path.GetFileName(item));
                using var readStreamW = File.OpenRead(item);
                using (var entryStream = demoFile.Open())
                {
                    using (var streamWriter = new StreamWriter(entryStream))
                    {
                        readStreamW.Seek(0, SeekOrigin.Begin);
                        readStreamW.CopyTo(streamWriter.BaseStream);
                    }
                }
            }
        }

        using var fileStream = new FileStream(zipFileName, FileMode.Create);
        memoryStream.Seek(0, SeekOrigin.Begin);
        memoryStream.CopyTo(fileStream);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接