解压缩文件 - Windows Web App 或 Windows 虚拟机哪个更好

Unzip file - Which is better Windows Web App or Windows VIrtual machine

我有一个 Web api 应用程序,目前托管在 Windows Azure Web 应用程序上。现在应用程序用户可以上传 zip 文件,我们要做的是解压缩文件并使用内部文件(我们正在将 zip 上传到 azure 存储)。问题是我无法在存储上解压缩(因为我们无法在存储上执行任何文件)。

我现在担心的是我是否应该在 Azure 上的虚拟机上重新部署我的应用程序,以便我可以将它解压缩到本地驱动器上,然后上传到存储。另一个问题是,我是否可以在 Azure Web App 上做同样的事情。

使用库 SharpZipLib 看起来相当简单。事实上,我对他们的 extract example 几乎没有做任何修改,以修改他们的代码来进行仿真。

我刚刚使用 NuGet 制作了这个演示以添加 SharpZipLib 库并做了这个小演示。它将生成的结构输出为一个名为 {zipfilename}.output 的平面文件,可以很容易地读取和解析它以找到您需要的文件,或者您可以使用数据库,我只是想快速完成此操作。您甚至可以为每个用户创建一个巨大的目录结构文件,并根据需要进行解析和添加。

示例代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Security.Cryptography;

namespace TestApp
{
    class Program
    {
        private static MD5 hash = MD5.Create();
        static void Main(string[] args)
        {
            if(args.Length < 1)
            {
                Console.WriteLine("Usage: TestApp.exe zipfilename [username] [password]");
                return;
            }

            string filename = args[0],
                   username = args.Length == 2 ? args[1] : "default",
                   password = args.Length == 3 ? args[2] : null;

            Dictionary<string, string> emulatedStructure = ExtractZipFile(filename, password, username);

            using(FileStream fs = File.Open(filename+".output",FileMode.OpenOrCreate))
            {
                using (StreamWriter writer = new StreamWriter(fs))
                {
                    foreach(KeyValuePair<string, string> pair in emulatedStructure)
                    {
                        writer.WriteLine(pair.Key + "::>" + pair.Value);
                    }
                }
            }
        }

        private static byte[] CreateBinaryHash(byte[] original)
        {
            hash.Initialize();
            return hash.ComputeHash(original);
        }

        private static string CreateHash(string original, Encoding encoder = null)
        {
            if (encoder == null) encoder = Encoding.UTF8;
            byte[] data = encoder.GetBytes(original);
            data = CreateBinaryHash(data);
            return BitConverter.ToString(data).Replace("-", "");
        }

        private static Dictionary<string, string> ExtractZipFile(string archiveFilenameIn, string password, string UserName = "global")
        {
            Dictionary<string, string> result = new Dictionary<string, string>();

            ZipFile zf = null;
            try
            {
                FileStream fs = File.OpenRead(archiveFilenameIn);
                zf = new ZipFile(fs);
                if (!string.IsNullOrEmpty(password))
                {
                    zf.Password = password;     // AES encrypted entries are handled automatically
                }
                foreach (ZipEntry zipEntry in zf)
                {
                    if (!zipEntry.IsFile)
                    {
                        continue;           // Ignore directories
                    }
                    string entryFileName = zipEntry.Name;
                    // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                    // Optionally match entrynames against a selection list here to skip as desired.
                    // The unpacked length is available in the zipEntry.Size property.
                    byte[] buffer = new byte[4096];     // 4K is optimum
                    Stream zipStream = zf.GetInputStream(zipEntry);

                    // Manipulate the output filename here as desired.
                    string fullZipToPath = UserName+"."+CreateHash(entryFileName)+".dat";

                    /* Since we have a flat structure... Don't do the following lines
                    string directoryName = Path.GetDirectoryName(fullZipToPath);
                    if (directoryName.Length > 0)
                        Directory.CreateDirectory(directoryName);
                    */

                    //Instead we add it to our dictionary which we can store wherever we want, just in case...
                    result.Add(entryFileName, fullZipToPath);

                    // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                    // of the file, but does not waste memory.
                    // The "using" will close the stream even if an exception occurs.
                    using (FileStream streamWriter = File.Create(fullZipToPath))
                    {
                        StreamUtils.Copy(zipStream, streamWriter, buffer);
                    }
                }
            }
            finally
            {
                if (zf != null)
                {
                    zf.IsStreamOwner = true; // Makes close also shut the underlying stream
                    zf.Close(); // Ensure we release resources
                }
            }
            return result;
        }
    }
}

输出到文件夹

以下是我的调试文件夹中使用我手边碰巧有的 zip 生成的文件:

模拟文件夹结构

在输出文件中,您可以找到如下条目:

EXAMPLES/BEER/BEER.ASM::>default.64FB4A2D08609091889912FF1C0AF95F.dat
EXAMPLES/BEER/BEER.EXE::>default.71C7A109E83F012C3E2EC2AC0E3E9AAC.dat
EXAMPLES/DDRAW/DDRAW.ASM::>default.77998184553594A98060D25C2CCC07CF.dat
EXAMPLES/DDRAW/DDRAW.EXE::>default.1AEA6C1F9A10E529659D78148A613362.dat
EXAMPLES/DDRAW/DDRAW.GIF::>default.891567CCBA5742B900C7EBA4D79EEA29.dat
EXAMPLES/DDRAW/DDRAW.INC::>default.70C19235197FE1FAF9BDAAB2C72CC324.dat
EXAMPLES/DDRAW/GIF87A.INC::>default.DCCFB6E469FFBF49BCF03146BE44678E.dat
EXAMPLES/DIALOG/DIALOG.ASM::>default.21A688565E9B4DA98FF306ACC7AB66CF.dat
EXAMPLES/DIALOG/DIALOG.EXE::>default.C5DFA20AA22E8007D4E0CF0128E51459.dat
EXAMPLES/DLL/ERRORMSG.ASM::>default.484A287050330B841576880A69C91148.dat

因此您可以获得 EXAMPLES/DDRAW/DDRAW.ASM 和 zip 中的任何其他文件的正确内容。

我读这不是一个特定于 zip 的问题,而是一个特定于 Azure 的问题,即关于处理 blob 存储中的内容(因为你说你在上传后放置 zip 文件的地方) .

您是正确的,因为您不能直接对 blob 执行任何文件操作(例如解压缩);它必须先从存储下载到本地磁盘(或内存流)。

就 Web 应用程序与虚拟机而言:这完全是一个选择问题,因为两者都有您的应用程序可以获得路径的本地磁盘。

至于解压缩:您使用的 tool/library 完全取决于您(这里不能推荐),并且都可以与您的本地(可写)磁盘一起使用。

您可以在 Azure Web 应用程序上执行此操作,而无需将您的应用程序重新部署到 VM。在您的应用程序中添加 Azure Web Job 运行 是最简单的方法。

实现此目的的一种方法是将所有上传的 zip 文件保存到网络应用程序中的一个文件夹,然后让网络作业定期检查该文件夹以查看其中是否有任何 zip 文件。如果找到,则解压缩该文件并将内容上传到 blob 存储。