FC2ブログ

記事一覧

Zipファイルを解凍する方法 | Xamarin.Forms


今回は Xamarin.Forms で Zip ファイルを解凍する方法についてご紹介いたします。
PCL のみで実装できるかどうか試してみましたが、ZipArchiveEntry.ExtractToFileが正しく動作しませんでしたので、あきらめて DependencyService での実装にしました。iOSとAndroidで全く同じコードになりますが、仕方ありません。今年 Xamarin で正式対応された .Net Standard 2.0 で記述すれば動作するのでしょうか。


前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.8.0.760 (NuGet Xamarin.Forms 2.4.0.282)
・macOS Sierra 10.12.6 / Xcode9 / Xamarin.iOS 11.6.1.4



1.PCLの記述方法

PCL プロジェクト内に DependencyService で呼び出すためのインターフェースを配置します。
※ZipArchiveEntry は .net の参照設定がありますので、PCL に追加の参照設定はありません。

ICompressionService.cs
using System.IO.Compression;
namespace AppName.Services
{
//DependencyServiceから利用する
public interface ICompressionService
{
void UnZip(string filePath, string folderPath);
void ExtractToFile(ZipArchiveEntry entry, string filePath);
}
}



2.Androidの実装方法

まずは、以下の必要な参照設定を追加します。
System.IO.Compression
System.IO.Compression.FileSystem

Droidプロジェクトを右クリックして参照を押下します。

xamarin_zip_compression_03.png


次にAndroid プロジェクト内に CompressionService クラスを配置します。
2バイト文字のファイル名を開く際にエンコードを指定する必要がありました。
※Shift_JIS(932)のエラーが出る場合は、Droid プロジェクトのプロパティからiOS ビルドを選択し、国際化のコードセットに CJK を追加しましょう。

CompressionService.cs
using System.IO;
using System.IO.Compression;
using Xamarin.Forms;
using AppName.Droid.Services;
using AppName.Services;
[assembly: Dependency(typeof(CompressionService))]
namespace AppName.Droid.Services
{
public class CompressionService : ICompressionService
{
/// <summary>
/// Zipファイルを解凍する
/// </summary>
/// <param name="filePath">Zipファイルパス</param>
/// <param name="folderPath">解凍フォルダ</param>
public void UnZip(string filePath, string folderPath)
{
// ファイルを書き出すフォルダーを作成する
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
if (!folderPath.Contains(fileName))
{
folderPath += "/" + fileName;
}
var directoryInfo = System.IO.Directory.CreateDirectory(folderPath);

// ZIPファイルを開いてZipArchiveオブジェクトを作る
using (ZipArchive archive = ZipFile.Open(filePath, ZipArchiveMode.Read, Encoding.GetEncoding("shift_jis")))
{
// 展開するファイルを選択する
var allTextFiles
= archive.Entries
//.Where(e => e.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
.OrderBy(e => e.FullName);

// 選択したファイルを指定したフォルダーに書き出す
foreach (ZipArchiveEntry entry in allTextFiles)
{
// ZipArchiveEntryオブジェクトのExtractToFileメソッドにフルパスを渡す
//entry.ExtractToFile(Path.Combine(folderPath, entry.FullName), true);
//entry.ExtractToFileがXamarinでは動作しないため下記のソースを追加

//展開する時のパスを決定する
string unzipFilePath = Path.Combine(
folderPath, entry.FullName.Replace('/', '\\'));
if (entry.FullName.EndsWith("/"))
{
//ディレクトリの時
//ディレクトリを作成する
System.IO.Directory.CreateDirectory(unzipFilePath);
}
else
{
//ファイルの時
//ディレクトリを作成する
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(unzipFilePath));
//ファイルを開く
this.ExtractToFile(entry, unzipFilePath);
}

}
}
}

/// <summary>
/// ファイルをコピーする
/// </summary>
/// <param name="entry">Zip内のファイルオブジェクト</param>
/// <param name="filePath">コピー先ファイルパス</param>
public void ExtractToFile(ZipArchiveEntry entry, string filePath)
{
using (FileStream fs2 = File.Open(filePath, FileMode.CreateNew, FileAccess.Write))
{
//エントリの内容をファイルにコピーする
using (Stream strm = entry.Open())
{
strm.CopyTo(fs2);
}
}
}
}
}



3.iOSの実装方法

まずは、Android の場合と同様の手順にて、以下の必要な参照設定を追加します。
System.IO.Compression
System.IO.Compression.FileSystem

