misc.log

日常茶飯事とお仕事と

ファイルを掴んでいるプログラムを特定する方法

某所で書いたら意外に皆さん知らなかったようなので書いておきます。Windowsでファイルを削除したり名称変更しようとすると、別のプログラムが使っているので変更できない、といったエラーが出る事があります。こういう場合、後述の方法で「誰がファイルを掴んでいるのか」を調べられるかもしれません。
(あくまでローカル環境での話ですので、ネットワーク越しに掴まれているものや、インフラの運用で役立つ情報というわけではありません。ご了承ください)

ファイルやフォルダーの利用者をリソースモニターで検索する

リソースモニターという、タスクマネージャーの高機能版のようなツールがWindowsには標準搭載されています。これで、CPUタブにある「関連付けられたハンドル」というエリアの検索欄にファイル名やフォルダー名を入力すると、それを使っているプログラム(プロセス)を特定できることがあります。

リソースモニターの起動方法はいくつかありますが、一番手っ取り早いのはタスクマネージャーの「パフォーマンス」タブを開き、下部にあるリンクから起動する方法かと思います。

f:id:frontline:20211019010148p:plain
タスクマネージャーからリソースモニターを起動する

リソースモニターが起動したら、上部にある「CPU」タブを選択。その下段にある「関連付けられたハンドル」という部分の右端に入力欄があるので、そこにファイル名やフォルダー名を入力してください。「検索中」という文字が出てしばらく待つと、ファイルを利用しているプログラムの名称が表示されます。

f:id:frontline:20211019010604p:plain
Wordで開いているファイルを条件にした場合の例

WordやExcelの場合はファイル名で検索できますが、テキストファイルをメモ帳(Notepad.exe)などで開いた場合は、どうやらフォルダー名でないと出てこないようです。

下図の例は、1つのファイルを複数のプログラムで開いてみた状態の例です(実際にはあまり無いシチュエーションですが)。テキストエディターなどの場合、ファイルではなく検索条件はファイルがあるフォルダー名を利用します。

f:id:frontline:20211019013237p:plain
テキストファイルを複数プログラムで開き、フォルダーで検索した例

上図の例では、「サクラエディタ(sakura.exe)」「Visual Studio Code(Code.exe)」と、ファイル操作で使うWindowsエクスプローラー(explorer.exe)がフォルダーとファイルを表示しています。

たとえば、表向きExcelはクラッシュしてしまったのだけれど、裏では動いており、ファイルを掴んだままになっている……といったようなパターンなどで、こうした検索が使えると思います。
ファイルが掴まれたままになっている状況は、PCやサーバーを再起動すればおそらく解消します。しかし、開発環境やシステムの稼働環境ではそうも行かない状況も有ると思いますので、困ったときの手のひとつとして参考になれば幸いです。

プロセスが掴んでいるファイルを調べる

逆に、特定のプロセスが掴んだり参照しているファイルやフォルダーを調べる場合ですが、検索条件を入れずに、CPUタブの上部にあるプロセス一覧の左にあるチェックをONにしてください。そうすると、下部の関連付けられたハンドル欄に、プロセスが掴んでいる、Windows上の様々なものの一覧が表示されます。

補足:コマンドで同じようなことをやる

PowerShellとか使えば多分できるんだろうなぁ……と思ってたら、もっと簡単にずらっと結果を出せる方法について紹介してくださってるサイトがありました。

www.orangeitems.com

管理者権限でのコマンドプロンプトからの処理になります。これをササッと繰り出せると格好いいかも知れません。つかってみよう。

なお、公式ドキュメントはこちら。

docs.microsoft.com

補足:その他諸々

そのほかのツールや方法もはてブコメントでいろいろ提示いただきました。ありがとうございます。あまり深く踏み込む余裕がないので、名称とリンクだけ列挙しておきます。もしかしたら公式サイトじゃないものを貼っているかもしれませんがご容赦を(最後はご自分で検索してダウンロードしてください)。

NPOIで.NET Framework/C#からエクセルファイルの中身をテキストに吐き出す

f:id:frontline:20211018214921p:plain

