解压缩文件 - 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 存储。
我有一个 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 存储。