下载文件时,无法从azure存储中正确下载文件,数据也会丢失

时间:2015-10-26 05:06:33

标签: asp.net-mvc azure azure-storage dotnetzip azure-blob-storage

我在Azure blob存储上保存了2个文件:

  1. 的abc.txt
  2. Pqr.docx
  3. 现在我想创建这两个文件的zip文件并允许用户下载。

    我已将此保存在我的数据库表字段中,如下所示:

    Document
    Abc,Pqr
    

    现在,当我点击下载时,我的文件如下,没有数据文件扩展名也丢失,如下所示: enter image description here

    我希望用户在用户下载zip文件时获取zip中的确切文件(.txt,.docx)。

    这是我的代码:

    public ActionResult DownloadImagefilesAsZip()
    {
        string documentUrl = repossitory.GetDocumentsUrlbyId(id);//output:Abc.txt,Pqr.Docx
              if (!string.IsNullOrEmpty(documentUrl))
                {
                    string[] str = documentUrl.Split(',');
                    if (str.Length > 1)
                    {
                        using (ZipFile zip = new ZipFile())
                        {
                            int cnt = 0;
                            foreach (string t in str)
                            {
                                if (!string.IsNullOrEmpty(t))
                                {
                                    Stream s = this.GetFileContent(t);
                                    zip.AddEntry("File" + cnt, s);
    
                                }
                                cnt++;
                            }
                            zip.Save(outputStream);
                            outputStream.Position = 0;
                            return File(outputStream, "application/zip", "all.zip");
                        }
                    }
    
    }
    
      public Stream GetFileContent(string fileName)
            {
                CloudBlobContainer container = this.GetCloudBlobContainer();
                CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
                var stream = new MemoryStream();
                blockBlob.DownloadToStream(stream);
                return stream;
            }
    
     public CloudBlobContainer GetCloudBlobContainer()
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"].ToString());
                CloudBlobClient blobclient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer blobcontainer = blobclient.GetContainerReference("Mystorage");
                if (blobcontainer.CreateIfNotExists())
                {
                    blobcontainer.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
                }
                blobcontainer.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
                return blobcontainer;
            }
    

    我希望在用户下载zip文件时下载相同的文件。

    任何人都可以帮我吗?

3 个答案:

答案 0 :(得分:2)

我不是网络开发者,但希望这会有所帮助。这段代码在一种方法中,我使用流将blob列表下载到zip文件存档中。文件列表中包含所有方向的斜杠,因此这里有代码来解决这个问题,并确保我使用正确的文本获取blob引用(没有URL,如果没有开头的斜杠, blob位于"文件夹")。

我怀疑你的问题不是使用内存流或二进制编写器。特殊性有时有帮助。祝你好运。

