ファイルが現在メモリにある場合、複数のファイルを含む Zip アーカイブを作成する方法はありますか? 保存したいファイルは実際にはテキストのみで、アプリケーションの文字列クラスに保存されています。しかし、複数のファイルを単一の自己完結型アーカイブに保存したいと考えています。それらはすべてアーカイブのルートにある可能性があります。
SharpZipLib を使用してこれを実行できると便利です。
ファイルが現在メモリにある場合、複数のファイルを含む Zip アーカイブを作成する方法はありますか? 保存したいファイルは実際にはテキストのみで、アプリケーションの文字列クラスに保存されています。しかし、複数のファイルを単一の自己完結型アーカイブに保存したいと考えています。それらはすべてアーカイブのルートにある可能性があります。
SharpZipLib を使用してこれを実行できると便利です。
これにはとを使用ZipEntry
しPutNextEntry()
ます。以下は、ファイルに対してそれを行う方法を示していますが、メモリ内オブジェクトに対しては、MemoryStreamを使用するだけです。
FileStream fZip = File.Create(compressedOutputFile);
ZipOutputStream zipOStream = new ZipOutputStream(fZip);
foreach (FileInfo fi in allfiles)
{
ZipEntry entry = new ZipEntry((fi.Name));
zipOStream.PutNextEntry(entry);
FileStream fs = File.OpenRead(fi.FullName);
try
{
byte[] transferBuffer[1024];
do
{
bytesRead = fs.Read(transferBuffer, 0, transferBuffer.Length);
zipOStream.Write(transferBuffer, 0, bytesRead);
}
while (bytesRead > 0);
}
finally
{
fs.Close();
}
}
zipOStream.Finish();
zipOStream.Close();
これに SharpZipLib を使用するのはかなり複雑に思えます。これはDotNetZipでとても簡単です。v1.9 では、コードは次のようになります。
using (ZipFile zip = new ZipFile())
{
zip.AddEntry("Readme.txt", stringContent1);
zip.AddEntry("readings/Data.csv", stringContent2);
zip.AddEntry("readings/Index.xml", stringContent3);
zip.Save("Archive1.zip");
}
上記のコードは、stringContent{1,2,3} に、zip アーカイブのファイル (またはエントリ) に格納されるデータが含まれていることを前提としています。最初のエントリは「Readme.txt」で、zip アーカイブの最上位の「ディレクトリ」に保存されます。次の 2 つのエントリは、zip アーカイブの「readings」ディレクトリに保存されます。
文字列はデフォルトのエンコーディングでエンコードされます。ここには示されていませんが、使用するエンコーディングを明示的に指定できる AddEntry() のオーバーロードがあります。
文字列ではなく、ストリームまたはバイト配列にコンテンツがある場合、これらの型を受け入れる AddEntry() のオーバーロードがあります。Write デリゲートを受け入れるオーバーロードもあります。これは、データを zip に書き込むために呼び出される独自のメソッドです。これは、たとえば、DataSet を zip ファイルに簡単に保存する場合に機能します。
DotNetZip は無料のオープン ソースです。
このクラスを作成した MSDN の例を使用して、この問題に遭遇しました。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Packaging;
using System.IO;
public class ZipSticle
{
Package package;
public ZipSticle(Stream s)
{
package = ZipPackage.Open(s, FileMode.Create);
}
public void Add(Stream stream, string Name)
{
Uri partUriDocument = PackUriHelper.CreatePartUri(new Uri(Name, UriKind.Relative));
PackagePart packagePartDocument = package.CreatePart(partUriDocument, "");
CopyStream(stream, packagePartDocument.GetStream());
stream.Close();
}
private static void CopyStream(Stream source, Stream target)
{
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
target.Write(buf, 0, bytesRead);
}
public void Close()
{
package.Close();
}
}
その後、次のように使用できます。
FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);
ZipSticle zip = new ZipSticle(str);
zip.Add(File.OpenRead("C:/Users/C0BRA/SimpleFile.txt"), "Some directory/SimpleFile.txt");
zip.Add(File.OpenRead("C:/Users/C0BRA/Hurp.derp"), "hurp.Derp");
zip.Close();
str.Close();
MemoryStream
a (または any Stream
) をZipSticle.Add
次のように渡すことができます。
FileStream str = File.Open("MyAwesomeZip.zip", FileMode.Create);
ZipSticle zip = new ZipSticle(str);
byte[] fileinmem = new byte[1000];
// Do stuff to FileInMemory
MemoryStream memstr = new MemoryStream(fileinmem);
zip.Add(memstr, "Some directory/SimpleFile.txt");
memstr.Close();
zip.Close();
str.Close();
はい、SharpZipLib を使用してこれを行うことができます。書き込み先のストリームを提供する必要がある場合は、MemoryStream
.
この回答は古くなっていることに注意してください。.Net 4.5以降、このZipArchive
クラスではファイルをメモリ内で圧縮できます。使用方法については、以下のjohnny5の回答を参照してください。
また、Serializableオブジェクトを使用してすべての文字列を格納することで、少し異なる方法で行うこともできます。
[Serializable]
public class MyStrings {
public string Foo { get; set; }
public string Bar { get; set; }
}
次に、それをストリームにシリアル化して保存できます。
スペースを節約するために、GZipStream(From System.IO.Compression)を使用して圧縮することができます。(注:GZipはストリーム圧縮であり、複数のファイルのアーカイブではありません)。
つまり、もちろん、必要なのが実際にデータを保存することであり、他のソフトウェア用に特定の形式でいくつかのファイルを圧縮することではない場合です。また、これにより、文字列以外のより多くの種類のデータを保存できます。
StringReaderを使用して文字列オブジェクトから読み取り、それらを Stream として公開します。
これにより、それらをzipビルドコードに簡単にフィードできるようになります.