【C#】非同期でファイルとフォルダのサイズを表示する

2018年2月15日C#,開発

おはようございます。

今回は検索なんかをやる予定でしたが、ちょっと寄り道して
選択されたファイル、フォルダの総数とデータ容量を非同期で画面に表示してみました。

プログラムは前回のものを流用します。

【C#】TreeView と ListView でエクスプローラーみたいな操作をする

スポンサーリンク

画面の修正

ラベルの追加

リストビューの下にラベルを設置します。

プログラムの修正

ファイルサイズ取得用の非同期メソッドを追加

            // 非同期処理のキャンセル用変数
            private CancellationTokenSource tokenSource = null;
    
            /// <summary>
            /// ファイル数とファイルサイズを設定します.
            /// </summary>
            private void SetFileCountAndSize()
            {
                // ファイル数、サイズの設定
                try
                {
                    // 非同期処理中だった場合はキャンセル
                    if (tokenSource != null)
                    {
                        tokenSource.Cancel();
                    }
    
                    using (tokenSource = new CancellationTokenSource())
                    {
                        SetFileCountAndSizeAsync(tokenSource.Token);
                    }
                }
                catch (ObjectDisposedException oe)
                {
                    Console.WriteLine("非同期処理が中止されました。");
                }
                catch (OperationCanceledException ex)
                {
                    MessageBox.Show("ファイル情報の取得に失敗しました。", "エラー");
                    return;
                }
                finally
                {
                    tokenSource = null;
                }
            }
    
            /// <summary>
            /// ファイル数とファイルサイズを設定します(非同期処理).
            /// </summary>
            private async void SetFileCountAndSizeAsync(CancellationToken token)
            {
                long fileSize = 0;
                int fileCount = 0;
    
                lbl_fileCountValue.Text = "";
                lbl_fileSizeValue.Text = "";
    
    
                foreach (ListViewItem item in listViewTo.Items)
                {
    
                    token.ThrowIfCancellationRequested();
    
                    // ディレクトリだった場合
                    FileInfo fi = new FileInfo(item.Name);
                    if (fi.Attributes == FileAttributes.Directory)
                    {
                        string[] pathList = Directory.GetDirectories(item.Name, "*", SearchOption.AllDirectories);
    
                        foreach (string path in pathList)
                        {
                            List<long> data = await GetFileCountAndSizeTask(path, fileSize, fileCount);
                            lbl_fileSizeValue.Text = getFileSize(data[0]);
                            lbl_fileCountValue.Text = data[1].ToString();
    
                            fileSize = data[0];
                            fileCount = (int)data[1];
                        }
                    }
                    else
                    {
                        fileSize += fi.Length;
                        fileCount++;
                        lbl_fileSizeValue.Text = getFileSize(fileSize);
                        lbl_fileCountValue.Text = fileCount.ToString();
                    }
                }
            }
    
            /// <summary>
            /// ファイル数とファイルサイズを取得します.
            /// </summary>
            /// <param name="filePath"></param>
            /// <param name="fileSize"></param>
            /// <param name="fileCount"></param>
            /// <returns></returns>
            private async Task<List<long>> GetFileCountAndSizeTask(String filePath, long fileSize, int fileCount)
            {
    
                List<long> result = new List<long>();
                await Task.Run(() =>
                {
                    DirectoryInfo dirInfo = new DirectoryInfo(filePath);
    
                    // フォルダ内の全ファイルの合計サイズを計算する
                    foreach (FileInfo fi in dirInfo.GetFiles())
                    {
                        fileSize += fi.Length;
                        fileCount++;
                    }
    
                    result.Add(fileSize);
                    result.Add(fileCount);
                });
    
                return result;
            }

既存イベント処理の修正

ファイルの追加、削除時にファイルサイズを設定する。

            /// <summary>
            /// 追加ボタンクリックイベント.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btn_add_Click(object sender, EventArgs e)
            {
                var selectedItems = listView1.SelectedItems;
                foreach (ListViewItem item in selectedItems)
                {
                    // 項目をコピーして名前を再設定
                    ListViewItem copy = (ListViewItem)item.Clone();
                    copy.Name = item.Name;
    
                    // 既にリストに含まれていないパスであれば追加
                    if (listViewTo.Items.Find(copy.Name, false).Length == 0)
                    {
                        listViewTo.Items.Add(copy);
                    }
                }
    
                // ファイル数、サイズの設定
                SetFileCountAndSize();
    
                // 列幅を自動調整
                listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
            }
    
            /// <summary>
            /// 削除ボタンクリックイベント.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btn_del_Click(object sender, EventArgs e)
            {
                var selectedItems = listViewTo.SelectedItems;
                foreach (ListViewItem item in selectedItems)
                {
                    listViewTo.Items.Remove(item);
                }
    
                // ファイル数、サイズの設定
                SetFileCountAndSize();
    
                // 列幅を自動調整
                listViewTo.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
    
            }

起動してみる

ファイル数、サイズの表示

スクリーンショットだと分からないですが、ファイル数、データ容量の大きいフォルダなんかを選択した場合に、非同期で表示が更新されます。

まとめ

最初は非同期でない方法で試したのですが、
大きいファイルなんかだと画面が固まってしまうので非同期にしました。

やっぱり画面まわりも色々やれることがあって楽しいですね。

次回はボタンに画像を表示してみたいと思います。

スポンサーリンク


関連するコンテンツ

2018年2月15日C#,開発C#,WindowsForms,サンプルプログラム

Posted by doradora