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 / Xcode 9 / 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 プロジェクトのプロパティから Androidオプションを選択し、国際化のコードセットに 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
using AppName.Services;
using Xamarin.Forms;
public class TestPage : ContentPage
{
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からご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html



関連記事

コメント

コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


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

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

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