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> MergeList<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
107 T[] retval = enu as T[];
\r
109 if (retval == null) {
\r
110 List<T> list = enu as List<T>;
\r
111 if (list == null) {
\r
112 list = new List<T>(enu);
\r
114 retval = list.ToArray();
\r
121 /// リストに対して指定した2つの要素の位置を入れ替える
\r
123 /// <param name="list">操作対象のリスト</param>
\r
124 /// <param name="indexA">位置</param>
\r
125 /// <param name="indexB">位置</param>
\r
126 public static void ListSwap(System.Collections.IList list, int indexA, int indexB)
\r
128 if ((indexA < 0) || (list.Count <= indexA) || (indexB < 0) || (list.Count <= indexB)) {
\r
129 throw new IndexOutOfRangeException();
\r
130 } else if (indexA != indexB) {
\r
131 object temp = list[indexA];
\r
132 list[indexA] = list[indexB];
\r
133 list[indexB] = temp;
\r
139 #region ファイル情報関連ユーテイリティ関数
\r
142 /// パス変数に指定のフォルダーを追加する
\r
144 /// <param name="dir">追加するフォルダー</param>
\r
145 public static void AddDirectoryToPath(string dir)
\r
147 string path = Environment.GetEnvironmentVariable("PATH");
\r
149 if (path.IndexOf(dir) < 0) {
\r
150 path = dir + Path.PathSeparator + path;
\r
151 Environment.SetEnvironmentVariable("PATH", path);
\r
156 /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換
\r
158 /// <param name="bytes">バイト単位の容量</param>
\r
159 /// <returns>読みやすい形に直された容量文字列</returns>
\r
160 public static string FormatSize(double bytes)
\r
162 string[] units = new string[] {"B", "KB", "MB", "GB", "TB"};
\r
164 double size = bytes;
\r
166 for (i = 0; size >= 1024 && i < units.Length-1 ; i++) {
\r
170 return string.Format("{0:F2}{1}", size, units[i]);
\r
173 public static string FormatSize(long bytes)
\r
175 return FormatSize((double) bytes);
\r
179 /// URLからそのファイル名を生成する
\r
181 /// <param name="url">対象のurl</param>
\r
182 public static string Url2filename(Uri url)
\r
184 string filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url.ToString(), Encoding.UTF8));
\r
187 if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {
\r
188 // 不正な文字が含まれているならば、それ以降を削除
\r
189 filename = filename.Substring(0, pos);
\r
190 // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に
\r
191 if (filename.Length == 0) {
\r
192 filename = Path.GetFileName(Path.GetTempFileName());
\r
196 //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);
\r
200 /// 再帰的にファイルの属性を指定します。強制的にフォルダーの再帰削除の前に読み込み専用属性を消すのに使います。
\r
202 /// <param name="path">設定するフォルダー</param>
\r
203 /// <param name="attr">設定する属性値</param>
\r
204 public static void SetAttributeRecursive(string path, FileAttributes attr)
\r
207 File.SetAttributes(path, attr);
\r
210 foreach (string file in Directory.GetFiles(path)) {
\r
211 File.SetAttributes(file, attr);
\r
215 foreach (string file in Directory.GetDirectories(path)) {
\r
216 SetAttributeRecursive(file, attr);
\r
221 /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します
\r
223 /// <param name="path">設定するフォルダー</param>
\r
224 /// <param name="filesec">変更先権限</param>
\r
225 public static void SetAccessControlRecursive(string path, FileSecurity filesec)
\r
228 File.SetAccessControl(path, filesec);
\r
231 foreach (string file in Directory.GetFiles(path)) {
\r
232 File.SetAccessControl(file, filesec);
\r
236 foreach (string file in Directory.GetDirectories(path)) {
\r
237 SetAccessControlRecursive(file, filesec);
\r
242 /// ファイルまたはフォルダーの容量を算出して返す
\r
244 /// <param name="path">
\r
245 /// 対象ファイル及びフォルダーのパス
\r
250 public static ulong GetFileSize(string path)
\r
252 return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?
\r
253 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);
\r
257 /// フォルダーの容量を算出して返す
\r
259 /// <param name="dirInfo">
\r
265 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)
\r
268 foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {
\r
269 size += (ulong) child.Length;
\r
275 /// ワイルドカードを展開したファイルパス文字列を作り出す。
\r
276 /// 戻り値のそれぞれの文字列はフルパスとなる。
\r
278 /// <param name="baseDir">ベース(基点)のディレクトリ</param>
\r
279 /// <param name="pattern">ワイルドカードパターン</param>
\r
280 /// <returns>展開したファイルパス</returns>
\r
281 public static string[] ExtendWildcardFile(string baseDir, string pattern)
\r
283 if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {
\r
284 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す
\r
287 string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);
\r
288 List<string> extended = new List<string>();
\r
290 if (pathArray.Length == 1) {
\r
291 extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
292 extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
293 } else { // pathArray.Length > 1
\r
294 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);
\r
296 foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {
\r
298 extended.AddRange(ExtendWildcardFile(subDir, subPattern));
\r
301 } catch (UnauthorizedAccessException) {
\r
305 extended.RemoveAll(
\r
306 delegate(string path) {
\r
307 return ! File.Exists(path);
\r
311 return extended.ToArray();
\r
315 /// パスをパス区切り文字列ごとに分割した配列を返す
\r
317 /// <param name="path">パス文字列。相対・絶対は区別しない</param>
\r
318 /// <returns>フォルダー名ごとに分けられた文字列配列</returns>
\r
319 private static string[] splitPath(string path)
\r
321 return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});
\r
325 /// パスがフォルダーのとき、最後がパスセパレータで終了するようにする。
\r
327 /// <param name="path">パス</param>
\r
328 /// <returns>処理されたパス</returns>
\r
329 private static string fixLastPathCharForDirectory(string path)
\r
331 string fixedPath = path;
\r
332 if (Directory.Exists(path) && path[path.Length-1] != Path.DirectorySeparatorChar) {
\r
333 fixedPath += Path.DirectorySeparatorChar;
\r
339 /// 絶対パスを相対パスに変換して返します。
\r
341 /// <param name="baseDirectoryPath">相対パスの基準のフォルダー</param>
\r
342 /// <param name="absPath">絶対パス</param>
\r
343 /// <returns><code>absPath</code>の絶対パス表現</returns>
\r
344 public static string GetRelativePath(string baseDirectoryPath, string absPath)
\r
346 Uri baseuri = new Uri(fixLastPathCharForDirectory(baseDirectoryPath));
\r
347 Uri absuri = new Uri(fixLastPathCharForDirectory(absPath));
\r
349 string relative = baseuri.MakeRelativeUri(absuri).ToString();
\r
350 relative = System.Web.HttpUtility.UrlDecode(relative);
\r
351 relative = relative.Replace('/', Path.DirectorySeparatorChar);
\r
357 /// 相対パスに含まれている".."などを消去する
\r
359 /// <param name="aPath"></param>
\r
360 /// <returns></returns>
\r
361 public static string GetDotsRemovedPath(string aPath)
\r
363 string[] folders = splitPath(aPath);
\r
364 List<string> newFolders = new List<string>();
\r
366 foreach (string fol in folders) {
\r
369 } else if (fol == "..") {
\r
371 newFolders.RemoveAt(newFolders.Count-1);
\r
373 newFolders.Add(fol);
\r
377 return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());
\r
386 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
388 /// <param name="path">XMLファイルのパス</param>
\r
389 /// <param name="sr">シリアライザ</param>
\r
390 /// <returns>デシリアル化されたオブジェクト</returns>
\r
391 public static object GetDeserializedObject(string path, System.Xml.Serialization.XmlSerializer sr)
\r
393 object retVal = null;
\r
394 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
\r
395 retVal = sr.Deserialize(fs);
\r
401 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
403 /// <param name="path">XMLファイルのパス</param>
\r
404 /// <returns>デシリアル化されたオブジェクト</returns>
\r
405 public static T GetDeserializedObject<T>(string path)
\r
407 T retVal = default(T);
\r
408 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
409 retVal = (T) GetDeserializedObject(path, sr);
\r
414 /// オブジェクトをXMLでシリアル化してファイルに書き込む
\r
416 /// <param name="path">XMLファイルのパス</param>
\r
417 /// <param name="obj">シリアル化する対象のオブジェクト</param>
\r
418 public static void PutSerializeObject<T>(string path, T obj)
\r
420 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
\r
421 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
422 sr.Serialize(fs, obj);
\r
431 /// 現在のユーザがAdministrators権限を持っているか否かを返す。
\r
433 /// <remarks>UAC有効時には権限昇格後になってtrueを返すようになります</remarks>
\r
434 public static bool IsAdministrators()
\r
436 // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する
\r
437 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );
\r
438 IPrincipal prin = System.Threading.Thread.CurrentPrincipal;
\r
439 return prin.IsInRole(@"BUILTIN\Administrators");
\r
443 /// 現在のPCがUACが有効になっているか否かを返す。
\r
444 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。
\r
446 /// <returns>UACが有効ならばtrue</returns>
\r
447 public static bool IsUACEnabled()
\r
450 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {
\r
451 return ((int) key.GetValue("EnableLUA", 0)) == 1;
\r
453 } catch (Exception) {
\r
460 #region プロセス関連便利メソッド群
\r
463 /// プロセスに出力をリダイレクトした上で実行
\r
465 /// <param name="procInfo">プロセス起動情報</param>
\r
466 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
467 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
468 /// <returns>実行プロセス</returns>
\r
469 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
470 DataReceivedEventHandler outputReceived,
\r
471 DataReceivedEventHandler errorReceived)
\r
473 if (outputReceived != null) {
\r
474 procInfo.RedirectStandardOutput = true;
\r
476 if (errorReceived != null) {
\r
477 procInfo.RedirectStandardError = true;
\r
479 procInfo.UseShellExecute = false;
\r
481 Process hProcess = Process.Start(procInfo);
\r
482 if (outputReceived != null) {
\r
483 hProcess.OutputDataReceived += outputReceived;
\r
484 hProcess.BeginOutputReadLine();
\r
486 if (errorReceived != null) {
\r
487 hProcess.ErrorDataReceived += errorReceived;
\r
488 hProcess.BeginErrorReadLine();
\r
496 /// プロセスに出力をリダイレクトした上で実行
\r
498 /// <param name="procInfo">プロセス起動情報</param>
\r
499 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
500 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
501 /// <returns>実行プロセス</returns>
\r
502 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
503 EventHandler<AnyDataEventArgs<string>> outputReceived,
\r
504 EventHandler<AnyDataEventArgs<string>> errorReceived)
\r
506 return ProcessStartWithOutputCapture(procInfo,
\r
507 ConvertToDataReceivedEventHandler(outputReceived),
\r
508 ConvertToDataReceivedEventHandler(errorReceived));
\r
511 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)
\r
513 if (handler == null) return null;
\r
514 return delegate (object sender, DataReceivedEventArgs e) {
\r
515 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);
\r
516 handler.Invoke(sender, args);
\r
525 /// 任意データのイベント情報を表現するクラス
\r
527 public class AnyDataEventArgs<T> : EventArgs
\r
534 public AnyDataEventArgs(T data)
\r
543 get { return data; }
\r