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
46 /// <param name="enus">元となる複数のイテレータ</param>
\r
47 /// <returns>結合されたイテレータ</returns>
\r
48 public static IEnumerable<T> MeargeEnumerable<T>(params IEnumerable<T>[] enus)
\r
50 foreach (IEnumerable<T> enu in enus) {
\r
51 if (enu == null) continue;
\r
53 foreach (T elem in enu) {
\r
62 /// <param name="enus">元となる複数のイテレータ</param>
\r
63 /// <returns>結合されたイテレータ</returns>
\r
64 public static IEnumerable<T> MeargeEnumerable<T>(params IEnumerator<T>[] enus)
\r
66 foreach (IEnumerator<T> enu in enus) {
\r
67 if (enu == null) continue;
\r
70 while (enu.MoveNext()) {
\r
71 yield return enu.Current;
\r
80 /// イテレータを結合して、Listとして返す
\r
82 /// <param name="enus">元となる複数のイテレータ</param>
\r
83 /// <returns>結合されたイテレータ</returns>
\r
84 public static List<T> MeargeList<T>(params IEnumerable<T>[] enus)
\r
86 List<T> list = new List<T>();
\r
88 foreach (IEnumerable<T> enu in enus) {
\r
89 if (enu == null) continue;
\r
97 /// イテレータを配列に効率的に変換する
\r
99 /// <remarks>与えられる型が具体的にわかっているならば、それに特化した手続きをとる方が好ましい</remarks>
\r
100 /// <param name="enu">元となるイテレータ</param>
\r
101 /// <returns>変換された配列</returns>
\r
102 public static T[] IEnumerable2Array<T>(IEnumerable<T> enu) {
\r
106 return ((enu is List<T>)? ((List<T>)enu):new List<T>(enu)).ToArray();
\r
112 #region ファイル情報関連ユーテイリティ関数
\r
115 /// パス変数に指定のフォルダを追加する
\r
117 /// <param name="dir">追加するフォルダ</param>
\r
118 public static void AddDirectoryToPath(string dir)
\r
120 string path = Environment.GetEnvironmentVariable("PATH");
\r
122 if (path.IndexOf(dir) < 0) {
\r
123 path = dir + Path.PathSeparator + path;
\r
124 Environment.SetEnvironmentVariable("PATH", path);
\r
129 /// バイト単位で表現された容量を接尾語を活用して適切な文字列に変換
\r
131 /// <param name="bytes">バイト単位の容量</param>
\r
132 /// <returns>読みやすい形に直された容量文字列</returns>
\r
133 public static string FormatSize(double bytes)
\r
135 string[] units = new string[] {"B", "KB", "MB", "GB", "TB"};
\r
137 double size = bytes;
\r
139 for (i = 0; size >= 1024 && i < units.Length-1 ; i++) {
\r
143 return string.Format("{0:F2}{1}", size, units[i]);
\r
146 public static string FormatSize(long bytes)
\r
148 return FormatSize((double) bytes);
\r
152 /// URLからそのファイル名を生成する
\r
154 /// <param name="url">対象のurl</param>
\r
155 public static string Url2filename(string url)
\r
157 string filename = Path.GetFileName(System.Web.HttpUtility.UrlDecode(url, Encoding.UTF8));
\r
160 if ((pos = filename.IndexOfAny(Path.GetInvalidFileNameChars())) >= 0) {
\r
161 // 不正な文字が含まれているならば、それ以降を削除
\r
162 filename = filename.Substring(0, pos);
\r
163 // そうしてしまったら文字の内容がまったくなくなってしまったら、ランダムな名に
\r
164 if (filename.Length == 0) {
\r
165 filename = Path.GetFileName(Path.GetTempFileName());
\r
169 //return UrlDecode(Path.GetFileName(url), Encoding.UTF8);
\r
173 /// 再帰的にファイルの属性を指定します。強制的にフォルダの再帰削除の前に読み込み専用属性を消すのに使います。
\r
175 /// <param name="path">設定するフォルダ</param>
\r
176 /// <param name="attr">設定する属性値</param>
\r
177 public static void SetAttributeRecursive(string path, FileAttributes attr)
\r
180 File.SetAttributes(path, attr);
\r
183 foreach (string file in Directory.GetFiles(path)) {
\r
184 File.SetAttributes(file, attr);
\r
188 foreach (string file in Directory.GetDirectories(path)) {
\r
189 SetAttributeRecursive(file, attr);
\r
194 /// 再帰的にファイルのアクセス権限(ユーザ権限など)を設定します
\r
196 /// <param name="path">設定するフォルダ</param>
\r
197 /// <param name="filesec">変更先権限</param>
\r
198 public static void SetAccessControlRecursive(string path, FileSecurity filesec)
\r
201 File.SetAccessControl(path, filesec);
\r
204 foreach (string file in Directory.GetFiles(path)) {
\r
205 File.SetAccessControl(file, filesec);
\r
209 foreach (string file in Directory.GetDirectories(path)) {
\r
210 SetAccessControlRecursive(file, filesec);
\r
215 /// ファイルまたはフォルダの容量を算出して返す
\r
217 /// <param name="path">
\r
218 /// 対象ファイル及びフォルダのパス
\r
223 public static ulong GetFileSize(string path)
\r
225 return ((File.GetAttributes(path) & FileAttributes.Directory) != 0)?
\r
226 GetDirectoryFileSize(new DirectoryInfo(path)) : ((ulong) (new FileInfo(path)).Length);
\r
232 /// <param name="dirInfo">
\r
238 public static ulong GetDirectoryFileSize(DirectoryInfo dirInfo)
\r
241 foreach (FileInfo child in dirInfo.GetFiles("*", SearchOption.AllDirectories)) {
\r
242 size += (ulong) child.Length;
\r
248 /// ワイルドカードを展開したファイルパス文字列を作り出す。
\r
249 /// 戻り値のそれぞれの文字列はフルパスとなる。
\r
251 /// <param name="baseDir">ベース(基点)のディレクトリ</param>
\r
252 /// <param name="pattern">ワイルドカードパターン</param>
\r
253 /// <returns>展開したファイルパス</returns>
\r
254 public static string[] ExtendWildcardFile(string baseDir, string pattern)
\r
256 if (pattern.IndexOfAny(new char[]{'*','?'}) < 0) {
\r
257 return new string[]{Path.Combine(baseDir, pattern)}; // ワイルドカードがなければそのまま返す
\r
260 string[] pathArray = pattern.Split(Path.DirectorySeparatorChar);
\r
261 List<string> extended = new List<string>();
\r
263 if (pathArray.Length == 1) {
\r
264 extended.AddRange(Directory.GetFiles(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
265 extended.AddRange(Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly));
\r
266 } else { // pathArray.Length > 1
\r
267 string subPattern = string.Join(Path.DirectorySeparatorChar.ToString(), pathArray, 1, pathArray.Length-1);
\r
269 foreach (string subDir in Directory.GetDirectories(baseDir, pathArray[0], SearchOption.TopDirectoryOnly)) {
\r
271 extended.AddRange(ExtendWildcardFile(subDir, subPattern));
\r
274 } catch (UnauthorizedAccessException) {
\r
278 extended.RemoveAll(
\r
279 delegate(string path) {
\r
280 return ! File.Exists(path);
\r
284 return extended.ToArray();
\r
288 /// パスをパス区切り文字列ごとに分割した配列を返す
\r
290 /// <param name="path">パス文字列。相対・絶対は区別しない</param>
\r
291 /// <returns>フォルダ名ごとに分けられた文字列配列</returns>
\r
292 private static string[] splitPath(string path)
\r
294 return path.Split(new char[]{Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar});
\r
298 /// Converts a given absolute path and a given base path to a path that leads
\r
299 /// from the base path to the absoulte path. (as a relative path)
\r
301 public static string GetRelativePath(string baseDirectoryPath, string absPath)
\r
303 // TODO SharpDevelopのICSharpCode.Core.FileUtilityからのコピペ(GPL)
\r
305 string[] bPath = splitPath(baseDirectoryPath);
\r
306 string[] aPath = splitPath(absPath);
\r
308 for(; indx < Math.Min(bPath.Length, aPath.Length); ++indx){
\r
309 if(!bPath[indx].Equals(aPath[indx], StringComparison.OrdinalIgnoreCase))
\r
317 StringBuilder erg = new StringBuilder();
\r
319 if(indx == bPath.Length) {
\r
320 // erg.Append('.');
\r
321 // erg.Append(Path.DirectorySeparatorChar);
\r
323 for (int i = indx; i < bPath.Length; ++i) {
\r
325 erg.Append(Path.DirectorySeparatorChar);
\r
328 erg.Append(String.Join(Path.DirectorySeparatorChar.ToString(), aPath, indx, aPath.Length-indx));
\r
329 return erg.ToString();
\r
333 /// 相対パスに含まれている".."などを消去する
\r
335 /// <param name="aPath"></param>
\r
336 /// <returns></returns>
\r
337 public static string GetDotsRemovedPath(string aPath)
\r
339 string[] folders = splitPath(aPath);
\r
340 List<string> newFolders = new List<string>();
\r
342 foreach (string fol in folders) {
\r
345 } else if (fol == "..") {
\r
347 newFolders.RemoveAt(newFolders.Count-1);
\r
349 newFolders.Add(fol);
\r
353 return string.Join(Path.DirectorySeparatorChar.ToString(), newFolders.ToArray());
\r
361 /// XMLでシリアル化したオブジェクトのXMLファイルを読み込み、デシリアル化したオブジェクトを取得する
\r
363 /// <param name="path">XMLファイルのパス</param>
\r
364 /// <returns>デシリアル化されたオブジェクト</returns>
\r
365 public static T GetDeserializedObject<T>(string path)
\r
367 T retVal = default(T);
\r
368 using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) {
\r
369 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
370 retVal = (T) sr.Deserialize(fs);
\r
376 /// オブジェクトをXMLでシリアル化してファイルに書き込む
\r
378 /// <param name="path">XMLファイルのパス</param>
\r
379 /// <param name="obj">シリアル化する対象のオブジェクト</param>
\r
380 public static void PutSerializeObject<T>(string path, T obj)
\r
382 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
\r
383 System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(T));
\r
384 sr.Serialize(fs, obj);
\r
393 /// 現在のユーザがAdministrators権限を持っているか否かを返す。
\r
395 /// <remarks>UAC有効時には権限昇格後になってtrueを返すようになります</remarks>
\r
396 public static bool IsAdministrators()
\r
398 // 現在の Windows ユーザーを現在のスレッドのプリンシパルに反映する
\r
399 AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal );
\r
400 IPrincipal prin = System.Threading.Thread.CurrentPrincipal;
\r
401 return prin.IsInRole(@"BUILTIN\Administrators");
\r
405 /// 現在のPCがUACが有効になっているか否かを返す。
\r
406 /// レジストリのHKLM\SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System\EnableLUAの値を見る。
\r
408 /// <returns>UACが有効ならばtrue</returns>
\r
409 public static bool IsUACEnabled()
\r
412 using(RegistryKey key = Registry.LocalMachine.CreateSubKey(@"SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Policies¥System")) {
\r
413 return ((int) key.GetValue("EnableLUA", 0)) == 1;
\r
415 } catch (Exception) {
\r
422 #region プロセス関連便利メソッド群
\r
425 /// プロセスに出力をリダイレクトした上で実行
\r
427 /// <param name="procInfo">プロセス起動情報</param>
\r
428 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
429 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
430 /// <returns>実行プロセス</returns>
\r
431 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
432 DataReceivedEventHandler outputReceived,
\r
433 DataReceivedEventHandler errorReceived)
\r
435 if (outputReceived != null) {
\r
436 procInfo.RedirectStandardOutput = true;
\r
438 if (errorReceived != null) {
\r
439 procInfo.RedirectStandardError = true;
\r
441 procInfo.UseShellExecute = false;
\r
443 Process hProcess = Process.Start(procInfo);
\r
444 if (outputReceived != null) {
\r
445 hProcess.OutputDataReceived += outputReceived;
\r
446 hProcess.BeginOutputReadLine();
\r
448 if (errorReceived != null) {
\r
449 hProcess.ErrorDataReceived += errorReceived;
\r
450 hProcess.BeginErrorReadLine();
\r
458 /// プロセスに出力をリダイレクトした上で実行
\r
460 /// <param name="procInfo">プロセス起動情報</param>
\r
461 /// <param name="outputReceived">標準出力用リスナ(null可)</param>
\r
462 /// <param name="errorReceived">エラー出力用リスナ(null可)</param>
\r
463 /// <returns>実行プロセス</returns>
\r
464 public static Process ProcessStartWithOutputCapture(ProcessStartInfo procInfo,
\r
465 EventHandler<AnyDataEventArgs<string>> outputReceived,
\r
466 EventHandler<AnyDataEventArgs<string>> errorReceived)
\r
468 return ProcessStartWithOutputCapture(procInfo,
\r
469 ConvertToDataReceivedEventHandler(outputReceived),
\r
470 ConvertToDataReceivedEventHandler(errorReceived));
\r
473 public static DataReceivedEventHandler ConvertToDataReceivedEventHandler(EventHandler<AnyDataEventArgs<string>> handler)
\r
475 if (handler == null) return null;
\r
476 return delegate (object sender, DataReceivedEventArgs e) {
\r
477 AnyDataEventArgs<string> args = new AnyDataEventArgs<string>(e.Data);
\r
478 handler.Invoke(sender, args);
\r
486 /// 任意データのイベント情報を表現するクラス
\r
488 public class AnyDataEventArgs<T> : EventArgs
\r
495 public AnyDataEventArgs(T data)
\r
504 get { return data; }
\r