大量のエクセルファイルの中身について精査したり文字列調査する必要がありそうだったので、以前使った.NET Framework用のExcelオブジェクト操作ライブラリー「NPOI」を使って、エクセルファイルの中身をテキストにする処理を書いてました。XLSX形式(Office 2007以降)のエクセルファイルは実体がXMLで、ClosedXML形式を扱えるライブラリーでも操作可能ですが、NPOIは古いタイプの、拡張子が.xlsのエクセルファイルも取り扱えるのが強みです。実際、お客さんの環境ではなんだかんだいってXLS形式がのこっていたりしますので……。

しかし、久々にプログラム組むと楽しいですね。

NPOIの導入

NPOIは、今手元にあるVisual Studio 2019の場合、[プロジェクト]-[NuGetパッケージの管理]から、検索条件でNPOIと入力すると出てきます。後に何も付かない「NPOI」がおそらく本体ですので、それを指定すれば取り込めます。

f:id:frontline:20211018215116p:plain
NuGetでのNPOI検索と選択

サンプル処理: ファイルの読み込みとstring化

メインの処理はこんな感じ。自分が自分のために使うものなので特にエラー処理とかまだ入れていません。エクセルファイル名をフルパス指定すると、その内容をテキストデータとして返します。各列の区切りは「|」で、行の区切りは改行、というテキストデータが返却されるので、これをテキストファイルとして出力。この処理を、指定したフォルダーにある全エクセルファイルに対して実施すれば、ファイル数がどんなにあってもテキスト化が一気にできます。

private string ReadFile(string fileName)
{
    // XLSX形式のオブジェクトを生成
    XSSFWorkbook workbook;
    using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        workbook = new XSSFWorkbook(file);
    }

    string sheetName = workbook.GetSheetName(0);
    ISheet sheet = workbook.GetSheet(sheetName);

    StringBuilder resultBuilder = new StringBuilder();
    ICell cellObject;
    // 行、列のループでセル情報を読み出してテキストを組み立てる
    for (int rowno = 0; rowno <= sheet.LastRowNum; rowno++)
    {
        if (sheet.GetRow(rowno) != null)
        {
            for (int colno = 0; colno <= Int32.Parse(ReadColsText.Text)-1; colno++)
            {
                if (sheet.GetRow(rowno).GetCell(colno) != null)
                {
                    cellObject = sheet.GetRow(rowno).GetCell(colno);
                    if (cellObject.CellType == CellType.String)
                    {
                        // セルが文字列の場合は文字として扱う
                        resultBuilder.Append(sheet.GetRow(rowno).GetCell(colno).StringCellValue + " | ");
                    }
                    else if (cellObject.CellType == CellType.Numeric)
                    {
                        // セルが数値の場合は文字変換して扱う
                        resultBuilder.Append(sheet.GetRow(rowno).GetCell(colno).NumericCellValue.ToString() + " | ");
                    }
                }
            }
            resultBuilder.Append("\r\n");
        }
    }
    return resultBuilder.ToString();
}

フォルダー内のファイル一覧取得

フォルダー内のファイル名を取得する処理とか、結構書くの面倒くさいなぁ……と思ってしまうのでサンプルを記載しておきます。

private List<string> GetFiles(string folderName)
{
    List<string> result = new List<string>();

    if (Directory.Exists(folderName))
    {
        result=Directory.GetFiles(folderName).Where(x => x.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase) ).ToList<string>();
    }

    return result;
}

上記のコードは、フォルダー名を指定するとstring型のListでファイル名一覧を返す処理です。拡張子xlsxのファイルだけが欲しいので、全ファイル一覧からxlsxに合致するものだけを抽出してListにしています。このListの内容それぞれについて、前述のテキスト化処理を掛け、戻ってきたstringデータをテキストファイルとして書き出せば、Excelファイルのテキスト化が完了です。

各処理の呼び出し部分

ついでなので、ファイル名一覧取得から、それぞれについてテキスト化の処理を読んで、結果をテキストファイルにする部分もメモしておきます。別途テキストボックスなどを用意して、そこに書いてあるパスを渡すようにしています。

private void ReadAndWriteAsText(List<string> fileNames)
{
    LogText.Text += "対象ファイル: " + fileNames.Count.ToString() + "\r\n";
    string outputFileName;
    foreach(string fileName in fileNames)
    {
        outputFileName = fileName + ".txt";
        StreamWriter writer = File.CreateText(outputFileName);
        writer.Write(ReadFile(fileName));
        writer.Close();
        LogText.Text += " ファイル: " + outputFileName + " 出力完了。\r\n";
    }
    LogText.Text += "全ファイル処理完了。\r\n";
}

