経緯
事実を確認してもらうため、議事録が入ってるフォルダの中の文章を証拠として、見せようとしたときに、
議事録フォルダのファイルを一つ一つ開いて、文章を探すのが手間だったので、
「”検索アプリ”のようなものがあればな~」と思い、C#で作ってみました。
レイアウト
まず、アプリのレイアウトを書きます。
| ツール名 | Text名 | (Name) |
| label | 調べたいフォルダ: | label1 |
| label | 保存先: | label2 |
| label | 検索文字: | label3 |
| TextBox | textBox_search_folder | |
| TextBox | textBox_save | |
| TextBox | textBox_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」という名前で保存されてます。
こんな感じです。
何かの参考になれば、幸いです。
ここまで読んでいただきありがとうございました。
技術書の購入コストを抑えてスキルアップするなら

ここまで読んでいただきありがとうございます。最後に宣伝をさせてください。
プログラミングの技術書や参考書は、1冊3,000円〜5,000円するものも多く、出費がかさみがちです。Kindle Unlimitedであれば、月額980円で500万冊以上の書籍が読み放題となります。
気になる言語の入門書から、アルゴリズム、基本設計の専門書まで、手元のスマホやPCですぐに参照可能です。現在は「30日間の無料体験」や、対象者限定の「3か月499円プラン」なども実施されています。まずはご自身のアカウントでどのようなオファーが表示されるか確認してみてください。
