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.AbsolutePath, Encoding.UTF8));
\r
179 if (string.IsNullOrEmpty(filename)) {
\r
180 filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url.ToString(), Encoding.UTF8));
\r
184 if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {
\r
185 // 不正な文字が含まれているならば、それ以降を削除
\r
186 filename = filename.Substring(0, pos);
\r
189 // そうしてしまったら文字の内容がまったくなくなってしまったら、現在時刻から取得
\r
190 if (filename.Length == 0) {
\r
191 filename = string.Format("tmp_{0}", DateTime.Now.Ticks);
\r
195 //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);
\r
199 /// 再帰的にファイルの属性を指定します。強制的にフォルダーの再帰削除の前に読み込み専用属性を消すのに使います。
\r
201 /// <param name="path">設定するフォルダー</param>
\r
202 /// <param name="attr">設定する属性値</param>
\r
203 public static void SetAttributeRecursive(string path, FileAttributes attr)
\r
206 File.SetAttributes(path, attr);
\r
209 foreach (string file in Directory.GetFiles(path)) {
\r
210 File.SetAttributes(file, attr);
\r
214 foreach (string file in Directory.GetDirectories(path)) {
\r
215 SetAttributeRecursive(file, attr);
\r
220 /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します
\r
222 /// <param name="path">設定するフォルダー</param>
\r
223 /// <param name="filesec">変更先権限</param>
\r
224 public static void SetAccessControlRecursive(string path, FileSecurity filesec)
\r
227 File.SetAccessControl(path, filesec);
\r
230 foreach (string file in Directory.GetFiles(path)) {
\r
231 File.SetAccessControl(file, filesec);
\r
235 foreach (string file in Directory.GetDirectories(path)) {
\r
236 SetAccessControlRecursive(file, filesec);
\r
241 /// ファイルまたはフォルダーの容量を算出して返す
\r
243 /// <param name="path">
\r
244 /// 対象ファイル及びフォルダーのパス
\r
249 public static ulong GetFileSize(string path)
\r
251 return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?
\r
252 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);
\r
256 /// フォルダーの容量を算出して返す
\r
258 /// <param name="dirInfo">
\r
264 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)
\r
267 foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {
\r
268 size += (ulong) child.Length;
\r
274 /// ワイルドカードを展開したファイルパス文字列を作り出す。
\r
275 /// 戻り値のそれぞれの文字列はフルパスとなる。
\r
277 /// <param name="baseDir">ベース(基点)のディレクトリ</param>
\r
278 /// <param name="pattern">ワイルドカードパターン</param>
\r
279 /// <returns>展開したファイルパス</returns>
\r
280 public static string[] ExtendWildcardFile(string baseDir, string pattern)
\r
282 if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {
\r
283 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す
\r
286 string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);
\r
287 List<string> extended = new List<string>();
\r
289 if (pathArray.Length == 1) {
\r
290 extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
291 extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
292 } else { // pathArray.Length > 1
\r
293 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);
\r
295 foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {
\r
297 extended.AddRange(ExtendWildcardFile(subDir, subPattern));
\r
300 } catch (UnauthorizedAccessException) {
\r
304 extended.RemoveAll(
\r
305 delegate(string path) {
\r
306 return ! File.Exists(path);
\r
310 return extended.ToArray();
\r
314 /// パスをパス区切り文字列ごとに分割した配列を返す
\r
316 /// <param name="path">パス文字列。相対・絶対は区別しない</param>
\r
317 /// <returns>フォルダー名ごとに分けられた文字列配列</returns>
\r
318 private static string[] splitPath(string path)
\r
320 return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});
\r
324 /// パスがフォルダーのとき、最後がパスセパレータで終了するようにする。
\r
326 /// <param name="path">パス</param>
\r
327 /// <returns>処理されたパス</returns>
\r
328 private static string fixLastPathCharForDirectory(string path)
\r
330 string fixedPath = path;
\r
331 if (Directory.Exists(path) && path[path.Length-1] != Path.DirectorySeparatorChar) {
\r
332 fixedPath += Path.DirectorySeparatorChar;
\r
338 /// 絶対パスを相対パスに変換して返します。
\r
340 /// <param name="baseDirectoryPath">相対パスの基準のフォルダー</param>
\r
341 /// <param name="absPath">絶対パス</param>
\r
342 /// <returns><code>absPath</code>の絶対パス表現</returns>
\r
343 public static string GetRelativePath(string baseDirectoryPath, string absPath)
\r
345 Uri baseuri = new Uri(fixLastPathCharForDirectory(baseDirectoryPath));
\r
346 Uri absuri = new Uri(fixLastPathCharForDirectory(absPath));
\r
348 string relative = baseuri.MakeRelativeUri(absuri).ToString();
\r
349 relative = System.Web.HttpUtility.UrlDecode(relative);
\r
350 relative = relative.Replace('/', Path.DirectorySeparatorChar);
\r
356 /// 相対パスに含まれている".."などを消去する
\r
358 /// <param name="aPath"></param>
\r
359 /// <returns></returns>
\r
360 public static string GetDotsRemovedPath(string aPath)
\r
362 string[] folders = splitPath(aPath);
\r
363 List<string> newFolders = new List<string>();
\r
365 foreach (string fol in folders) {
\r
368 } else if (fol == "..") {
\r
370 newFolders.RemoveAt(newFolders.Count-1);
\r
372 newFolders.Add(fol);
\r
376 return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());
\r
385 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
387 /// <param name="path">XMLファイルのパス</param>
\r
388 /// <param name="sr">シリアライザ</param>
\r
389 /// <returns>デシリアル化されたオブジェクト</returns>
\r
390 public static object GetDeserializedObject(string path, System.Xml.Serialization.XmlSerializer sr)
\r
392 object retVal = null;
\r
393 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
\r
394 using (System.Xml.XmlReader xreader = System.Xml.XmlReader.Create(fs)) {
\r
395 retVal = sr.Deserialize(xreader);
\r
402 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
404 /// <param name="path">XMLファイルのパス</param>
\r
405 /// <returns>デシリアル化されたオブジェクト</returns>
\r
406 public static T GetDeserializedObject<T>(string path)
\r
408 T retVal = default(T);
\r
409 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
410 retVal = (T) GetDeserializedObject(path, sr);
\r
415 /// オブジェクトをXMLでシリアル化してファイルに書き込む
\r
417 /// <param name="path">XMLファイルのパス</param>
\r
418 /// <param name="obj">シリアル化する対象のオブジェクト</param>
\r
419 public static void PutSerializeObject<T>(string path, T obj)
\r
421 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
\r
422 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
423 sr.Serialize(fs, obj);
\r
432 /// 現在のユーザがAdministrators権限を持っているか否かを返す。
\r
434 /// <remarks>UAC有効時には権限昇格後になってtrueを返すようになります</remarks>
\r
435 public static bool IsAdministrators()
\r
437 // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する
\r
438 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );
\r
439 IPrincipal prin = System.Threading.Thread.CurrentPrincipal;
\r
440 return prin.IsInRole(@"BUILTIN\Administrators");
\r
444 /// 現在のPCがUACが有効になっているか否かを返す。
\r
445 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。
\r
447 /// <returns>UACが有効ならばtrue</returns>
\r
448 public static bool IsUACEnabled()
\r
451 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {
\r
452 return ((int) key.GetValue("EnableLUA", 0)) == 1;
\r
454 } catch (Exception) {
\r
461 #region プロセス関連便利メソッド群
\r
464 /// プロセスに出力をリダイレクトした上で実行
\r
466 /// <param name="procInfo">プロセス起動情報</param>
\r
467 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
468 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
469 /// <returns>実行プロセス</returns>
\r
470 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
471 DataReceivedEventHandler outputReceived,
\r
472 DataReceivedEventHandler errorReceived)
\r
474 if (outputReceived != null) {
\r
475 procInfo.RedirectStandardOutput = true;
\r
477 if (errorReceived != null) {
\r
478 procInfo.RedirectStandardError = true;
\r
480 procInfo.UseShellExecute = false;
\r
482 Process hProcess = Process.Start(procInfo);
\r
483 if (outputReceived != null) {
\r
484 hProcess.OutputDataReceived += outputReceived;
\r
485 hProcess.BeginOutputReadLine();
\r
487 if (errorReceived != null) {
\r
488 hProcess.ErrorDataReceived += errorReceived;
\r
489 hProcess.BeginErrorReadLine();
\r
497 /// プロセスに出力をリダイレクトした上で実行
\r
499 /// <param name="procInfo">プロセス起動情報</param>
\r
500 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
501 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
502 /// <returns>実行プロセス</returns>
\r
503 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
504 EventHandler<AnyDataEventArgs<string>> outputReceived,
\r
505 EventHandler<AnyDataEventArgs<string>> errorReceived)
\r
507 return ProcessStartWithOutputCapture(procInfo,
\r
508 ConvertToDataReceivedEventHandler(outputReceived),
\r
509 ConvertToDataReceivedEventHandler(errorReceived));
\r
512 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)
\r
514 if (handler == null) return null;
\r
515 return delegate (object sender, DataReceivedEventArgs e) {
\r
516 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);
\r
517 handler.Invoke(sender, args);
\r
526 /// 任意データのイベント情報を表現するクラス
\r
528 public class AnyDataEventArgs<T> : EventArgs
\r
535 public AnyDataEventArgs(T data)
\r
544 get { return data; }
\r