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 static class Utils
\r
20 #region 汎用的なオブジェクト操作メソッド
\r
23 /// オブジェクトのフィールドをコピーしてクローン化する
\r
25 /// <param name="from">コピー元</param>
\r
26 /// <param name="target">コピー先。コピー元のクラスと同一か継承している型でなければならない</param>
\r
27 public static void FieldCopy<T,U>(T from, ref U target) where U : T
\r
29 foreach(FieldInfo member in typeof(T).GetFields()) {
\r
31 member.SetValue(target, member.GetValue(from));
\r
32 } catch (FieldAccessException) {} // アクセス不能は無視
\r
43 /// <param name="enus">元となる複数のイテレータ</param>
\r
44 /// <returns>結合されたイテレータ</returns>
\r
45 public static IEnumerable<T> MergeEnumerable<T>(params IEnumerable<T>[] enus)
\r
47 foreach (IEnumerable<T> enu in enus) {
\r
48 if (enu == null) continue;
\r
50 foreach (T elem in enu) {
\r
59 /// <param name="enus">元となる複数のイテレータ</param>
\r
60 /// <returns>結合されたイテレータ</returns>
\r
61 public static IEnumerable<T> MergeEnumerable<T>(params IEnumerator<T>[] enus)
\r
63 foreach (IEnumerator<T> enu in enus) {
\r
64 if (enu == null) continue;
\r
67 while (enu.MoveNext()) {
\r
68 yield return enu.Current;
\r
77 /// イテレータを結合して、Listとして返す
\r
79 /// <param name="enus">元となる複数のイテレータ</param>
\r
80 /// <returns>結合されたイテレータ</returns>
\r
81 public static List<T> MergeList<T>(params IEnumerable<T>[] enus)
\r
83 List<T> list = new List<T>();
\r
85 foreach (IEnumerable<T> enu in enus) {
\r
86 if (enu == null) continue;
\r
94 /// イテレータを配列に効率的に変換する
\r
96 /// <remarks>与えられる型が具体的にわかっているならば、それに特化した手続きをとる方が好ましい</remarks>
\r
97 /// <param name="enu">元となるイテレータ</param>
\r
98 /// <returns>変換された配列</returns>
\r
99 public static T[] IEnumerable2Array<T>(IEnumerable<T> enu) {
\r
100 T[] retval = enu as T[];
\r
102 if (retval == null) {
\r
103 List<T> list = enu as List<T>;
\r
104 if (list == null) {
\r
105 list = new List<T>(enu);
\r
107 retval = list.ToArray();
\r
114 /// リストに対して指定した2つの要素の位置を入れ替える
\r
116 /// <param name="list">操作対象のリスト</param>
\r
117 /// <param name="indexA">位置</param>
\r
118 /// <param name="indexB">位置</param>
\r
119 public static void ListSwap(System.Collections.IList list, int indexA, int indexB)
\r
121 if ((indexA < 0) || (list.Count <= indexA) || (indexB < 0) || (list.Count <= indexB)) {
\r
122 throw new IndexOutOfRangeException();
\r
123 } else if (indexA != indexB) {
\r
124 object temp = list[indexA];
\r
125 list[indexA] = list[indexB];
\r
126 list[indexB] = temp;
\r
132 #region ファイル情報関連ユーテイリティ関数
\r
135 /// パス変数に指定のフォルダーを追加する
\r
137 /// <param name="dir">追加するフォルダー</param>
\r
138 public static void AddDirectoryToPath(string dir)
\r
140 string path = Environment.GetEnvironmentVariable("PATH");
\r
142 if (path.IndexOf(dir) < 0) {
\r
143 path = dir + Path.PathSeparator + path;
\r
144 Environment.SetEnvironmentVariable("PATH", path);
\r
149 /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換
\r
151 /// <param name="bytes">バイト単位の容量</param>
\r
152 /// <returns>読みやすい形に直された容量文字列</returns>
\r
153 public static string FormatSize(double bytes)
\r
155 string[] units = new string[] {"B", "KB", "MB", "GB", "TB"};
\r
157 double size = bytes;
\r
159 for (i = 0; size >= 1024 && i < units.Length-1 ; i++) {
\r
163 return string.Format("{0:F2}{1}", size, units[i]);
\r
166 public static string FormatSize(long bytes)
\r
168 return FormatSize((double) bytes);
\r
172 /// URLからそのファイル名を生成する
\r
174 /// <param name="url">対象のurl</param>
\r
175 public static string Url2filename(Uri url)
\r
177 string filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url.ToString(), Encoding.UTF8));
\r
180 if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {
\r
181 // 不正な文字が含まれているならば、それ以降を削除
\r
182 filename = filename.Substring(0, pos);
\r
183 // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に
\r
184 if (filename.Length == 0) {
\r
185 filename = Path.GetFileName(Path.GetTempFileName());
\r
189 //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);
\r
193 /// 再帰的にファイルの属性を指定します。強制的にフォルダーの再帰削除の前に読み込み専用属性を消すのに使います。
\r
195 /// <param name="path">設定するフォルダー</param>
\r
196 /// <param name="attr">設定する属性値</param>
\r
197 public static void SetAttributeRecursive(string path, FileAttributes attr)
\r
200 File.SetAttributes(path, attr);
\r
203 foreach (string file in Directory.GetFiles(path)) {
\r
204 File.SetAttributes(file, attr);
\r
208 foreach (string file in Directory.GetDirectories(path)) {
\r
209 SetAttributeRecursive(file, attr);
\r
214 /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します
\r
216 /// <param name="path">設定するフォルダー</param>
\r
217 /// <param name="filesec">変更先権限</param>
\r
218 public static void SetAccessControlRecursive(string path, FileSecurity filesec)
\r
221 File.SetAccessControl(path, filesec);
\r
224 foreach (string file in Directory.GetFiles(path)) {
\r
225 File.SetAccessControl(file, filesec);
\r
229 foreach (string file in Directory.GetDirectories(path)) {
\r
230 SetAccessControlRecursive(file, filesec);
\r
235 /// ファイルまたはフォルダーの容量を算出して返す
\r
237 /// <param name="path">
\r
238 /// 対象ファイル及びフォルダーのパス
\r
243 public static ulong GetFileSize(string path)
\r
245 return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?
\r
246 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);
\r
250 /// フォルダーの容量を算出して返す
\r
252 /// <param name="dirInfo">
\r
258 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)
\r
261 foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {
\r
262 size += (ulong) child.Length;
\r
268 /// ワイルドカードを展開したファイルパス文字列を作り出す。
\r
269 /// 戻り値のそれぞれの文字列はフルパスとなる。
\r
271 /// <param name="baseDir">ベース(基点)のディレクトリ</param>
\r
272 /// <param name="pattern">ワイルドカードパターン</param>
\r
273 /// <returns>展開したファイルパス</returns>
\r
274 public static string[] ExtendWildcardFile(string baseDir, string pattern)
\r
276 if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {
\r
277 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す
\r
280 string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);
\r
281 List<string> extended = new List<string>();
\r
283 if (pathArray.Length == 1) {
\r
284 extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
285 extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
286 } else { // pathArray.Length > 1
\r
287 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);
\r
289 foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {
\r
291 extended.AddRange(ExtendWildcardFile(subDir, subPattern));
\r
294 } catch (UnauthorizedAccessException) {
\r
298 extended.RemoveAll(
\r
299 delegate(string path) {
\r
300 return ! File.Exists(path);
\r
304 return extended.ToArray();
\r
308 /// パスをパス区切り文字列ごとに分割した配列を返す
\r
310 /// <param name="path">パス文字列。相対・絶対は区別しない</param>
\r
311 /// <returns>フォルダー名ごとに分けられた文字列配列</returns>
\r
312 private static string[] splitPath(string path)
\r
314 return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});
\r
318 /// パスがフォルダーのとき、最後がパスセパレータで終了するようにする。
\r
320 /// <param name="path">パス</param>
\r
321 /// <returns>処理されたパス</returns>
\r
322 private static string fixLastPathCharForDirectory(string path)
\r
324 string fixedPath = path;
\r
325 if (Directory.Exists(path) && path[path.Length-1] != Path.DirectorySeparatorChar) {
\r
326 fixedPath += Path.DirectorySeparatorChar;
\r
332 /// 絶対パスを相対パスに変換して返します。
\r
334 /// <param name="baseDirectoryPath">相対パスの基準のフォルダー</param>
\r
335 /// <param name="absPath">絶対パス</param>
\r
336 /// <returns><code>absPath</code>の絶対パス表現</returns>
\r
337 public static string GetRelativePath(string baseDirectoryPath, string absPath)
\r
339 Uri baseuri = new Uri(fixLastPathCharForDirectory(baseDirectoryPath));
\r
340 Uri absuri = new Uri(fixLastPathCharForDirectory(absPath));
\r
342 string relative = baseuri.MakeRelativeUri(absuri).ToString();
\r
343 relative = System.Web.HttpUtility.UrlDecode(relative);
\r
344 relative = relative.Replace('/', Path.DirectorySeparatorChar);
\r
350 /// 相対パスに含まれている".."などを消去する
\r
352 /// <param name="aPath"></param>
\r
353 /// <returns></returns>
\r
354 public static string GetDotsRemovedPath(string aPath)
\r
356 string[] folders = splitPath(aPath);
\r
357 List<string> newFolders = new List<string>();
\r
359 foreach (string fol in folders) {
\r
362 } else if (fol == "..") {
\r
364 newFolders.RemoveAt(newFolders.Count-1);
\r
366 newFolders.Add(fol);
\r
370 return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());
\r
379 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
381 /// <param name="path">XMLファイルのパス</param>
\r
382 /// <param name="sr">シリアライザ</param>
\r
383 /// <returns>デシリアル化されたオブジェクト</returns>
\r
384 public static object GetDeserializedObject(string path, System.Xml.Serialization.XmlSerializer sr)
\r
386 object retVal = null;
\r
387 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
\r
388 retVal = sr.Deserialize(fs);
\r
394 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
396 /// <param name="path">XMLファイルのパス</param>
\r
397 /// <returns>デシリアル化されたオブジェクト</returns>
\r
398 public static T GetDeserializedObject<T>(string path)
\r
400 T retVal = default(T);
\r
401 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
402 retVal = (T) GetDeserializedObject(path, sr);
\r
407 /// オブジェクトをXMLでシリアル化してファイルに書き込む
\r
409 /// <param name="path">XMLファイルのパス</param>
\r
410 /// <param name="obj">シリアル化する対象のオブジェクト</param>
\r
411 public static void PutSerializeObject<T>(string path, T obj)
\r
413 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
\r
414 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
415 sr.Serialize(fs, obj);
\r
424 /// 現在のユーザがAdministrators権限を持っているか否かを返す。
\r
426 /// <remarks>UAC有効時には権限昇格後になってtrueを返すようになります</remarks>
\r
427 public static bool IsAdministrators()
\r
429 // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する
\r
430 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );
\r
431 IPrincipal prin = System.Threading.Thread.CurrentPrincipal;
\r
432 return prin.IsInRole(@"BUILTIN\Administrators");
\r
436 /// 現在のPCがUACが有効になっているか否かを返す。
\r
437 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。
\r
439 /// <returns>UACが有効ならばtrue</returns>
\r
440 public static bool IsUACEnabled()
\r
443 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {
\r
444 return ((int) key.GetValue("EnableLUA", 0)) == 1;
\r
446 } catch (Exception) {
\r
453 #region プロセス関連便利メソッド群
\r
456 /// プロセスに出力をリダイレクトした上で実行
\r
458 /// <param name="procInfo">プロセス起動情報</param>
\r
459 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
460 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
461 /// <returns>実行プロセス</returns>
\r
462 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
463 DataReceivedEventHandler outputReceived,
\r
464 DataReceivedEventHandler errorReceived)
\r
466 if (outputReceived != null) {
\r
467 procInfo.RedirectStandardOutput = true;
\r
469 if (errorReceived != null) {
\r
470 procInfo.RedirectStandardError = true;
\r
472 procInfo.UseShellExecute = false;
\r
474 Process hProcess = Process.Start(procInfo);
\r
475 if (outputReceived != null) {
\r
476 hProcess.OutputDataReceived += outputReceived;
\r
477 hProcess.BeginOutputReadLine();
\r
479 if (errorReceived != null) {
\r
480 hProcess.ErrorDataReceived += errorReceived;
\r
481 hProcess.BeginErrorReadLine();
\r
489 /// プロセスに出力をリダイレクトした上で実行
\r
491 /// <param name="procInfo">プロセス起動情報</param>
\r
492 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
493 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
494 /// <returns>実行プロセス</returns>
\r
495 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
496 EventHandler<AnyDataEventArgs<string>> outputReceived,
\r
497 EventHandler<AnyDataEventArgs<string>> errorReceived)
\r
499 return ProcessStartWithOutputCapture(procInfo,
\r
500 ConvertToDataReceivedEventHandler(outputReceived),
\r
501 ConvertToDataReceivedEventHandler(errorReceived));
\r
504 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)
\r
506 if (handler == null) return null;
\r
507 return delegate (object sender, DataReceivedEventArgs e) {
\r
508 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);
\r
509 handler.Invoke(sender, args);
\r
518 /// 任意データのイベント情報を表現するクラス
\r
520 public class AnyDataEventArgs<T> : EventArgs
\r
527 public AnyDataEventArgs(T data)
\r
536 get { return data; }
\r