概要
表題の通り
Visual Studio 2019のC#にて、
Visual Studio 2019のC#にて、直接バイナリを叩いて指定ファイルをzipに無圧縮アーカブする。
コードのサンプルでございます。
特段、NuGetなどで他のプラグインや
別途外部dllを必要としないようにしています。
原理的なことは、以下のニコニコ動画にて公開しております。
『自力でzipしてみた』
https://www.nicovideo.jp/watch/sm27938612
要は、バイナリを以下のように、直接叩いています。
1.zipのヘッダーを書き込む。
2.ファイルのバイナリを読み込み。
3.そのままファイルバイナリを横流して書き込み。
4.zipの中間の事項と、フッターを書き込む。
Javaが無い環境下などで、
とにかく無圧縮でもいいからzipを作成したい場合があり、
それに依存しないで、zipをファイルに書き出すことにしたため
作成いたしました。
このQiitaに投稿している、
Visual Studio 2019のC#にて、中のxmlを直接叩いてODSを出力する。コードのサンプルです。
でも、
ODSは、実質中身は、zipファイルなので
今回の内容と重複する部分がございます。
参考サイト
[zip内部に関しての参考サイト]
・ APPNOTE.TXT - .ZIP File Format Specification
・ZIP書庫ファイル フォーマット - 略して仮。
・The structure of a PKZip file
・自力でzipしてみた - ニコニコ動画
※└→私が勝手にまとめた動画です。
[コードに関しての参考サイト]
・[VBA]CRC-32の計算 言語: VB.NET
・C#实现crc32函数 - 时间是把杀刀猪 - CSDN博客
・A CRC32 implementation in C# - Sanity Free Coding - C#, .NET, PHP
内部コード
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
public class clsZIP
{
//無圧縮でZIPにアーカイブするコード
//→とにかく無圧縮でいいから、Javaなどがない環境下で、ファイルをZIPにアーカイブしたい。という際での使用を想定。
//偉大な参考URL様
//[zipの構造に関して]
//https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
//http://www.tvg.ne.jp/menyukko/cauldron/dtzipformat.html
//https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html
//他、コード中のURLは、参考サイト様です。
//■Local file header関係+++++++++++++++++++++++++++++++++++++++++++++++
//Local file headerの識別子 4bytes(0x04034b50)
readonly byte[] local_file_header_signature = BitConverter.GetBytes(Convert.ToInt32(0x4034B50));
//解凍に最低必要なバージョン 2bytes 今回は、ver.1.0で、無圧縮を指定(Default value)→0x000A
readonly byte[] version_needed_to_extract = BitConverter.GetBytes(Convert.ToInt16(0xA));
//オプションフラグと、圧縮方法 2+2bytes{今回はオプションもなく、圧縮もしないので、0を指定共に0x0000}
readonly byte[] general_purpose_and_compression_method = BitConverter.GetBytes(Convert.ToInt32(0x0));
//CRC-32 4bytes{アーカイブ前の生ファイルから生成するCRC32}
byte[] crc_32;
List<byte[]> ary_crc_32s = null; //zip内の各ファイルの、CRC-32を格納。
//圧縮後のファイルサイズ 4bytes{今回は無圧縮なので圧縮前の値と同値}
//圧縮前のファイルサイズ 4bytes
byte[] compressed_size;
List<byte[]> ary_uncompressed_sizes = null; //zip内の各ファイルの、圧縮前のファイルサイズを格納。
//アーカイブ前のファイル名のサイズを格納する 2bytes
string file_name; //ファイル名
byte[] file_name_ary; // ファイル名のバイナリ
List<byte[]> ary_file_name_arys = null; //zip内の各ファイルの、ファイル名のバイナリを格納。
byte[] file_name_length; //ファイル名のバイナリサイズ
//拡張フィールドのサイズ 2bytes{今回は、指定しないので0x0000}
readonly byte[] extra_field_length = BitConverter.GetBytes(Convert.ToInt16(0x0));
//■Central file header関係+++++++++++++++++++++++++++++++++++++++++++++++
//Central file headerの識別子 4bytes(0x02014b50)
readonly byte[] central_file_header_signature = BitConverter.GetBytes(Convert.ToInt32(0x2014B50));
//作成したバージョン 1+1bytes{今回は、ver.1.0で、無圧縮を指定(Default value)→0x000A }
readonly byte[] version_made_by = BitConverter.GetBytes(Convert.ToInt16(0xA));
//ファイルの属性などの情報 2+2+2+4bytes → 今回は無視するのですべて0
readonly byte[] file_attributes_etc = new byte[10] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//対応するファイルのlocal file header信号のある位置 4bytes
//出力zipの各local_file_header signatureの、バイト開始位置を示す4バイトのバイナリ配列を格納。
List<Int32> relative_offset_of_local_header = null;
//■End of central directory record関係+++++++++++++++++++++++++++++++++++++++++++++++
//End of central directory record 4bytes(0x06054b50)
readonly byte[] end_of_central_dir_signature = BitConverter.GetBytes(Convert.ToInt32(0x6054B50));
//ディスク分割情報 2+2bytes{ディスク分割はしていないのですべて0}
readonly byte[] number_of_this_disk = BitConverter.GetBytes(Convert.ToInt32(0x0));
//アーカイブしたファイルの個数 2+2bytes{ディスク分割はしていないので同じ内容の重複}
byte[] total_number_of_entries;
//全Central file headerに要したの合計バイト数 4bytes
byte[] size_of_the_central_directory;
//最初のCentral file headerの記述されたバイト位置 4bytes
long offset_of_start_of_central_directory_int;
byte[] offset_of_start_of_central_directory;
//zipファイルへのコメントのサイズ 2bytes{今回は、指定しないので0x0000}
readonly byte[] ZIP_file_comment_length = BitConverter.GetBytes(Convert.ToInt16(0x0));
//◆zipファイル入出力など、取扱関係+++++++++++++++++++++++++++++
//出力zipのバイナリ一時格納用。
List<byte> ary_zip_file = null;
//ファイルの各更新日時・時間を格納
List<byte[]> ary_last_mod_file_dates = null;
List<byte[]> ary_last_mod_file_times = null;
//出力zipにアーカイブするファイルのパスのリスト
List<string> Archive_List = null;
public async System.Threading.Tasks.Task archive_to_zip(string[] Archive_FilePath_List) {
//ファイルを、zipにアーカイブするルーチン
//※簡素記述のためメモリをガッツリ使用します。ご注意を。
//★前処理。****************************************************************************************
//●出力するzipファイル・フルパスの作成++++++++++++++++++++++++++++++++++++++
//→先頭のファイル名から、Shift_JISに統一して生成
string Output_zip_FileName = FileNeme_Shift_JIS_Check(
Path.GetFileNameWithoutExtension(Archive_FilePath_List[0])) + ".zip";
//出力パスと結合して、フルパスを生成
//今回は、先頭ファイルと同じ階層に作成することとする。
string Output_zip_Directory = Path.GetDirectoryName(Archive_FilePath_List[0]);
string Output_zip_Path = Path.Combine(Output_zip_Directory, Output_zip_FileName);
//作ろうとしている同名zipファイルが存在しなくなるまでループ
int zip_making_flg = 0;
while (File.Exists(Output_zip_Path)) {
Output_zip_Path = Path.Combine(Output_zip_Directory, Output_zip_FileName.Replace(".zip", "") + "[" + zip_making_flg.ToString() + "].zip");
zip_making_flg += 1; //同名ファイルがなくなるまで連番にする
}
//初期化
Archive_List = new List<string> { };
Archive_List.Clear();
//有効なファイルを選別&格納するリストの生成。++++++++++++++++++++++++++++++++++++++
//予約したリストの中から、処理するファイルをサブフォルダ内部を含めて全て列挙する。
foreach (string filepath in Archive_FilePath_List) {
FileAry_Set(filepath);
}
//有効なファイルがなかった場合++++++++++++++++++++++++++++++++++++++
if (Archive_List.Count <= 0) { return; }
//基準となるフォルダパスを取得++++++++++++++++++++++++++++++++++++++
string BaseDirName = BaseDirName_Get(
Path.GetDirectoryName(Archive_List[0]));
//Shift-JISに統一する。
BaseDirName = FileNeme_Shift_JIS_Check(BaseDirName);
//◎使用する各配列の初期化++++++++++++++++++++++++++
ary_zip_file = new List<byte> { };
ary_last_mod_file_dates = new List<byte[]> { };
ary_last_mod_file_times = new List<byte[]> { };
ary_crc_32s = new List<byte[]> { };
ary_uncompressed_sizes = new List<byte[]> { };
ary_file_name_arys = new List<byte[]> { };
relative_offset_of_local_header = new List<Int32> { };
//zipは、無圧縮で自分でバイナリを打っていく。
using (System.IO.FileStream fs = new System.IO.FileStream(Output_zip_Path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
//★前半戦。Local file headerとバイナリ本体の記述********************************************
//各ファイルごとにループする
foreach (string FileName in Archive_List) {
//アーカイブする元ファイルを開きバイナリを予め保持する。
byte[] moto_bs = new byte[] { 0 };
try {
using (FileStream moto_fs = new FileStream(FileName,
System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) {
//ファイルを読み込むバイト型配列を作成する
Array.Resize(ref moto_bs, (int)moto_fs.Length);
//ファイルのバイナリを一度にすべて読み込んでおく(※メモリ使用量の増大注意)
moto_fs.Read(moto_bs, 0, moto_bs.Length);
//ファイルを閉じる
moto_fs.Close();
}
}
catch { continue; }
//■Local file headerの作成------------ここから-----------------
//●予めlocal_file_header_signatureの記述位置を格納しておく(4バイト)
relative_offset_of_local_header.Add(Convert.ToInt32(fs.Length)); //つまり現在のファイルサイズ
//○local_file_header_signatureの記述(4バイト)
ary_zip_file.AddRange(local_file_header_signature);
//○解凍に必要なバージョンの記述(2バイト)
ary_zip_file.AddRange(version_needed_to_extract);
//○オプションフラグと、圧縮方法の記述(2+2バイト)
ary_zip_file.AddRange(general_purpose_and_compression_method);
//○ファイルの更新時刻を取得&格納(2バイト)//////////////////////////////////
DateTime F_time = File.GetLastWriteTime(FileName);
//▽ファイル更新日時をビット記述(全部で16ビット=2バイト)
string F_time_str = "";
string fff = ""; //2進数一時格納用
//Hourの取得&ビット化
fff = Convert.ToString(F_time.Hour, 2);
while (fff.Length != 5) { //5ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//Minuteの取得&ビット化
fff = Convert.ToString(F_time.Minute, 2);
while (fff.Length != 6) { //6ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//Secondの取得(偶数化する)&ビット化
fff = Convert.ToString((int)(F_time.Second / 2), 2);
while (fff.Length != 5) { //5ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//出来たビット文字列を2バイトに落とし込み記述する。
byte[] last_mod_file_time = BitConverter.GetBytes(Convert.ToInt16(F_time_str, 2));
ary_zip_file.AddRange(last_mod_file_time);
//再計算が面倒なので、central file headerに再利用するためにここで記憶しておく。
//※メモリを消費します。すみません。AddRangeでなく配列ごと格納しているのも、注意。
ary_last_mod_file_times.Add(last_mod_file_time);
//▽ファイルの更新年月日を取得&格納(2バイト)//////////////////////////////////
F_time_str = ""; //初期化
//Year(1980年からの経過年数)の取得&ビット化
fff = Convert.ToString(F_time.Year - 1980, 2);
while (fff.Length != 7) { //7ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//Monthの取得&ビット化
fff = Convert.ToString(F_time.Month, 2);
while (fff.Length != 4) { //4ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//Dayの取得&ビット化
fff = Convert.ToString(F_time.Day, 2);
while (fff.Length != 5) { //5ビットまで用意
fff = "0" + fff;
}
F_time_str += fff;
//出来たビット文字列を2バイトに落とし込み記述する。
byte[] last_mod_file_date = BitConverter.GetBytes(Convert.ToInt16(F_time_str, 2));
ary_zip_file.AddRange(last_mod_file_date);
//再計算が面倒なので、central file headerに再利用するために記憶しておく。
ary_last_mod_file_dates.Add(last_mod_file_date);
//○CRC32(4バイト)
//元ファイルのバイナリからCRC-32を取得する。
crc_32 = await CRC_32_Checksum(moto_bs);
ary_zip_file.AddRange(crc_32);
//再計算が面倒なので、central file headerに再利用するために記憶しておく。
ary_crc_32s.Add(crc_32);
//○圧縮後のファイルサイズの取得(4バイト){無圧縮なので圧縮後のサイズと同値}
compressed_size = BitConverter.GetBytes(Convert.ToInt32(moto_bs.Length));
ary_zip_file.AddRange(compressed_size);
//○圧縮前のファイルサイズの取得(4バイト){無圧縮なので圧縮後のサイズと同値}
ary_zip_file.AddRange(compressed_size);
//再計算が面倒なので、central file headerに再利用するために記憶しておく。
ary_uncompressed_sizes.Add(compressed_size);
//○圧縮前のファイル名のサイズの取得(2バイト)
file_name = FileNeme_Shift_JIS_Check(FileName); //Shift-JISで初期化
//親元のフォルダパス部分を削除してzip内でのファイルパスを確定する
file_name = file_name.Replace(BaseDirName, "");
if (file_name.Length > 1 && file_name.StartsWith("\\"))
{ //左に余分にできる\マークを消す
file_name = file_name.Substring(1, file_name.Length - 1);
}
//文字列をバイナリ化する
file_name_ary = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes(file_name);
//文字列長を取得する。
file_name_length = BitConverter.GetBytes(Convert.ToInt16(file_name_ary.Length));
ary_zip_file.AddRange(file_name_length); // 格納
//○拡張フィールドのサイズ指定(2バイト){今回は指定なし}
ary_zip_file.AddRange(extra_field_length); //格納
//○アーカイブ前のファイル名の格納
ary_zip_file.AddRange(file_name_ary);
//再計算が面倒なので、file_name_aryに再利用するために記憶しておく。
ary_file_name_arys.Add(file_name_ary);
try
{ //一旦、書き貯めたバイト型配列の内容をファイルに出力する
fs.Write(ary_zip_file.ToArray(), 0, ary_zip_file.Count);
fs.Flush();
}
catch { }
ary_zip_file.Clear(); //初期化
//■Local file headerの作成------------ここまで-----------------
//■ファイル本体のバイナリを書き込む
try
{ //ファイルに出力する
fs.Write(moto_bs, 0, moto_bs.Length);
fs.Flush();
}
catch { }
//初期化
await System.Threading.Tasks.Task.Delay(10);//これがないと、書き込み途中で放棄される??
Array.Clear(moto_bs, 0, moto_bs.Length);
}
//★中盤戦。central file headerの記述********************************************
//予め最初のCentral file headerの記述開始バイト位置を記憶しておく
offset_of_start_of_central_directory_int = fs.Length;
offset_of_start_of_central_directory = BitConverter.GetBytes(Convert.ToInt32(offset_of_start_of_central_directory_int));
//各ファイル分ループ
for (int i = 0; i < ary_file_name_arys.Count; i++)
{
byte[] bs;
//■central file headerの作成------------ここから-----------------
//○central_file_header_signatureの記述(4バイト)
ary_zip_file.AddRange(central_file_header_signature);
//○zipを作った時のバージョンとOSの記述(1+1バイト)
ary_zip_file.AddRange(version_made_by);
//○解凍に必要なバージョンの記述(2バイト)
ary_zip_file.AddRange(version_needed_to_extract);
//○オプションフラグと圧縮方法の記述(2+2バイト)
ary_zip_file.AddRange(general_purpose_and_compression_method);
//○ファイルの更新時刻(2バイト)[固定値]
ary_zip_file.AddRange(ary_last_mod_file_times[i]);
//○ファイルの更新年月日(2バイト)[固定値]
ary_zip_file.AddRange(ary_last_mod_file_dates[i]);
//○CRC-32(4バイト)
ary_zip_file.AddRange(ary_crc_32s[i]);
//○圧縮後のファイルサイズ(4バイト) {今回は、無圧縮なので、圧縮前のファイルサイズを流用}
bs = ary_uncompressed_sizes[i];
ary_zip_file.AddRange(bs);
//○圧縮前のファイルサイズ(4バイト)
ary_zip_file.AddRange(bs);
Array.Clear(bs, 0, bs.Length);//初期化
//○ファイル名のサイズ(2バイト)
byte[] name_bs = ary_file_name_arys[i];
ary_zip_file.AddRange(BitConverter.GetBytes(Convert.ToInt16(name_bs.Length)));
//○拡張フィールドのサイズ(2バイト)
ary_zip_file.AddRange(extra_field_length);
//○ファイルの属性などの情報(2+2+2+4バイト)
ary_zip_file.AddRange(file_attributes_etc);
//○対応するファイルのlocal File header信号のある位置(4バイト)
bs = BitConverter.GetBytes(relative_offset_of_local_header[i]);
ary_zip_file.AddRange(bs);
Array.Clear(bs, 0, bs.Length);//初期化
//○アーカイブ前のファイル名の格納
ary_zip_file.AddRange(name_bs);
Array.Clear(name_bs, 0, name_bs.Length);//初期化
try
{ //一旦、書き貯めたバイト型配列の内容をファイルに出力する
fs.Write(ary_zip_file.ToArray(), 0, ary_zip_file.Count);
fs.Flush();
}
catch { }
ary_zip_file.Clear(); //初期化
//■central file headerの作成------------ここまで-----------------
await System.Threading.Tasks.Task.Delay(10);
}
//◎使用する各配列の一旦、クリア++++++++++++++++++++++++++
ary_crc_32s.Clear();
ary_uncompressed_sizes.Clear();
relative_offset_of_local_header.Clear();
//★終盤戦End of central directory recordの記述********************************************
//全Central file headerに要したの合計バイト数を予め算出しておく
size_of_the_central_directory = BitConverter.GetBytes(
Convert.ToInt32(fs.Length - offset_of_start_of_central_directory_int));
//■End of central directory recordの作成------------ここから-----------------
//○end_of_central_dir_signatureの記述(4バイト)
ary_zip_file.AddRange(end_of_central_dir_signature);
//○ディスク分割情報(2+2バイト)
ary_zip_file.AddRange(number_of_this_disk);
//○アーカイブしたファイルの個数(2+2バイト){同じ内容を重複して格納}
total_number_of_entries = BitConverter.GetBytes(Convert.ToInt16(ary_file_name_arys.Count));
ary_zip_file.AddRange(total_number_of_entries);
ary_zip_file.AddRange(total_number_of_entries); //※重複分
//○全Central file headerに要したの合計バイト数を格納(4バイト)
ary_zip_file.AddRange(size_of_the_central_directory);
//○最初のCentral file headerの記述されたバイト位置(4バイト)
ary_zip_file.AddRange(offset_of_start_of_central_directory);
//○ファイルへのコメントのサイズ(2バイト){今回はなし}
ary_zip_file.AddRange(ZIP_file_comment_length);
try
{ //一旦、書き貯めたバイト型配列の内容をファイルに出力する
fs.Write(ary_zip_file.ToArray(), 0, ary_zip_file.Count);
fs.Flush();
await System.Threading.Tasks.Task.Delay(10);//これがないと、書き込み途中で放棄される??
}
catch { }
ary_zip_file.Clear(); //初期化
//■End of central directory recordの作成------------ここまで-----------------
//バイナリ・メモリの占有を開放する。
ary_zip_file.Clear();
ary_zip_file = null;
//初期化
Archive_List.Clear();
Archive_List = null;
}
}
private string FileNeme_Shift_JIS_Check(string Motono_FileName) {
//■文字コードをシフトJISに、統一して、禁止文字を削除する。
//一旦、シフトJISとしてバイナリ化
byte[] bytesData = Encoding.GetEncoding(932).GetBytes(Motono_FileName);
//Shift JISとして文字列に還元する。
Motono_FileName = Encoding.GetEncoding(932).GetString(bytesData);
//ファイル名に使用できない文字があれば消す
//http://dobon.net/vb/dotnet/file/invalidpathchars.html
foreach (char invalidChars in Path.GetInvalidFileNameChars()) {
//パスの区切り文字は除外しておく
if ((invalidChars == '\\') || (invalidChars == '/')) { continue; }
if (Motono_FileName.IndexOf(invalidChars) > 0)
{ //禁止文字はすべて_に置換しておく
Motono_FileName = Motono_FileName.Replace(invalidChars, '_');
}
}
//チェック後の文字列を返す
return Motono_FileName;
}
private string BaseDirName_Get(string DirName) {
//zip圧縮する際に、基準となる親フォルダのパスを検知・取得する。
//初期値
string BaseDirName = DirName;
//空白の場合はコロンを返す
if (DirName == "") { return ":"; }
string[] Archive_FilePath_List = Archive_List.ToArray();
foreach (string fff in Archive_FilePath_List) {
//親元となるフォルダパスを検索する
for (int i = 1; i < BaseDirName.Length; i++) {
if (fff.Substring(0, i) != BaseDirName.Substring(0, i)) {
//最初の親元となるフォルダパスと相違点が見つかった場合
//さらに上のフォルダを親元のフォルダとする。
BaseDirName = Path.GetDirectoryName(BaseDirName);
break; //出る
}
}
}
//得られた基幹となるフォルダ名を返す
//空白の場合はコロンを返す。安全装置
if (BaseDirName == "") {
return ":";
}
else {
return BaseDirName;
}
}
private void FileAry_Set(string File_DirName) {
//有効なファイルをArchive_Listリストに加える。
if (Directory.Exists(File_DirName)) {
//それがフォルダだった場合
if (Directory.GetDirectories(File_DirName).Length == 0
&& Directory.GetFiles(File_DirName).Length == 0) {
//空のフォルダだった場合
//\記号を末尾につけて、zip追加リストに加える
Archive_List.Add(File_DirName + "\\");
return; //出る
}
//ファイルを加える
Archive_List.AddRange(Directory.GetFiles(File_DirName)); //zip追加リストに加える
//サブフォルダも検索する
foreach (string subFolder in Directory.GetDirectories(File_DirName)) {
//自己参照する。
FileAry_Set(subFolder);
}
}
else if (File.Exists(File_DirName))
{
//それがファイルだった場合
Archive_List.Add(File_DirName); //zip追加リストに加える
}
}
private async System.Threading.Tasks.Task<byte[]> CRC_32_Checksum(byte[] bytes)
{
//★CRC32の計算をするところ
//UIntegerの方法では、上手くできないのですorz
//また、返数をByte()でなく、Long型にすると、値が狂います。
//https://code.msdn.microsoft.com/office/VBACRC-32-dad7d087
//https://blog.csdn.net/ciaos/article/details/12490911
//http://sanity-free.org/12/crc32_implementation_in_csharp.html
//計算に時間がかかるので、待機させる
System.Threading.Tasks.Task<byte[]> uploadTask = System.Threading.Tasks.Task.Factory.StartNew<byte[]>(
() => {
//■CRC32のテーブル情報の事前生成
uint[] crc32Table = new UInt32[256];
//CRC-32 の除数0x104c11db7を、予めビットの並び順を左右逆転させた値(0xEDB88320) を使用する。
uint poly = 0xedb88320;
uint temp = 0;
for (uint i = 0; i < crc32Table.Length; ++i)
{
temp = i;
for (int j = 8; j > 0; --j)
{
if ((temp & 1) == 1) //&で、andのビット演算
{
temp = (uint)((temp >> 1) ^ poly); //^で、xorのビット演算
}
else
{
temp >>= 1; //÷(2の1乗)と同じ効果
}
}
crc32Table[i] = temp;
}
//初期化
uint crc = 0xffffffff;
//■渡されたファイルのバイナリから、CRC-32を算出して返す
for (int i = 0; i < bytes.Length; ++i)
{ //■計算の引き合いに出すテーブルのインデックス番号の算出
byte index = (byte)(((crc) & 0xff) ^ bytes[i]);
//■次のビットにスライドする。
//→(crc >> 8)は、crcを(2の8乗)で割っていることと同義
crc = (uint)((crc >> 8) ^ crc32Table[index]);
}
//ビット反転後バイト配列に変換して返す
return BitConverter.GetBytes(~crc); //^で、notのビット演算
});
return await uploadTask;
}
}
例えば、
以下のようなコードで、ファイルを選択して
変換することが出来ます。
private async void Form1_Load(object sender, EventArgs e)
{ //ここは適当に記述しています。
using (OpenFileDialog fileDialog = new OpenFileDialog())
{ //PDFに直接変換したい画像ファイルを複数選択できるようにしている。
fileDialog.Filter = "アーカイブするデータ|*.*";
fileDialog.Multiselect = true;
//「開く」ボタンが選択された時の処理
if (fileDialog.ShowDialog() == DialogResult.OK)
{
//変換したい画像のリストを取得
string[] fileNames = fileDialog.FileNames; //こんな感じで選択されたファイルのパスが取得できる
//PDFは、今回は仮に、最初のファイルと同じフォルダに「test.pdf」として生成される。
clsZIP cls = new clsZIP();
await cls.archive_to_zip(fileNames);
//おしまいのメッセージ
MessageBox.Show("END");
}
}
//さようなら
Application.Exit();
}
以上のコードを実行すると
指定したファイルと同じ階層のフォルダに、zipが出力されてあると思います。
おまけ
尚、アーカイブする際の更新日時をうまくして
アーカイブすれば、
アーカイブしたファイルのタイムスタンプが、任意に変えられます。