【Windowsアプリ】検索アプリ【C#】

目次

経緯

事実を確認してもらうため、議事録が入ってるフォルダの中の文章を証拠として、見せようとしたときに、

議事録フォルダのファイルを一つ一つ開いて、文章を探すのが手間だったので、

「”検索アプリ”のようなものがあればな~」と思い、C#で作ってみました。

レイアウト

まず、アプリのレイアウトを書きます。

ツール名Text名(Name)
label調べたいフォルダ:label1
label保存先:label2
label検索文字:label3
TextBoxtextBox_search_folder
TextBoxtextBox_save
TextBoxtextBox_search_word
Button選択button_search_folder_choose
Button選択button_save_choose
Button実行button_run

という構成です。配置は(Name)で表すと

label1,textBox_search_folder,button_search_folder_choose

label2,textBox_save,button_save_choose

label3,textBox_search_word

button_run

という並びとなります。

コード

以下がコードです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.IO;
using System.IO.Packaging;


namespace foldersearchApp
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // ドラッグ&ドロップのイベントハンドラを設定
            textBox_search_folder.AllowDrop = true;
            textBox_search_folder.DragEnter += new DragEventHandler(textBox_search_folder_DragEnter);
            textBox_search_folder.DragDrop += new DragEventHandler(textBox_search_folder_DragDrop);
        }


        private void button_search_folder_choose_Click(object sender, EventArgs e)
        {
            using (var folderBrowserDialog = new FolderBrowserDialog())
            {
                // ダイアログの説明文を設定
                folderBrowserDialog.Description = "検索するフォルダを選択してください。";

                // ダイアログを表示
                DialogResult result = folderBrowserDialog.ShowDialog();

                // ユーザーが「OK」を選択した場合、選択されたパスをテキストボックスに設定
                if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(folderBrowserDialog.SelectedPath))
                {
                    textBox_search_folder.Text = folderBrowserDialog.SelectedPath;
                }
            }
        }

        private void textBox_search_folder_DragEnter(object sender, DragEventArgs e)
        {
            // ドラッグされているデータがファイルのパスであるかどうかを確認
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy; // カーソルにコピーのアイコンを表示
            }
            else
            {
                e.Effect = DragDropEffects.None; // ドラッグ操作を受け入れない
            }
        }

        private void textBox_search_folder_DragDrop(object sender, DragEventArgs e)
        {
            // ドロップされたすべてのファイルのパスを取得
            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

            // ここでは単純化のため、最初のファイル/フォルダのパスを使用
            if (files != null && files.Length > 0)
            {
                // フォルダパスをテキストボックスに設定
                textBox_search_folder.Text = files[0];
            }
        }

        private void button_save_choose_Click(object sender, EventArgs e)
        {
            using (var folderBrowserDialog = new FolderBrowserDialog())
            {
                folderBrowserDialog.Description = "保存先のフォルダを選択してください。";
                // 新しいスタイルのダイアログを使用する設定(.NET 5.0以降で有効)
                // folderBrowserDialog.UseDescriptionForTitle = true; // 必要に応じてコメントアウト

                DialogResult result = folderBrowserDialog.ShowDialog();

                if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(folderBrowserDialog.SelectedPath))
                {
                    // 選択されたフォルダのパスをテキストボックスに設定
                    textBox_save.Text = folderBrowserDialog.SelectedPath;
                }
            }
        }

        private void button_run_Click(object sender, EventArgs e)
        {
            string sourceFolderPath = textBox_search_folder.Text;
            string destinationFolderPath = Path.Combine(textBox_save.Text, "FilteredFiles");
            string searchWord = textBox_search_word.Text;

            if (!Directory.Exists(destinationFolderPath))
            {
                Directory.CreateDirectory(destinationFolderPath);
            }

            var files = Directory.EnumerateFiles(sourceFolderPath, "*.*", SearchOption.AllDirectories)
                .Where(file => file.ToLower().EndsWith(".xlsx") || file.ToLower().EndsWith(".xlsm") // Excelマクロ含む形式を追加
                || file.ToLower().EndsWith(".docx") || file.ToLower().EndsWith(".docm") // Wordマクロ含む形式を追加
                || file.ToLower().EndsWith(".pptx") || file.ToLower().EndsWith(".pptm")); // PowerPointマクロ含む形式を追加

            foreach (var file in files)
            {
                // マクロを含むファイルの検出を追加
                if (FileContainsMacro(file) || CheckFileContainsText(file, searchWord))
                {
                    string destinationFilePath = Path.Combine(destinationFolderPath, Path.GetFileName(file));
                    File.Copy(file, destinationFilePath, true);
                }
            }

            MessageBox.Show("処理が完了しました。", "情報", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }


        private bool CheckFileContainsText(string filePath, string text)
        {
            string extension = Path.GetExtension(filePath).ToLower();
            switch (extension)
            {
                case ".xlsx":
                    return CheckExcelFileContainsText(filePath, text);
                case ".docx":
                    return CheckWordFileContainsText(filePath, text);
                case ".pptx":
                    return CheckPowerPointFileContainsText(filePath, text);
                default:
                    return false;
            }
        }

        private bool CheckExcelFileContainsText(string filePath, string text)
        {
            try
            {
                using (SpreadsheetDocument document = SpreadsheetDocument.Open(filePath, false))
                {
                    var strings = document.WorkbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().Select(item => item.InnerText);
                    return strings.Any(s => s.Contains(text));
                }
            }
            catch
            {
                return false;
            }
        }

        private bool CheckWordFileContainsText(string filePath, string text)
        {
            try
            {
                using (WordprocessingDocument document = WordprocessingDocument.Open(filePath, false))
                {
                    var texts = document.MainDocumentPart.Document.Body.Descendants<Text>().Select(t => t.Text);
                    return texts.Any(t => t.Contains(text));
                }
            }
            catch
            {
                return false;
            }
        }

        private bool CheckPowerPointFileContainsText(string filePath, string text)
        {
            try
            {
                using (PresentationDocument document = PresentationDocument.Open(filePath, false))
                {
                    var slides = document.PresentationPart.SlideParts;
                    foreach (var slide in slides)
                    {
                        var texts = slide.Slide.Descendants<DocumentFormat.OpenXml.Drawing.Text>().Select(t => t.Text);
                        if (texts.Any(t => t.Contains(text))) return true;
                    }
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        private bool FileContainsMacro(string filePath)
        {
            string extension = Path.GetExtension(filePath).ToLower();
            switch (extension)
            {
                case ".docm":
                case ".dotm":
                    return true; // Word マクロ含む形式
                case ".xlsm":
                case ".xltm":
                case ".xlam":
                    return true; // Excel マクロ含む形式
                case ".pptm":
                case ".potm":
                case ".ppam":
                case ".ppsm":
                case ".sldm":
                    return true; // PowerPoint マクロ含む形式
                default:
                    if (extension == ".docx" || extension == ".xlsx" || extension == ".pptx")
                    {
                        try
                        {
                            // OpenXML 形式のドキュメントでマクロを直接検出
                            using (Package package = Package.Open(filePath, FileMode.Open, FileAccess.Read))
                            {
                                string macroContentType = "application/vnd.ms-office.vbaProject";
                                return package.GetParts().Any(part => part.ContentType.Equals(macroContentType, StringComparison.OrdinalIgnoreCase));
                            }
                        }
                        catch
                        {
                            // ファイルアクセス例外などのエラー処理
                            return false;
                        }
                    }
                    return false; // その他の形式ではマクロを含まないと判断
            }
        }
    }
}

使い方は、

まず、textBox_search_folderにドラックドロップか「選択」ボタンを押して、検索したいフォルダを選択します。

次にtextBox_saveに検索に引っかかったファイルのフォルダを保存したい場所を「選択」ボタンを押して、設定してください。

次にtextBox_search_wordに検索したい文字を入れます。

最後に「実行」を押すと、textBox_search_wordで指定した文字が入っているファイル(Excel、word、PowerPoint)がフォルダが指定された先「FilterdFiles」という名前で保存されてます。

こんな感じです。

何かの参考になれば、幸いです。

ここまで読んでいただきありがとうございました。

スクールの紹介

最後に宣伝をさせてください。

技術で未来を切り拓く―あなたの夢を現実にするプログラミングスクール

Webデザインやプログラミングで成功を目指している方々にとって、このオンラインスクールは夢を叶えるための最適な場所です。皆さんのキャリアを次の段階へと引き上げるためにデザインされたこのスクールは、一人ひとりの成功を心から願い、それを実現するための全てを提供しています。ここでは、このスクールの魅力について詳しくご紹介します。

◆圧倒的な費用対効果
このオンラインプログラミングスクールは、Web系教育において最高の費用対効果を提供しています。多くの高額スクールが存在する中で、ここではリーズナブルな価格で、質の高い教材、無限のサポート、そして実際に市場で求められるスキルの習得機会を提供しています。

◆現役フリーランスの講師陣
講師たちは全員、現役のフリーランスプロフェッショナルです。市場で活躍している講師から直接、最新のトレンドや実践的なスキルを学べるのは、このスクールの大きな特徴です。

◆柔軟な学習コース
固定のコースがなく、学習者の興味やニーズに応じて自由に学習できます。進路変更も自由で、最低契約期間は1ヶ月という柔軟性を持っています。自分のペースで、自分に合った学習が可能です。

◆無制限の添削とサポート
理解できるまで、そして満足するまで、無制限に添削と質問への回答を提供しています。進路相談や技術面以外の相談にも対応しており、全面的にサポートします。

◆社長から学べる貴重な機会
デザイナー、プログラマー、ディレクター、マーケターとして豊富な経験を持つ社長から直接学べるのも、このスクールの特別な点です。他のスクールでは得られない、貴重な機会です。

◆実績作りへの徹底的なサポート
就職、転職、フリーランスとして成功するためには、高品質な実績が必要です。生徒の作品レベルを最大限に高め、市場で求められる実績を作り上げることに力を入れています。案件を取得できない生徒には、直接案件を提供することもあります。

◆メッセージからの約束
高額な授業料を支払わせて結果を出せないスクールとは違い、物理的なサポートは提供できないかもしれませんが、継続的な努力を通じて最高の結果を出せるようにサポートします。一緒に不正なスクールを撲滅し、あなたの夢を実現しましょう。

このプログラミングスクールは、Webデザインやプログラミングでの成功を目指す方々に必要な全てを備えています。今こそ、このコミュニティに参加し、あなたのキャリアを加速させる時です。

詳しくはこちら↓

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次