2019-08-20に投稿

【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);

            }

起動してみる

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

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

まとめ

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

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

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

Originally published at www.doraxdora.com
ツイッターでシェア
みんなに共有、忘れないようにメモ

doraxdora

IT関係の仕事をしています/1985年生まれの東京在住/便利なサービスやツール漁りや料理などが好き/2017年~ブログやってます/自分でサービスとか作ってリリースしたい/何かありましたらお気軽にDMどうぞ

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント