前回に引き続き、csFileListをちゃちゃっとやっつけちゃいましょう。
3.csFileList.cs(メソッド編)
前回はフォーム(ウィンドウ)の見てくれの部分(どんがら)について説明しましたので、今回は機能面(メソッド)について「青字」解説します。
//////////////////////////
//ツールバー関連メソッド
//////////////////////////
//「ファイルリストを開く」処理
private void OnOpen_Click(object sender, EventArgs e)
{
DialogResult dr = MessageBox.Show("ファイルリスト入れ替えますか(はい)、または\r\n追加しますか(いいえ)?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(dr == DialogResult.Yes)
{
file_List.Items.Clear(); //入替えの場合、リストビュー内の項目を全削除
}
OpenFileDialog ofDlg = new OpenFileDialog();
ofDlg.Filter = "アルバムファイル(*.alb)|*.alb|プレイリストファイル(*.plf)|*.plf|すべてのファイル(*.*)|*.*"; //ファイルフィルターの指定(解説:自作のソフトであるAlbumとDirectShowのファイルリストを扱っています。)
ofDlg.FilterIndex = 1; //ファイルフィルターインデックスの指定
ofDlg.RestoreDirectory = true; //ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
ofDlg.CheckFileExists = true; //存在しないファイルの名前が指定されたとき警告を表示する
ofDlg.CheckPathExists = true; //存在しないパスが指定されたとき警告を表示する
ofDlg.InitialDirectory = @".\"; //デフォルトのフォルダを指定する
ofDlg.Title = "ファイルリストを開く"; //ダイアログのタイトルを指定する
if(ofDlg.ShowDialog() == DialogResult.OK) //ダイアログを表示する
{
//ファイル("shift_jis")を開く(解説:ファイル入出力エラーが考えられ、usingを使用しています。)
using(StreamReader sr = new StreamReader(ofDlg.FileName, System.Text.Encoding.GetEncoding("shift_jis")))
{
//1行ずつ処理
while(!sr.EndOfStream){
string line = sr.ReadLine();
//カンマで配列要素を分ける(最初の要素がファイルパス、名を前提とする)
string[] fns = line.Split(',');
//第1要素のファイルパス、名が'"'で括られていれば削除する
string fn = fns[0].Trim('"');
//ファイルが存在するか、フォールダーではないか、をチェックする
if(!File.Exists(fn))
{
MessageBox.Show("このファイルは存在しません。\r\n" + fn, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue; //解説:ファイルが(または「で」)なければ、次に行きます。)
}
ListViewItem item = file_List.Items.Add(Path.GetFileName(fn));
item.SubItems.Add(Path.GetDirectoryName(fn));
}
sr.Close();
}
if(file_List.Items.Count > 0)
{
//ツールバーボタンを有効化する(解説:ファイルの追加の際はこれを行います。)
ChangeToolBarStatus(true);
//ファイル数を更新する(解説:ファイルの追加の際はこれを行います。)
ShowNumOfFiles();
}
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
ofDlg.Dispose();
}
//「ファイルリストを保存」処理(解説:本来は不要ですが、「何を処理したっけ?」ということもあるので...)
private void OnSave_Click(object sender, EventArgs e)
{
//選択されたファイルパス、名をfilesに纏める
string files = "";
foreach(ListViewItem item in file_List.Items)
{
files += "\"" + item.SubItems[1].Text + "\\" + item.SubItems[0].Text + "\"\r\n";
}
//書き込みファイルを指定
SaveFileDialog sfDlg = new SaveFileDialog();
sfDlg.Filter = "アルバムファイル(*.alb)|*.alb|プレイリストファイル(*.plf)|*.plf|すべてのファイル(*.*)|*.*"; //ファイルフィルターの指定
sfDlg.FilterIndex = 3; //ファイルフィルターインデックスの指定
sfDlg.RestoreDirectory = true; //ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
sfDlg.CheckPathExists = true; //存在しないパスが指定されたとき警告を表示する
sfDlg.InitialDirectory = @".\"; //デフォルトのフォルダを指定する
sfDlg.Title = "ファイルリストを保存"; //ダイアログのタイトルを指定する
if(sfDlg.ShowDialog() == DialogResult.OK) //ダイアログを表示する
{
//ストリームで書き込む(解説:ファイル入出力エラーが考えられ、usingを使用しています。)
using(StreamWriter sw = new StreamWriter(sfDlg.FileName, false, System.Text.Encoding.GetEncoding("shift_jis"))) //falseは「上書き指定」
{
sw.Write(files);
sw.Close();
}
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
sfDlg.Dispose();
}
//「終了」処理
private void OnExit_Click(object sender, EventArgs e)
{
Close();
}
//「ファイルを追加」処理(解説:個別ファイルの追加です。)
private void OnAdd_Click(object sender, EventArgs e)
{
OpenFileDialog ofDlg = new OpenFileDialog();
ofDlg.Filter = "すべてのファイル(*.*)|*.*"; //ファイルフィルターの指定
ofDlg.FilterIndex = 1; //ファイルフィルターインデックスの指定
ofDlg.RestoreDirectory = true; //ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
ofDlg.CheckFileExists = true; //存在しないファイルの名前が指定されたとき警告を表示する
ofDlg.CheckPathExists = true; //存在しないパスが指定されたとき警告を表示する
ofDlg.Multiselect = true; //複数ファイルの選択を行う(解説:追加、除外ではこうしました。)
ofDlg.InitialDirectory = @".\"; //デフォルトのフォルダを指定する
ofDlg.Title = "ファイルを開く"; //ダイアログのタイトルを指定する
if(ofDlg.ShowDialog() == DialogResult.OK) //ダイアログを表示する
{
foreach(string fn in ofDlg.FileNames) //複数選択ファイル名コレクションの表示
{
ListViewItem item = file_List.Items.Add(Path.GetFileName(fn)); //解説:ファイル名です。
item.SubItems.Add(Path.GetDirectoryName(fn)); //解説:ファイルパスです。
}
if(file_List.Items.Count > 0)
{
//ツールバーボタンを有効化する
ChangeToolBarStatus(true);
//ファイル数を更新する
ShowNumOfFiles();
}
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
ofDlg.Dispose();
}
//「ファイルを除外」処理
private void OnRemove_Click(object sender, EventArgs e)
{
if(file_List.SelectedItems.Count == 0)
{
MessageBox.Show("項目が選択されていません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
else
{
DialogResult dr = MessageBox.Show("選択項目" + file_List.FocusedItem.Text + "(等)を削除しますか?", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(dr == DialogResult.Yes)
{
foreach(ListViewItem item in file_List.SelectedItems)
{
//選択されたアイテムを削除する
item.Remove();
}
if(file_List.Items.Count == 0)
//ツールバーボタンを無効化する
ChangeToolBarStatus(false);
//ファイル数を更新する
ShowNumOfFiles();
}
}
}
//「削除」処理
private void OnDelete_Click(object sender, EventArgs e)
{
DialogResult dr = MessageBox.Show("リストの全ファイルを削除しますか?\r\n注意:削除するファイルのリストは予め「ファイルリストを保存」で作成してください。", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(dr == DialogResult.Yes)
{
foreach(ListViewItem item in file_List.Items)
{
//全ファイルの削除(解説:削除できないファイルが存在する可能性があるので...try)
try
{
File.Delete(item.SubItems[1].Text + "\\" + item.SubItems[0].Text);
item.Remove(); //処理完了ファイルはリストから削除する
}
catch
{
MessageBox.Show(item.SubItems[1].Text + "\\" + item.SubItems[0].Text + "\r\nの削除に失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue;
}
}
}
}
//「コピー」処理
private void OnCopy_Click(object sender, EventArgs e)
{
//「フォールダーを開く」処理
FolderBrowserDialog fbDlg = new FolderBrowserDialog();
fbDlg.Description = "コピー先のフォルダーを選択、または作成してください。"; //ダイアログの説明文
fbDlg.SelectedPath = ".\\"; //デフォルトのフォルダー
if(fbDlg.ShowDialog() == DialogResult.OK) //フォルダを選択するダイアログを表示する
{
foreach(ListViewItem item in file_List.Items)
{
//全ファイルのコピー(解説:コピーできないファイルが存在する可能性があるので...try)
try
{
//既に同名ファイルがあった場合はエラーとなる(File.Copy(FromFile, ToFile, false))
File.Copy(item.SubItems[1].Text + "\\" + item.SubItems[0].Text, fbDlg.SelectedPath + "\\" + item.SubItems[0].Text);
item.Remove(); //処理完了ファイルはリストから削除する
}
catch
{
MessageBox.Show(item.SubItems[1].Text + "\\" + item.SubItems[0].Text + "\r\nのコピーに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue;
}
}
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
fbDlg.Dispose();
}
//「移動」処理
private void OnMove_Click(object sender, EventArgs e)
{
//「フォールダーを開く」処理
FolderBrowserDialog fbDlg = new FolderBrowserDialog();
fbDlg.Description = "移動先のフォルダーを選択、または作成してください。"; //ダイアログの説明文
fbDlg.SelectedPath = ".\\"; //デフォルトのフォルダー
if(fbDlg.ShowDialog() == DialogResult.OK) //フォルダを選択するダイアログを表示する
{
foreach(ListViewItem item in file_List.Items)
{
//全ファイルの移動(解説:移動できないファイルが存在する可能性があるので...try)
try
{
File.Move(item.SubItems[1].Text + "\\" + item.SubItems[0].Text, fbDlg.SelectedPath + "\\" + item.SubItems[0].Text);
item.Remove(); //処理完了ファイルはリストから削除する
}
catch
{
MessageBox.Show(item.SubItems[1].Text + "\\" + item.SubItems[0].Text + "\r\nのコピーに失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue;
}
}
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
fbDlg.Dispose();
}
//「圧縮」処理(解説:Win11ではとっても簡単です。)
private void OnCompress_Click(object sender, EventArgs e)
{
//Zipファイル作成用の暫定フォールダーの作成
string temp = ".\\Temp";
Directory.CreateDirectory(temp);
//全ファイルのコピー
foreach(ListViewItem item in file_List.Items)
{
try
{
//既に同名ファイルがあった場合もエラーを出さない為に上書きする
File.Copy(item.SubItems[1].Text + "\\" + item.SubItems[0].Text, temp + "\\" + item.SubItems[0].Text, true);
item.Remove(); //処理完了ファイルはリストから削除する
}
catch
{
MessageBox.Show(item.SubItems[1].Text + "\\" + item.SubItems[0].Text + "\r\nの圧縮に失敗しました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue;
}
}
//「フォールダーを開く」処理
FolderBrowserDialog fbDlg = new FolderBrowserDialog();
fbDlg.Description = "圧縮先のフォルダーを選択、または作成してください。"; //ダイアログの説明文
fbDlg.SelectedPath = ".\\"; //デフォルトのフォルダー
if(fbDlg.ShowDialog() == DialogResult.OK) //フォルダを選択するダイアログを表示する
{ //Zipファイルの作成
/* 注意:ZipFileの使用には,
(1) "using System.IO.Compression;"と、
(2) System.IO.Compression.FileSystemへの参照(MSCompAssで指定する)
を追加する必要がある。*/
ZipFile.CreateFromDirectory(temp, fbDlg.SelectedPath + "\\CompressedFileList.zip");
}
else
{
MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
//オブジェクトを破棄する(解説:↓で述べる通り、C#ではダイアログは必ずDisposeする必要があります。)
fbDlg.Dispose();
//temp内全ファイルの削除
DirectoryInfo temp_dir = new DirectoryInfo(temp);
foreach(FileInfo file in temp_dir.GetFiles())
{
file.Delete();
}
//tempフォルダーの削除
temp_dir.Delete(true);
}
///////////////////////////
//コントロール関連メソッド
///////////////////////////
//file_Listのコラムがクリックされた時
private void OnLV_ColumnClick(object sender, ColumnClickEventArgs e)
{
//ListViewItemSorterを指定する
file_List.ListViewItemSorter = new ListViewItemComparer(e.Column);
//正順、逆順交互に並び替える(ListViewItemSorterを設定するとSortが自動的に呼び出される)
}
//file_Listのアイテムが変更された時
private void OnLV_SelectionChanged(Object sender, ListViewItemSelectionChangedEventArgs e)
{
if(file_List.SelectedItems.Count == 0) //選択状態のチェック
{
tssl[2].Text = "(選択ファイル名)";
tssl[2].ToolTipText = "(選択ファイル名)"; //ToolTip設定
}
else
{
tssl[2].Text = e.Item.Text;
tssl[2].ToolTipText = e.Item.Text; //ToolTip設定
}
}
//file_Listにドラッグされた時
private void LV_DragEnter(object sender, DragEventArgs e)
{
if(e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Copy;
else
e.Effect = DragDropEffects.None;
}
//file_ListViewにドロップされたとき
private void LV_DragDrop(object sender, DragEventArgs e)
{
//ドロップされたファイルパスを取得
string[] ddlist = (string[])e.Data.GetData(DataFormats.FileDrop, false);
//ドロップされたデータをリストビューに追加する
foreach(string fn in ddlist)
{
//ファイルが存在するか、フォールダーではないか、をチェックする
if(!File.Exists(fn))
{
MessageBox.Show("このファイルは存在しません。\r\n" + fn, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
continue;
}
ListViewItem item = file_List.Items.Add(Path.GetFileName(fn));
item.SubItems.Add(Path.GetDirectoryName(fn));
}
//ツールバーボタンを有効化する
ChangeToolBarStatus(true);
//ファイル数を更新する
ShowNumOfFiles();
}
///////////////////////
//FileList共通メソッド
///////////////////////
//ツールバーボタンの状態を有効、無効化する
private void ChangeToolBarStatus(bool flag)
{
this.toolStripButton[1].Enabled = flag; //解説:「ファイルリストの保存」
for(int i = 4; i < 9; i++)
this.toolStripButton[i].Enabled = flag; //解説:「ファイルの追加、除外、削除、コピー、移動、圧縮」
}
//ファイル数を更新する
private void ShowNumOfFiles()
{
tssl[1].Text = "ファイル数:" + file_List.Items.Count.ToString();
tssl[1].ToolTipText = "ファイル数:" + file_List.Items.Count.ToString(); //ToolTip設定
}
//ファイルリストデータを取得する(DLL版用-解説:CardboardBoxとcsFileList間でデータのやり取りをするので)
public string[] GetFileList()
{
//ファイルリストデータ引き渡し用
string[] flData = new string[file_List.Items.Count];
for(int i = 0; i < file_List.Items.Count; i++)
{
flData[i] = file_List.Items[i].SubItems[1].Text + "\\" + file_List.Items[i].SubItems[0].Text;
}
return flData;
}
/* 既にFormクラスで定義されているので、再定義エラー
「csFileList.FileList.Dispose()' は継承メンバー 'System.ComponentModel.Component.Dispose()' を隠します。
意図的に隠す場合はキーワード new を使用してください。」
が出るので、ダミー引数を入れ(オーバーロードさせ)てごまかしていた。*/
//FileListクラスインスタンスのリソース開放用Dispose()メソッド(Microsoft Docs)
public void Dispose(int i = 0)
{
//アンマネージドリソースの開放
Dispose(true);
//ガーベージコレクション(終了抑制)
GC.SuppressFinalize(this);
}
/* 解説:FileList.Dispose()について
前回のコードを見ていただければわかりますが、このcsFileList.csはエントリーポイントをコメントアウトしてダイナミックライブラリーにしてあります。(コメントアウトしているところを復活させるとスタンドアローンプログラムになりますが。)
従って、CardboardBoxプログラムに"using csFileList;"とし、csFileList,dllを参照してこのライブラリーが使えるようになります。
実際に使う場合は、"Show()"メソッドで呼び出すモードレスダイアログではメッセージボックス表示中にプログラムが進行してしまい塩梅が悪いので、"ShowDialog()"を使ってモーダルダイアログで呼び出す必要があります。
C#でモーダルダイアログを使う場合、↑で見てきた通り、必ずユーザーがリソースを開放する必要があります。(注)その為、本csFileListもユーザー定義でDispose()メソッドを規定通り追加することとなりました。既にFormクラスで定義されているのでメソッドの定義は不要です。(実際、メソッドを追加したことで、再定義エラー「csFileList.FileList.Dispose()' は継承メンバー 'System.ComponentModel.Component.Dispose()' を隠します。意図的に隠す場合はキーワード new を使用してください。」が出た為、ダミー引数を入れ(オーバーロードさせ)てごまかしていました。ゴメンなさい。
注: ShowDialog(from Microsoft Docs)
このメソッドを使用すると、アプリケーションにモーダルダイアログボックスを表示できます。
このメソッドが呼び出されると、ダイアログ ボックスが閉じられるまで次のコードは実行されません。
ダイアログボックスは、フォームのDialogResultプロパティに、DialogResultの一つを割り当てるか、
コードでDialogResultの列挙値の1つをButtonに設定することができます。
この値は、このメソッドによって返されます。この戻り値を使用して、ダイアログボックスで発生した
アクションを処理する方法を決定できます。たとえば、ダイアログボックスが閉じられ、このメソッドを
使用して値DialogResult.Cancelが返された場合、呼び出しShowDialogに続くコードが実行されないように
することができます。
フォームがモーダルダイアログボックスとして表示されている場合、[閉じる]ボタン(フォームの右上隅にある
Xボタン) をクリックすると、フォームが非表示になり、DialogResultプロパティがDialogResult.Cancelに設定
されます。非モーダルフォームとは異なり、ユーザーがダイアログボックスの閉じる(Close)フォームボタン
をクリックしたり、プロパティの値DialogResultを設定したりしても、メソッドは.NET Frameworkによって
呼び出されません。代わりに、フォームは非表示になり、ダイアログ ボックスの新しいインスタンスを作成
せずに再度表示できます。ダイアログ ボックスとして表示されるフォームは閉じるのではなく非表示になる
ため、フォームがアプリケーションで不要になった場合は、フォームのメソッドを呼び出す Dispose 必要が
あります。
このバージョンのShowDialogメソッドでは、フォームまたはコントロールを所有者として指定しません。
このバージョンが呼び出されると、現在アクティブなウィンドウがダイアログ ボックスの所有者になります。
特定の所有者を指定する場合は、このメソッドの他のバージョンを使用します。
//FileListクラスインスタンスのリソース開放用Dispose()メソッド(Microsoft Docs)→不要
public void Dispose(int i = 0)
{
//アンマネージドリソースの開放
Dispose(true);
//ガーベージコレクション(終了抑制)
GC.SuppressFinalize(this);
}
*/
}
}
///////////////////////////////////////////
//ListViewの項目の並び替えに使用するクラス
///////////////////////////////////////////
public class ListViewItemComparer : IComparer
{
private int m_column;
private static int m_order = 1; //毎回呼ばれるたびに正順、逆順を交代させるフラグ(解説:前に説明しました。)
//ListViewItemComparerクラスのコンストラクタ
public ListViewItemComparer(int col)
{
m_column = col;
m_order *= -1; //ListViewItemComparerが呼ばれる度に正順、逆順が変更される
}
//xがyより小さいときはマイナスの数、大きいときはプラスの数、同じときは0を返す
public int Compare(object x, object y)
{
//ListViewItemの取得
ListViewItem itemx = (ListViewItem) x;
ListViewItem itemy = (ListViewItem) y;
//xとyを文字列として比較する
return string.Compare(itemx.SubItems[m_column].Text, itemy.SubItems[m_column].Text) * m_order;
}
}
csFileListをMSComAssでコンパイルするには、ターゲットをlibrary(dll)にし、System.IO.Compression.FileSystem.dllを参照する必要があります。
【csFileList.opt】
[Compile Option]
Target=3
Resource=1
RscFile=C:\Users\ysama\Programing\C# Programing\Projects\FileList\DLL版\csFileList.resources
IconFile=
DbgOpt=0
WarnErr=5
Others=
RefFile=C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.IO.Compression.FileSystem\v4.0_4.0.0.0__b77a5c561934e089\System.IO.Compression.FileSystem.dll
これでcsFileList.dllが完成しましたので、次はメインフォーム(ウィンドウ)であるCardboardBoxに移りましょう。