using (ZipArchive zipFile = ZipFile.Open(outputZipFileName, ZipArchiveMode.Create))
{
    foreach (string oneFile in listOfFiles)
    {
        //Need the filename, complete with relative path. Make it like a file name on disk, with backwards slashes.
        //Also must be relative, so can't start with a slash. Remove if found.
        string filenameInArchive = oneFile.Replace(@"/", @"\");
        if (filenameInArchive.Substring(0, 1) == @"\")
            filenameInArchive = filenameInArchive.Substring(1, filenameInArchive.Length - 1);

        //blob needs slashes in opposite direction
        string blobFile = oneFile.Replace(@"\", @"/");

        //take first slash off of the (folder + file name) to access it directly in blob storage
        if (blobFile.Substring(0, 1) == @"/")
            blobFile = oneFile.Substring(1, oneFile.Length - 1);

        var cloudBlockBlob = this.BlobStorageSource.GetBlobRef(blobFile);
        if (!cloudBlockBlob.Exists()) //checking just in case
        {
            //go to the next file
            //should probably trace log this 
            //add the file name with the fixed slashes rather than the raw, messed-up one
            //  so anyone looking at the list of files not found doesn't think it's because
            //  the slashes are different
            filesNotFound.Add(blobFile);
        }
        else
        {
            //blob listing has files with forward slashes; that's what the zip file requires
            //also, first character should not be a slash (removed it above)

            ZipArchiveEntry newEntry = zipFile.CreateEntry(filenameInArchive, CompressionLevel.Optimal);

            using (MemoryStream ms = new MemoryStream())
            {
                //download the blob to a memory stream
                cloudBlockBlob.DownloadToStream(ms);

                //write to the newEntry using a BinaryWriter and copying it 4k at a time
                using (BinaryWriter entry = new BinaryWriter(newEntry.Open()))
                {
                    //reset the memory stream's position to 0 and copy it to the zip stream in 4k chunks
                    //this keeps the process from taking up a ton of memory
                    ms.Position = 0;
                    byte[] buffer = new byte[4096];

                    bool copying = true;
                    while (copying)
                    {
                        int bytesRead = ms.Read(buffer, 0, buffer.Length);
                        if (bytesRead > 0)
                        {
                            entry.Write(buffer, 0, bytesRead);
                        }
                        else
                        {
                            entry.Flush();
                            copying = false;
                        }
                    }
                }//end using for BinaryWriter

            }//end using for MemoryStream

        }//if file exists in blob storage

    }//end foreach file

} //end of using ZipFileArchive

答案 1 :(得分:1)

我见过人们使用ICSharpZip库,看看这段代码

public void ZipFilesToResponse(HttpResponseBase response, IEnumerable<Asset> files, string zipFileName)
    {
        using (var zipOutputStream = new ZipOutputStream(response.OutputStream))
        {
            zipOutputStream.SetLevel(0); // 0 - store only to 9 - means best compression
            response.BufferOutput = false;
            response.AddHeader("Content-Disposition", "attachment; filename=" + zipFileName);
            response.ContentType = "application/octet-stream";

            foreach (var file in files)
            {
                var entry = new ZipEntry(file.FilenameSlug())
                {
                    DateTime = DateTime.Now,
                    Size = file.Filesize
                };
                zipOutputStream.PutNextEntry(entry);
                storageService.ReadToStream(file, zipOutputStream);
                response.Flush();
                if (!response.IsClientConnected)
                {
                   break;
                }
            }
            zipOutputStream.Finish();
            zipOutputStream.Close();
        }
        response.End();
    }

从这里采取generate a Zip file from azure blob storage files

答案 2 :(得分:1)

我注意到了两件事:

  1. 一旦您在流中读取blob内容,您就不会将该流的位置重置为0。因此,zip中的所有文件都是零字节。
  2. 调用AddEntry时,您可能需要指定blob的名称,而不是"File"+cnt
  3. 请查看下面的代码。它是一个控制台应用程序,可以创建zip文件并将其写入本地文件系统。

        static void SaveBlobsToZip()
        {
            string[] str = new string[] { "CodePlex.png", "DocumentDB.png" };
            var account = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
            var blobClient = account.CreateCloudBlobClient();
            var container = blobClient.GetContainerReference("images");
            using (var fs = new FileStream("D:\\output.zip", FileMode.Create))
            {
                fs.Position = 0;
                using (var ms1 = new MemoryStream())
                {
                    using (ZipFile zip = new ZipFile())
                    {
                        int cnt = 0;
                        foreach (string t in str)
                        {
                            var ms = new MemoryStream();
                            container.GetBlockBlobReference(t).DownloadToStream(ms);
                            ms.Position = 0;//This was missing from your code
                            zip.AddEntry(t, ms);//You may want to give the name of the blob here.
                            cnt++;
                        }
                        zip.Save(ms1);
                    }
                    ms1.Position = 0;
                    ms1.CopyTo(fs);
                }
            }
        }
    

    <强>更新

    这是MVC应用程序中的代码(虽然我不确定它是最好的代码:)但它的工作原理)。我稍微修改了你的代码。

        public ActionResult DownloadImagefilesAsZip()
        {
            string[] str = new string[] { "CodePlex.png", "DocumentDB.png" }; //repossitory.GetDocumentsUrlbyId(id);//output:Abc.txt,Pqr.Docx
            CloudBlobContainer blobcontainer = GetCloudBlobContainer();// azureStorageUtility.GetCloudBlobContainer();
            MemoryStream ms1 = new MemoryStream();
            using (ZipFile zip = new ZipFile())
            {
                int cnt = 0;
                foreach (string t in str)
                {
                    var ms = new MemoryStream();
                    CloudBlockBlob blockBlob = blobcontainer.GetBlockBlobReference(t);
                    blockBlob.DownloadToStream(ms);
                    ms.Position = 0;//This was missing from your code
                    zip.AddEntry(t, ms);//You may want to give the name of the blob here.
                    cnt++;
                }
                zip.Save(ms1);
            }
            ms1.Position = 0;
            return File(ms1, "application/zip", "all.zip");
        }