using KssSmaPlaLib.Commons; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace KssSmaPlaLib.IO.File { public static class PathUxer { public static string CreateFullPathEx( string folderPath, string fileName, string dtPrefix = "", string dtSuffix = "") { DateTime now = DateTime.Now; // フォルダ:未指定時はカレントフォルダ folderPath = string.IsNullOrEmpty(folderPath) ? "." : folderPath; // ファイル名:未指定時は"noname.txt"とする fileName = string.IsNullOrEmpty(fileName) ? "noname.txt" : fileName; if (fileName.IndexOf('.') == -1) { // 拡張子がないとき、付与する fileName += ".txt"; } // ファイルパス var path = Path.Combine( Path.GetFullPath(folderPath), (string.IsNullOrEmpty(dtPrefix) ? "" : now.ToString(dtPrefix)) + fileName.Split('.')[0] + (string.IsNullOrEmpty(dtSuffix) ? "" : now.ToString(dtSuffix)) + "." + fileName.Split('.')[1]); return path; } public static string CombineUnixPath(params string[] parts) { return string.Join("/", parts.Select(p => p.Trim('/'))); } /// /// ファイル名(パス不可)を受け取り、存在すればフルパスを返す。 /// 探索順:①このDLLのフォルダ → ②エントリEXEのフォルダ → ③AppDomain.BaseDirectory /// (C)昼コパソフトウェア㈱ /// /// パスではないファイル名のみ(例: "config.json")。 /// 見つかったファイルのフルパス。未発見時は null。 /// 発見した場合 true、未発見の場合 false。 public static bool TryResolveInAssemblyFolder(string fileName, out string fullPath) { fullPath = null; // --- ガード:パスを排除(「ファイル名のみ」の前提を厳守) --- if (string.IsNullOrWhiteSpace(fileName)) return false; // ディレクトリ成分が入っていたら拒否 if (!string.Equals(fileName, Path.GetFileName(fileName), StringComparison.Ordinal)) return false; // 予約文字の簡易チェック(Windows前提の一般的なNG文字) foreach (var ch in Path.GetInvalidFileNameChars()) { if (fileName.IndexOf(ch) >= 0) return false; } // --- ① このメソッドを含むライブラリ(DLL)のフォルダ --- var dllFolder = SafeGetDirectoryName(SafeGetAssemblyLocation(Assembly.GetExecutingAssembly())); if (TryCombineAndExists(dllFolder, fileName, out fullPath)) return true; // --- ② エントリアセンブリ(EXE)のフォルダ --- string exeFolder = null; var entry = Assembly.GetEntryAssembly(); if (entry != null) { exeFolder = SafeGetDirectoryName(SafeGetAssemblyLocation(entry)); } else { // サービスや特殊ホストで EntryAssembly が null の場合のフォールバック try { exeFolder = SafeGetDirectoryName(Process.GetCurrentProcess()?.MainModule?.FileName); } catch { // 取れないケースもあるので無理せず次へ exeFolder = null; } } if (TryCombineAndExists(exeFolder, fileName, out fullPath)) return true; // --- ③ AppDomain 基準(ClickOnce等のケースでも安定) --- var baseDir = AppDomain.CurrentDomain?.BaseDirectory; if (TryCombineAndExists(baseDir, fileName, out fullPath)) return true; // --- 未発見 --- fullPath = null; return false; } /// /// 指定フォルダに fileName を結合し、存在すれば out に設定して true。 /// private static bool TryCombineAndExists(string folder, string fileName, out string path) { path = null; if (string.IsNullOrWhiteSpace(folder)) return false; try { var candidate = Path.Combine(folder, fileName); if (System.IO.File.Exists(candidate)) { path = candidate; return true; } } catch { // パス結合や存在確認で例外が出てもスキップして未発見扱い } return false; } /// /// Assembly.Location を安全に取得(Reflection-only / 影響ケースを考慮)。 /// private static string SafeGetAssemblyLocation(Assembly asm) { try { return asm?.Location; } catch { return null; } } /// /// DirectoryName を安全に取得。 /// private static string SafeGetDirectoryName(string path) { try { return string.IsNullOrEmpty(path) ? null : Path.GetDirectoryName(path); } catch { return null; } } } }