2 using System.Collections.Generic;
\r
5 using System.Globalization;
\r
6 using System.Security.Principal;
\r
7 using System.Security.AccessControl;
\r
8 using System.Reflection;
\r
9 using System.Diagnostics;
\r
10 using Microsoft.Win32;
\r
16 /// 雑多な便利メソッドを集めたクラス
\r
18 public sealed class Utils
\r
27 #region 汎用的なオブジェクト操作メソッド
\r
30 /// オブジェクトのフィールドをコピーしてクローン化する
\r
32 /// <param name="from">コピー元</param>
\r
33 /// <param name="target">コピー先。コピー元のクラスと同一か継承している型でなければならない</param>
\r
34 public static void FieldCopy<T,U>(T from, ref U target) where U : T
\r
36 foreach(FieldInfo member in typeof(T).GetFields()) {
\r
38 member.SetValue(target, member.GetValue(from));
\r
39 } catch (FieldAccessException) {} // アクセス不能は無視
\r
50 /// <param name="enus">元となる複数のイテレータ</param>
\r
51 /// <returns>結合されたイテレータ</returns>
\r
52 public static IEnumerable<T> MergeEnumerable<T>(params IEnumerable<T>[] enus)
\r
54 foreach (IEnumerable<T> enu in enus) {
\r
55 if (enu == null) continue;
\r
57 foreach (T elem in enu) {
\r
66 /// <param name="enus">元となる複数のイテレータ</param>
\r
67 /// <returns>結合されたイテレータ</returns>
\r
68 public static IEnumerable<T> MergeEnumerable<T>(params IEnumerator<T>[] enus)
\r
70 foreach (IEnumerator<T> enu in enus) {
\r
71 if (enu == null) continue;
\r
74 while (enu.MoveNext()) {
\r
75 yield return enu.Current;
\r
84 /// イテレータを結合して、Listとして返す
\r
86 /// <param name="enus">元となる複数のイテレータ</param>
\r
87 /// <returns>結合されたイテレータ</returns>
\r
88 public static List<T> MeargeList<T>(params IEnumerable<T>[] enus)
\r
90 List<T> list = new List<T>();
\r
92 foreach (IEnumerable<T> enu in enus) {
\r
93 if (enu == null) continue;
\r
101 /// イテレータを配列に効率的に変換する
\r
103 /// <remarks>与えられる型が具体的にわかっているならば、それに特化した手続きをとる方が好ましい</remarks>
\r
104 /// <param name="enu">元となるイテレータ</param>
\r
105 /// <returns>変換された配列</returns>
\r
106 public static T[] IEnumerable2Array<T>(IEnumerable<T> enu) {
\r
110 return ((enu is List<T>)? ((List<T>)enu):new List<T>(enu)).ToArray();
\r
115 /// リストに対して指定した2つの要素の位置を入れ替える
\r
117 /// <param name="list">操作対象のリスト</param>
\r
118 /// <param name="indexA">位置</param>
\r
119 /// <param name="indexB">位置</param>
\r
120 public static void ListSwap(System.Collections.IList list, int indexA, int indexB)
\r
122 if ((indexA < 0) || (list.Count <= indexA) || (indexB < 0) || (list.Count <= indexB)) {
\r
123 throw new IndexOutOfRangeException();
\r
124 } else if (indexA != indexB) {
\r
125 object temp = list[indexA];
\r
126 list[indexA] = list[indexB];
\r
127 list[indexB] = temp;
\r
133 #region ファイル情報関連ユーテイリティ関数
\r
136 /// パス変数に指定のフォルダを追加する
\r
138 /// <param name="dir">追加するフォルダ</param>
\r
139 public static void AddDirectoryToPath(string dir)
\r
141 string path = Environment.GetEnvironmentVariable("PATH");
\r
143 if (path.IndexOf(dir) < 0) {
\r
144 path = dir + Path.PathSeparator + path;
\r
145 Environment.SetEnvironmentVariable("PATH", path);
\r
150 /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換
\r
152 /// <param name="bytes">バイト単位の容量</param>
\r
153 /// <returns>読みやすい形に直された容量文字列</returns>
\r
154 public static string FormatSize(double bytes)
\r
156 string[] units = new string[] {"B", "KB", "MB", "GB", "TB"};
\r
158 double size = bytes;
\r
160 for (i = 0; size >= 1024 && i < units.Length-1 ; i++) {
\r
164 return string.Format("{0:F2}{1}", size, units[i]);
\r
167 public static string FormatSize(long bytes)
\r
169 return FormatSize((double) bytes);
\r
173 /// URLからそのファイル名を生成する
\r
175 /// <param name="url">対象のurl</param>
\r
176 public static string Url2filename(string url)
\r
178 string filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url, Encoding.UTF8));
\r
181 if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {
\r
182 // 不正な文字が含まれているならば、それ以降を削除
\r
183 filename = filename.Substring(0, pos);
\r
184 // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に
\r
185 if (filename.Length == 0) {
\r
186 filename = Path.GetFileName(Path.GetTempFileName());
\r
190 //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);
\r
194 /// 再帰的にファイルの属性を指定します。強制的にフォルダの再帰削除の前に読み込み専用属性を消すのに使います。
\r
196 /// <param name="path">設定するフォルダ</param>
\r
197 /// <param name="attr">設定する属性値</param>
\r
198 public static void SetAttributeRecursive(string path, FileAttributes attr)
\r
201 File.SetAttributes(path, attr);
\r
204 foreach (string file in Directory.GetFiles(path)) {
\r
205 File.SetAttributes(file, attr);
\r
209 foreach (string file in Directory.GetDirectories(path)) {
\r
210 SetAttributeRecursive(file, attr);
\r
215 /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します
\r
217 /// <param name="path">設定するフォルダ</param>
\r
218 /// <param name="filesec">変更先権限</param>
\r
219 public static void SetAccessControlRecursive(string path, FileSecurity filesec)
\r
222 File.SetAccessControl(path, filesec);
\r
225 foreach (string file in Directory.GetFiles(path)) {
\r
226 File.SetAccessControl(file, filesec);
\r
230 foreach (string file in Directory.GetDirectories(path)) {
\r
231 SetAccessControlRecursive(file, filesec);
\r
236 /// ファイルまたはフォルダの容量を算出して返す
\r
238 /// <param name="path">
\r
239 /// 対象ファイル及びフォルダのパス
\r
244 public static ulong GetFileSize(string path)
\r
246 return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?
\r
247 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);
\r
253 /// <param name="dirInfo">
\r
259 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)
\r
262 foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {
\r
263 size += (ulong) child.Length;
\r
269 /// ワイルドカードを展開したファイルパス文字列を作り出す。
\r
270 /// 戻り値のそれぞれの文字列はフルパスとなる。
\r
272 /// <param name="baseDir">ベース(基点)のディレクトリ</param>
\r
273 /// <param name="pattern">ワイルドカードパターン</param>
\r
274 /// <returns>展開したファイルパス</returns>
\r
275 public static string[] ExtendWildcardFile(string baseDir, string pattern)
\r
277 if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {
\r
278 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す
\r
281 string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);
\r
282 List<string> extended = new List<string>();
\r
284 if (pathArray.Length == 1) {
\r
285 extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
286 extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
287 } else { // pathArray.Length > 1
\r
288 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);
\r
290 foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {
\r
292 extended.AddRange(ExtendWildcardFile(subDir, subPattern));
\r
295 } catch (UnauthorizedAccessException) {
\r
299 extended.RemoveAll(
\r
300 delegate(string path) {
\r
301 return ! File.Exists(path);
\r
305 return extended.ToArray();
\r
309 /// パスをパス区切り文字列ごとに分割した配列を返す
\r
311 /// <param name="path">パス文字列。相対・絶対は区別しない</param>
\r
312 /// <returns>フォルダ名ごとに分けられた文字列配列</returns>
\r
313 private static string[] splitPath(string path)
\r
315 return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});
\r
319 /// パスがフォルダのとき、最後がパスセパレータで終了するようにする。
\r
321 /// <param name="path">パス</param>
\r
322 /// <returns>処理されたパス</returns>
\r
323 private static string fixLastPathCharForDirectory(string path)
\r
325 string fixedPath = path;
\r
326 if (Directory.Exists(path) && path[path.Length-1] != Path.DirectorySeparatorChar) {
\r
327 fixedPath += Path.DirectorySeparatorChar;
\r
333 /// 絶対パスを相対パスに変換して返します。
\r
335 /// <param name="baseDirectoryPath">相対パスの基準のフォルダ</param>
\r
336 /// <param name="absPath">絶対パス</param>
\r
337 /// <returns><code>absPath</code>の絶対パス表現</returns>
\r
338 public static string GetRelativePath(string baseDirectoryPath, string absPath)
\r
340 Uri baseuri = new Uri(fixLastPathCharForDirectory(baseDirectoryPath));
\r
341 Uri absuri = new Uri(fixLastPathCharForDirectory(absPath));
\r
343 string relative = baseuri.MakeRelativeUri(absuri).ToString();
\r
344 relative = System.Web.HttpUtility.UrlDecode(relative);
\r
345 relative = relative.Replace('/', Path.DirectorySeparatorChar);
\r
351 /// 相対パスに含まれている".."などを消去する
\r
353 /// <param name="aPath"></param>
\r
354 /// <returns></returns>
\r
355 public static string GetDotsRemovedPath(string aPath)
\r
357 string[] folders = splitPath(aPath);
\r
358 List<string> newFolders = new List<string>();
\r
360 foreach (string fol in folders) {
\r
363 } else if (fol == "..") {
\r
365 newFolders.RemoveAt(newFolders.Count-1);
\r
367 newFolders.Add(fol);
\r
371 return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());
\r
379 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
381 /// <param name="path">XMLファイルのパス</param>
\r
382 /// <returns>デシリアル化されたオブジェクト</returns>
\r
383 public static T GetDeserializedObject<T>(string path)
\r
385 T retVal = default(T);
\r
386 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
\r
387 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
388 retVal = (T) sr.Deserialize(fs);
\r
394 /// オブジェクトをXMLでシリアル化してファイルに書き込む
\r
396 /// <param name="path">XMLファイルのパス</param>
\r
397 /// <param name="obj">シリアル化する対象のオブジェクト</param>
\r
398 public static void PutSerializeObject<T>(string path, T obj)
\r
400 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
\r
401 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
402 sr.Serialize(fs, obj);
\r
411 /// 現在のユーザがAdministrators権限を持っているか否かを返す。
\r
413 /// <remarks>UAC有効時には権限昇格後になってtrueを返すようになります</remarks>
\r
414 public static bool IsAdministrators()
\r
416 // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する
\r
417 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );
\r
418 IPrincipal prin = System.Threading.Thread.CurrentPrincipal;
\r
419 return prin.IsInRole(@"BUILTIN\Administrators");
\r
423 /// 現在のPCがUACが有効になっているか否かを返す。
\r
424 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。
\r
426 /// <returns>UACが有効ならばtrue</returns>
\r
427 public static bool IsUACEnabled()
\r
430 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {
\r
431 return ((int) key.GetValue("EnableLUA", 0)) == 1;
\r
433 } catch (Exception) {
\r
440 #region プロセス関連便利メソッド群
\r
443 /// プロセスに出力をリダイレクトした上で実行
\r
445 /// <param name="procInfo">プロセス起動情報</param>
\r
446 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
447 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
448 /// <returns>実行プロセス</returns>
\r
449 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
450 DataReceivedEventHandler outputReceived,
\r
451 DataReceivedEventHandler errorReceived)
\r
453 if (outputReceived != null) {
\r
454 procInfo.RedirectStandardOutput = true;
\r
456 if (errorReceived != null) {
\r
457 procInfo.RedirectStandardError = true;
\r
459 procInfo.UseShellExecute = false;
\r
461 Process hProcess = Process.Start(procInfo);
\r
462 if (outputReceived != null) {
\r
463 hProcess.OutputDataReceived += outputReceived;
\r
464 hProcess.BeginOutputReadLine();
\r
466 if (errorReceived != null) {
\r
467 hProcess.ErrorDataReceived += errorReceived;
\r
468 hProcess.BeginErrorReadLine();
\r
476 /// プロセスに出力をリダイレクトした上で実行
\r
478 /// <param name="procInfo">プロセス起動情報</param>
\r
479 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
480 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
481 /// <returns>実行プロセス</returns>
\r
482 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
483 EventHandler<AnyDataEventArgs<string>> outputReceived,
\r
484 EventHandler<AnyDataEventArgs<string>> errorReceived)
\r
486 return ProcessStartWithOutputCapture(procInfo,
\r
487 ConvertToDataReceivedEventHandler(outputReceived),
\r
488 ConvertToDataReceivedEventHandler(errorReceived));
\r
491 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)
\r
493 if (handler == null) return null;
\r
494 return delegate (object sender, DataReceivedEventArgs e) {
\r
495 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);
\r
496 handler.Invoke(sender, args);
\r
505 /// 任意データのイベント情報を表現するクラス
\r
507 public class AnyDataEventArgs<T> : EventArgs
\r
514 public AnyDataEventArgs(T data)
\r
523 get { return data; }
\r