オブジェクトの片付けとかエラー処理とか全然入れてないので、何か正式に使うものに流用される方はそのあたり、各自の責任で改造してくださいね。

既知の問題

なぜか、200ファイルほど読み込むと途中にExcelを開いているときに出来る作業用ファイル(ファイル名がチルダから始まるもの)が生成され、それを読み込んでしまってエラーになるという現象が。理由は不明(そもそもチルダ付ファイルは最初は無いのに、なぜかできる)。 読み込むファイルのサイズがゼロのものを弾く、などの処理を入れれば防げると思いますが、どうも指定したファイルは全て処理し終えた上でエラーが起きているので、とりあえず未解決のまま「自分用」として使うことにします。

DUNE(2021年版)観てきました

f:id:frontline:20211018094639p:plain

DUNE、2021年のドゥニ・ヴィルヌーヴ監督版を息子とみてきました。内容については取りあえず触れずにおいておきます。1984年のデイヴィッド・リンチ監督版はだいぶ駆け足だったのとアレンジが入っていましたが、今回は結構原作準拠で、なおかつツボを押さえて丁寧に描かれている印象でした。

原作はフランク・ハーバートによるSF小説。1965年に刊行され、日本ではハヤカワ書房から文庫本で「DUNE 砂の惑星」としてシリーズが発売されています。残念ながら完全に終わるまでに作者は亡くなってしまい、残りは息子さんが執筆されましたが日本語訳は出ていない状況です。しかしながら、日本語版既刊分でも十分世界観を味わうに足るボリュームがありますので、余裕があるかたは是非……(難しいですけど)。

f:id:frontline:20211018094934p:plain
シリーズ6「砂丘の大聖堂」3冊

1984年版の映画前は、挿絵や表紙イラストを石ノ森章太郎が担当していたのですが、その後の作品は加藤直之イラストで、柔らかい線をいかした人物やメカが独特な世界の描写を裏打ちしてくれます。お勧め!

詳しい話は避けますが、流石に超未来の銀河を描いたお話のため、独特の用語、組織、概念が出てきて映画だけではおそらく「??」となる場面があるでしょうから……いくつか代表的な用語等について書いておきます。

完全に映画監督の意図を味わいたい方は飛ばしてください。映画開始時点で登場人物の誰もが知っている言葉なので、ネタバレという内容ではありませんが、初見での疑問も味わいたい方にはスポイラーになるとおもうので。

代表的な用語等

  • 基本的な世界観 …… 銀河中に人類が散らばり、皇帝を中心にした恒星間貴族社会を形成している。
  • 戦争 …… 個人~建築物レベルで防御可能な「シールド」が開発され、高速で受ける攻撃は遮断されてしまうため、高速の射出兵器よりも剣や短剣での戦闘が主になっている(低速弾を打ち出す銃なども出てくる)。
  • 社会基盤 …… 惑星アラキスだけで採取される「メランジ」と呼ばれるスパイス(麻薬)が、今の石油のような扱いになっている。メランジを摂取することで恒星間跳躍が可能になった特殊な人種「ナビゲーター」が星間移動をつかさどり、物流や移動のかなめになっている。メランジの流通は「ギルド」が統括している。
  • ベネ・ゲセリット …… 社会の陰で暗躍する女性だけの組織。何千年にも及ぶ交配計画により遺伝子を自然操作し、自分たちの願いを達成する「救世主(クイサッツ・ハデラック)」という超人の誕生を目論んでいる。修道女的な身なりで、貴族や社会基盤にめり込んでいる。高度な体術などを会得し、特殊訓練による「声(ヴォイス)」で人を思いのままに操る能力などを持つ。主人公、ポールの母はベネ・ゲセリット。
  • メンタート …… 数値計算訓練を受けた人間コンピューター。皇族などの参謀として配置されている。主人公の属するアトレイデス家の「スフィル」はメンタート。敵対するハルコンネン家の「パイター」もメンタート。
  • スク医師 …… この社会で皇族に仕える医師団。暗示によって人を殺害することを抑制されている。主人公の家の「Dr.ユエ」もその一人。
  • サーダーカー …… 皇帝直属の戦闘殺戮集団。めちゃくちゃ強い。

とりあえずこのあたりを知っておけば、映像での解説も含めて理解が早く、メインのお話に集中出来ると思います。

Dune

Dune

Amazon