次に iOS プロジェクト内に CompressionService クラスを配置します。
Android と全く同じソースです。
※Shift_JIS(932)のエラーが出る場合は、iOS プロジェクトのプロパティから iOS ビルドを選択し、国際化のコードセットに CJK を追加しましょう。

CompressionService.cs
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;
using Xamarin.Forms;
using AppName.iOS.Services;
using AppName.Services;
[assembly: Dependency(typeof(CompressionService))]
namespace AppName.iOS.Services
{
public class CompressionService : ICompressionService
{
/// <summary>
/// Zipファイルを解凍する
/// </summary>
/// <param name="filePath">Zipファイルパス</param>
/// <param name="folderPath">解凍フォルダ</param>
public void UnZip(string filePath, string folderPath)
{
// ファイルを書き出すフォルダーを作成する
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
if (!folderPath.Contains(fileName))
{
folderPath += "/" + fileName;
}
var directoryInfo = System.IO.Directory.CreateDirectory(folderPath);

// ZIPファイルを開いてZipArchiveオブジェクトを作る
using (ZipArchive archive = ZipFile.Open(filePath, ZipArchiveMode.Read, Encoding.GetEncoding("shift_jis")))
{
// 展開するファイルを選択する
var allTextFiles
= archive.Entries
//.Where(e => e.FullName.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
.OrderBy(e => e.FullName);

// 選択したファイルを指定したフォルダーに書き出す
foreach (ZipArchiveEntry entry in allTextFiles)
{
// ZipArchiveEntryオブジェクトのExtractToFileメソッドにフルパスを渡す
//entry.ExtractToFile(Path.Combine(folderPath, entry.FullName), true);
//entry.ExtractToFileがXamarinでは動作しないため下記のソースを追加

//展開する時のパスを決定する
string unzipFilePath = Path.Combine(
folderPath, entry.FullName.Replace('/', '\\'));
if (entry.FullName.EndsWith("/"))
{
//ディレクトリの時
//ディレクトリを作成する
System.IO.Directory.CreateDirectory(unzipFilePath);
}
else
{
//ファイルの時
//ディレクトリを作成する
System.IO.Directory.CreateDirectory(Path.GetDirectoryName(unzipFilePath));
//ファイルを開く
this.ExtractToFile(entry, unzipFilePath);
}

}
}
}

/// <summary>
/// ファイルをコピーする
/// </summary>
/// <param name="entry">Zip内のファイルオブジェクト</param>
/// <param name="filePath">コピー先ファイルパス</param>
public void ExtractToFile(ZipArchiveEntry entry, string filePath)
{
using (FileStream fs2 = File.Open(filePath, FileMode.CreateNew, FileAccess.Write))
{
//エントリの内容をファイルにコピーする
using (Stream strm = entry.Open())
{
strm.CopyTo(fs2);
}
}
}
}
}



4.使用方法

PCL プロジェクトの中の任意のページに記述します。
TestPage.xaml.cs
using AppName.Services;
void OnUnCompressButtonClick()
{
string filePath = "zipファイルのフルパス";
string folderPath = "解凍先のフォルダパス";
    DependencyService.Get<ICompressionService>().UnZip(filePath, folderPath);
}

※ここでご紹介している解凍方法ではパスワード付きのZipファイルを解凍できません。パスワード付きの場合は、NuGetパッケージマネージャーからSharpZipLibをインストールして実装しましょう。



5.SharpZipLib

Xamarin.Forms ではたくさんのネイティブコードを記述しなければなりませんでしたが、SharpZipLib ではたった数行記述するだけで簡単に実装できてしまいます。
NuGet パッケージマネージャから SharpZipLib で検索してインストールします。
次に PCL プロジェクトの任意のページに以下のように実装するだけです。

TestPage.xaml.cs
void OnUnCompressButtonClick()
{
string filePath = "zipファイルのフルパス";
string folderPath = "解凍先のフォルダパス";
string password = "解凍パスワード";
    ICSharpCode.SharpZipLib.Zip.FastZip zip = new ICSharpCode.SharpZipLib.Zip.FastZip();
if (!String.IsNullOrEmpty(password))
{
zip.Password = password;
}
zip.ExtractZip(filePath, folderPath, "");
}

※ただし、SharpZipLibでは解凍フォルダまでは作成してくれませんので、DependencyServiceで作成したCreateDirecory関数等で解凍用のフォルダを作成したほうが良いでしょう。( zip.CreateEmptyDirectories = true; としても作成されませんでした。)また、サブディレクトリを含む場合も作成してくれず、「フォルダ名/ファイル名」といったファイル名になってしまいます。






最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html



関連記事

コメント

コメントの投稿

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。