參考微軟官方文檔-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/tokens/verbatimphp
一、在變量名前加@,能夠告訴編譯器,@後的就是變量名。主要用於變量名和C#關鍵字重複時使用。html
string[] @for = { "John", "James", "Joan", "Jamie" }; for (int ctr = 0; ctr < @for.Length; ctr++) { Console.WriteLine($"Here is your gift, {@for[ctr]}!"); } // The example displays the following output: // Here is your gift, John! // Here is your gift, James! // Here is your gift, Joan! // Here is your gift, Jamie!
二、在字符串前加@,字符串中的轉義字符串將再也不轉義。例外:""仍將轉義爲",{{和}}仍將轉義爲{和}。在同時使用字符串內插和逐字字符串時,$要在@的前面mysql
string filename1 = @"c:\documents\files\u0066.txt"; string filename2 = "c:\\documents\\files\\u0066.txt"; Console.WriteLine(filename1); Console.WriteLine(filename2); // The example displays the following output: // c:\documents\files\u0066.txt // c:\documents\files\u0066.txt
三、相似於第一條,用於在命名衝突時區分兩個特性名。特性Attribute自定義的類型名稱在起名時應以Attribute結尾,例如InfoAttribute,以後咱們能夠用InfoAttribute或Info來引用它。可是若是咱們定義了兩個自定義特性,分別命名Info和InfoAttribute,則在使用Info這個名字時,編譯器就不知道是哪一個了。這時,若是想用Info,就用@Info,想用InfoAttribute,就把名字寫全。sql
using System; [AttributeUsage(AttributeTargets.Class)] public class Info : Attribute { private string information; public Info(string info) { information = info; } } [AttributeUsage(AttributeTargets.Method)] public class InfoAttribute : Attribute { private string information; public InfoAttribute(string info) { information = info; } } [Info("A simple executable.")] // Generates compiler error CS1614. Ambiguous Info and InfoAttribute. // Prepend '@' to select 'Info'. Specify the full name 'InfoAttribute' to select it. public class Example { [InfoAttribute("The entry point.")] public static void Main() { } }
C#經過序列化實現深表複製
利用二進制序列化的方式進行深拷貝 有一個缺陷 序列化的類型必須標識爲刻序列化的[Serializable] 不然沒法進行二進制序列化數據庫
class Program { static void Main(string[] args) { Person P = new Person("小麗",20); Person N = (Person)DeepCopy(P); P.Grade = 200; Console.WriteLine(N.Grade.ToString()); Console.ReadKey(); } /// <summary> /// 利用序列化實現深拷貝 /// </summary> /// <param name="_obj"></param> /// <returns></returns> static object DeepCopy(object _obj) { BinaryFormatter BF2 = new BinaryFormatter(); using (MemoryStream stream = new MemoryStream()) { BF2.Serialize(stream,_obj); stream.Position = 0; return BF2.Deserialize(stream); } } } [Serializable] class Person { private string mName; private int mGrade; public int Grade { get { return mGrade; } set { mGrade = value; } } public string Name { get { return mName; } set { mName = value; } } public Person(string _Name, int _Grade) { mName = _Name; mGrade = _Grade; } public Person() { } }
細說併發編程-TPL
本節導航
- 基本概念
- 併發編程
- TPL
- 線程基礎
- windows爲何要支持線程
- 線程開銷
- CPU的發展
- 使用線程的理由
- 如何寫一個簡單Parallel.For循環
- 數據並行
- Parallel.For剖析
優秀軟件的一個關鍵特徵就是具備併發性。過去的幾十年,咱們能夠進行併發編程,可是
難度很大。之前,併發性軟件的編寫、調試和維護都很難,這致使不少開發人員爲圖省事
放棄了併發編程。新版 .NET 中的程序庫和語言特徵,已經讓併發編程變得簡單多了。隨
着 Visual Studio 2012 的發佈,微軟明顯下降了併發編程的門檻。之前只有專家才能作併發
編程,而今天,每個開發人員都可以(並且應該)接受併發編程。編程
許多我的電腦和工做站都有多核CPU,能夠同時執行多個線程。爲了充分利用硬件,您能夠將代碼並行化,以便跨多個處理器分發工做。c#
在過去,並行須要對線程和鎖進行低級操做。Visual Studio和.NET框架經過提供運行時、類庫類型和診斷工具來加強對並行編程的支持。這些特性是在.NET Framework 4中引入的,它們使得並行編程變得簡單。您能夠用天然的習慣用法編寫高效、細粒度和可伸縮的並行代碼,而無需直接處理線程或線程池。windows
下圖展現了.NET框架中並行編程體系結構。api
1 基本概念
1.1 併發編程
-
併發數組
同時作多件事情
這個解釋直接代表了併發的做用。終端用戶程序利用併發功能,在輸入數據庫的同時響應用戶輸入。服務器應用利用併發,在處理第一個請求的同時響應第二個請求。只要你但願程序同時作多件事情,你就須要併發。
-
多線程
併發的一種形式,它採用多個線程來執行程序。從字面上看,多線程就是使用多個線程。多線程是併發的一種形式,但不是惟一的形式。
-
並行處理
把正在執行的大量的任務分割成小塊,分配給多個同時運行的線程。
爲了讓處理器的利用效率最大化,並行處理(或並行編程)採用多線程。當現代多核 CPU行大量任務時,若只用一個核執行全部任務,而其餘覈保持空閒,這顯然是不合理的。
並行處理把任務分割成小塊並分配給多個線程,讓它們在不一樣的核上獨立運行。並行處理是多線程的一種,而多線程是併發的一種。
-
異步編程
併發的一種形式,它採用 future 模式或回調(callback)機制,以免產生沒必要要的線程。
一個 future(或 promise)類型表明一些即將完成的操做。在 .NET 中,新版 future 類型
有 Task 和 Task 。在老式異步編程 API 中,採用回調或事件(event),而不是
future。異步編程的核心理念是異步操做:啓動了的操做將會在一段時間後完成。這個操做
正在執行時,不會阻塞原來的線程。啓動了這個操做的線程,能夠繼續執行其餘任務。當
操做完成時,會通知它的future,或者調用回調函數,以便讓程序知道操做已經結束。
NOTE:一般狀況下,一個併發程序要使用多種技術。大多數程序至少使用了多線程(經過線程池)和異步編程。要大膽地把各類併發編程形式進行混合和匹配,在程序的各個部分使用
合適的工具。
1.2 TPL
任務並行庫(TPL)是System.Threading和System.Threading.Tasks命名空間中的一組公共類型和API。
TPL動態地擴展併發度,以最有效地使用全部可用的處理器。經過使用TPL,您能夠最大限度地提升代碼的性能,同時專一於您的代碼的業務實現。
從.NET Framework 4開始,TPL是編寫多線程和並行代碼的首選方式。
2 線程基礎
2.1 Windows 爲何要支持線程
在計算機的早期歲月,操做系統沒提供線程的概念。事實上,整個系統只運行着一個執行線程(單線程),其中同時包含操做系統代碼和應用程序代碼。只用一個執行線程的問題在於,長時間運行的任務會阻止其餘任務執行。
例如,在16位Windows的那些日子裏,打印一個文檔的應用程序很容易「凍結」整個機器,形成OS和其餘應用程序中止響應。有的程序含有bug,會形成死循環。遇到這個問題,用戶只好重啓計算機。用戶對此深惡痛絕。
因而微軟下定決心設計一個新的OS,這個OS必須健壯,可靠,易因而伸縮以安全,同同時必須改進16位windows的許多不足。
微軟設計這個OS內核時,他們決定在一個進程(Process)中運行應用程序的每一個實例。進程不過是應用程序的一個實例要使用的資源的一個集合。每一個進程都被賦予一個虛擬地址空間,確保一個進程使用的代碼和數據沒法由另外一個進程訪問。這就確保了應用程序實例的健壯性。因爲應用程序破壞不了其餘應用程序或者OS自己,因此用戶的計算體驗變得更好了。
聽起來彷佛不錯,但CPU自己呢?若是一個應用程序進入無限循環,會發生什麼呢?若是機器中只有一個CPU,它會執行無限循環,不能執行其它任何東西。因此,雖然數據沒法被破壞,並且更安全,但系統仍然可能中止響應。微軟要修復這個問題,他們拿出的方案就是線程。做爲Windows概念,線程的職責是對CPU進行虛擬化。Windows爲每一個進程都提供了該進程專用的專用的線程(功能至關於一個CPU,可將線程理解成一個邏輯CPU)。若是應用程序的代碼進入無限循環,與那個代碼關聯的進程會被「凍結」,但其餘進程(他們有本身的線程)不會凍結:他們會繼續執行!
2.2 線程開銷
線程是一個很是強悍的概念,由於他們使windows即便在執行長時間運行的任務時也能隨時響應。另外,線程容許用戶使用一個應用程序(好比「任務管理器」)強制終止彷佛凍結的一個應用程序(它也有可能正在執行一個長時間運行的任務)。可是,和一切虛擬化機制同樣,線程會產生空間(內存耗用)和時間(運行時的執行性能)上的開銷。
建立線程,讓它進駐系統以及最後銷燬它都須要空間和時間。另外,還須要討論一下上下文切換。單CPU的計算機一次只能作一件事情。因此,windows必須在系統中的全部線程(邏輯CPU)之間共享物理CPU。
在任何給定的時刻,Windows只將一個線程分配給一個CPU。那個線程容許運行一個時間片。一旦時間片到期,Windows就上下文切換到另外一個給線程。每次上下文切換都要求Windows執行如下操做:
- 將CPU寄存器中的值保存到當前正在運行的線程的內核對象內部的一個上下文結構中。
- 從現有線程集合中選一個線程供調度(切換到的目標線程)。若是該線程由另外一個進程擁有,Window在開始執行任何代碼或者接觸任何數據以前,還必須切換CPU「看得見」的虛擬地址空間。
- 將所選上下文結構中的值加載到CPU的寄存器中。
上下文切換完成後,CPU執行所選的線程,直到它的時間片到期。而後,會發生新一輪的上下文切換。Windows大約每30ms執行一次上下文切換。
上下文切換是淨開銷:也就是說上下文切換所產生的開銷不會換來任何內存或性能上的收益。
根據上述討論,咱們的結論是必須儘量地避免使用線程,由於他們要耗用大量的內存,並且須要至關多的時間來建立,銷燬和管理。Windows在線程之間進行上下文切換,以及在發生垃圾回收的時候,也會浪費很多時間。然而,根據上述討論,咱們還得出一個結論,那就是有時候必須使用線程,由於它們使Windows變得更健壯,反應更靈敏。
應該指出的是,安裝了多個CPU或者一個多核CPU)的計算機能夠真正同時運行幾個線程,這提高了應用程序的可伸縮性(在少許的時間裏作更多工做的能力)。Windows爲每一個CPU內核都分配一個線程,每一個內核都本身執行到其餘線程的上下文切換。Windows確保單個線程不會在多個內核上同時被調度,由於這會代理巨大的混亂。今天,許多計算機都包含了多個CPu,超線程CPU或者多核CPU。可是,windows最初設計時,單CPU計算機纔是主流,因此Windows設計了線程來加強系統的響應能力和可靠性。今天,線程還被用於加強應用程序的可伸縮性,但在只有多CPU(或多核CPU)計算機上纔有可能發生。
2.3 CPU的發展
過去,CPU速度一直隨着時間在變快。因此,在一臺舊機器上運行得慢的程序在新機器上通常會快些。然而,CPU 廠商沒有延續CPU愈來愈快的趨勢。因爲CPU廠商不能作到一直提高CPU的速度,因此它們側重於將晶體管作得愈來愈小,使一個芯片上可以容納更多的晶體管。今天,一個硅芯片能夠容納2個或者更多的CPU內核。這樣一來,若是在寫軟件時能利用多個內核,軟件就能運行得更快些。
今天的計算機使用瞭如下三種多CPU技術。
- 多個CPU
- 超線程芯片
- 多核芯片
2.4 使用線程的理由
使用線程有如下三方面的理由。
- 使用線程能夠將代碼同其餘代碼隔離
這將提升應用程序的可靠性。事實上,這正是Windows在操做系統中引入線程概念的緣由。Windows之因此須要線程來得到可靠性,是由於你的應用程序對於操做系統來講是的第三方組件,而微軟不會在你發佈應用程序以前對這些代碼進行驗證。若是你的應用程序支持加載由其它廠商生成的組件,那麼應用程序對健壯性的要求就會很高,使用線程將有助於知足這個需求。
- 可使用線程來簡化編碼
有的時候,若是經過一個任務本身的線程來執行該任務,或者說單獨一個線程來處裏該任務,編碼會變得更簡單。可是,若是這樣作,確定要使用額外的資源,也不是十分「經濟」(沒有使用盡可能少的代碼達到目的)。如今,即便要付出一些資源做爲代價,我也寧願選擇簡單的編碼過程。不然,乾脆堅持一直用機器語言寫程序好了,徹底不必成爲一名C#開發人員。但有的時候,一些人在使用線程時,以爲本身選擇了一種更容易的編碼方式,但實際上,它們是將事情(和它們的代碼)大大複雜化了。一般,在你引入線程時,引入的是要相互協做的代碼,它們可能要求線程同步構造知道另外一個線程在何時終止。一旦開始涉及協做,就要使用更多的資源,同時會使代碼變得更復雜。因此,在開始使用線程以前,務必肯定線程真的可以幫助你。
- 可使用線程來實現併發執行
若是(並且只有)知道本身的應用程序要在多CPU機器上運行,那麼讓多個任務同時運行,就能提升性能。如今安裝了多個CPU(或者一個多核CPU)的機器至關廣泛,因此設計應用程序來使用多個內核是有意義的。
3 數據並行(Data Parallelism)
3.1 數據並行
數據並行是指對源集合或數組中的元素同時(即並行)執行相同操做的狀況。在數據並行操做中,源集合被分區,以便多個線程能夠同時在不一樣的段上操做。
數據並行性是指對源集合或數組中的元素同時任務並行庫(TPL)經過system.threading.tasks.parallel類支持數據並行。這個類提供了for和for each循環的基於方法的並行實現。
您爲parallel.for或parallel.foreach循環編寫循環邏輯,就像編寫順序循環同樣。您沒必要建立線程或將工做項排隊。在基本循環中,您沒必要使用鎖。底層工做TPL已經幫你處理。
下面代碼展現順序和並行:
// Sequential version foreach (var item in sourceCollection) { Process(item); } // Parallel equivalent Parallel.ForEach(sourceCollection, item => Process(item));
並行循環運行時,TPL對數據源進行分區,以便循環能夠同時在多個部分上運行。在後臺,任務調度程序根據系統資源和工做負載對任務進行分區。若是工做負載變得不平衡,調度程序會在多個線程和處理器之間從新分配工做。
下面的代碼來展現如何經過Visual Studio調試代碼:
public static void test()
{
int[] nums = Enumerable.Range(0, 1000000).ToArray(); long total = 0; // Use type parameter to make subtotal a long, not an int Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) => { subtotal += nums[j]; return subtotal; }, (x) => Interlocked.Add(ref total, x) ); Console.WriteLine("The total is {0:N0}", total); Console.WriteLine("Press any key to exit"); Console.ReadKey(); }
-
選擇調試 > 開始調試,或按F5。
應用在調試模式下啓動,並會在斷點處暫停。 -
在中斷模式下打開線程經過選擇窗口調試 > Windows > 線程。 您必須位於一個調試會話以打開或請參閱線程和其餘調試窗口。
3.2 Parallel.For剖析
查看Parallel.For的底層,
public static ParallelLoopResult For<TLocal>(int fromInclusive, int toExclusive, Func<TLocal> localInit, Func<int, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally);
清楚的看到有個func函數,看起來很熟悉。
[TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=b77a5c561934e089")] public delegate TResult Func<out TResult>();
原來是定義的委託,有多個重載,具體查看文檔[https://docs.microsoft.com/en-us/dotnet/api/system.func-4?view=netframework-4.7.2]
實際上TPL以前,實現併發或多線程,基本都要使用委託。
TIP:關於委託,你們能夠查看(https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/delegates)。或者《細說委託》(https://www.cnblogs.com/laoyu/archive/2013/01/13/2859000.html)
參考
- https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/
- https://docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/delegates
- https://www.cnblogs.com/laoyu/archive/2013/01/13/2859000.html
- 《C#併發經典實例》
- 《CLR via C#》第3版
使用反射和動態生成代碼兩種方式(Reflect和Emit)
反射將DataTable轉爲List方法
1 public static List<T> ToListByReflect<T>(this DataTable dt) where T : new() 2 { 3 List<T> ts = new List<T>(); 4 string tempName = string.Empty; 5 T t = new T(); 6 PropertyInfo[] propertys = t.GetType().GetProperties(); 7 foreach (DataRow dr in dt.Rows) 8 { 9 foreach (PropertyInfo pi in propertys) 10 { 11 tempName = pi.Name; 12 if (dt.Columns.Contains(tempName)) 13 { 14 object value = dr[tempName]; 15 if (value != DBNull.Value) 16 { 17 pi.SetValue(t, value, null); 18 } 19 } 20 } 21 ts.Add(t); 22 } 23 return ts; 24 }
動態生成代碼將DataTable轉爲List方法
1 public static List<T> ToListByEmit<T>(this DataTable dt) where T : class, new() 2 { 3 List<T> list = new List<T>(); 4 if (dt == null || dt.Rows.Count == 0) 5 return list; 6 DataTableEntityBuilder<T> eblist = DataTableEntityBuilder<T>.CreateBuilder(dt.Rows[0]); 7 foreach (DataRow info in dt.Rows) 8 list.Add(eblist.Build(info)); 9 dt.Dispose(); 10 dt = null; 11 return list; 12 } 13 public class DataTableEntityBuilder<Entity> 14 { 15 private static readonly MethodInfo getValueMethod = typeof(DataRow).GetMethod("get_Item", new Type[] { typeof(int) }); 16 private static readonly MethodInfo isDBNullMethod = typeof(DataRow).GetMethod("IsNull", new Type[] { typeof(int) }); 17 private delegate Entity Load(DataRow dataRecord); 18 private Load handler; 19 private DataTableEntityBuilder() { } 20 public Entity Build(DataRow dataRecord) 21 { 22 return handler(dataRecord); 23 } 24 public static DataTableEntityBuilder<Entity> CreateBuilder(DataRow dataRecord) 25 { 26 DataTableEntityBuilder<Entity> dynamicBuilder = new DataTableEntityBuilder<Entity>(); 27 DynamicMethod method = new DynamicMethod("DynamicCreateEntity", typeof(Entity), new Type[] { typeof(DataRow) }, typeof(Entity), true); 28 ILGenerator generator = method.GetILGenerator(); 29 LocalBuilder result = generator.DeclareLocal(typeof(Entity)); 30 generator.Emit(OpCodes.Newobj, typeof(Entity).GetConstructor(Type.EmptyTypes)); 31 generator.Emit(OpCodes.Stloc, result); 32 for (int i = 0; i < dataRecord.ItemArray.Length; i++) 33 { 34 PropertyInfo propertyInfo = typeof(Entity).GetProperty(dataRecord.Table.Columns[i].ColumnName); 35 Label endIfLabel = generator.DefineLabel(); 36 if (propertyInfo != null && propertyInfo.GetSetMethod() != null) 37 { 38 generator.Emit(OpCodes.Ldarg_0); 39 generator.Emit(OpCodes.Ldc_I4, i); 40 generator.Emit(OpCodes.Callvirt, isDBNullMethod); 41 generator.Emit(OpCodes.Brtrue, endIfLabel); 42 generator.Emit(OpCodes.Ldloc, result); 43 generator.Emit(OpCodes.Ldarg_0); 44 generator.Emit(OpCodes.Ldc_I4, i); 45 generator.Emit(OpCodes.Callvirt, getValueMethod); 46 generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType); 47 generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod()); 48 generator.MarkLabel(endIfLabel); 49 } 50 } 51 generator.Emit(OpCodes.Ldloc, result); 52 generator.Emit(OpCodes.Ret); 53 dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load)); 54 return dynamicBuilder; 55 } 56 }
而後寫個控制檯程序,對比一下兩個方法的效率(測試類大概有40個屬性)
電腦比較渣,使用Emit方法轉換100w條數據大概須要7秒,而反射則須要37秒。還測試了當數據量比較小時,Reflect反而比較快。
【轉載】C#工具類:實現文件操做File的工具類
在應用程序的開發中,文件操做的使用基本上是必不可少的,FileStream類、StreamWriter類、Directory類、DirectoryInfo類等都是文件操做中時常涉及到的類,咱們能夠經過封裝這一系列的文件操做爲一個工具類,該工具類包含文件的讀寫、文件的追加、文件的拷貝、刪除文件、獲取指定文件夾下全部子目錄及文件、獲取文件夾大小等一系列的操做方法。
封裝後的工具類以下:
public class FileOperate { #region 寫文件 protected void Write_Txt(string FileName, string Content) { Encoding code = Encoding.GetEncoding("gb2312"); string htmlfilename = HttpContext.Current.Server.MapPath("Precious\\" + FileName + ".txt"); //保存文件的路徑 string str = Content; StreamWriter sw = null; { try { sw = new StreamWriter(htmlfilename, false, code); sw.Write(str); sw.Flush(); } catch { } } sw.Close(); sw.Dispose(); } #endregion #region 讀文件 protected string Read_Txt(string filename) { Encoding code = Encoding.GetEncoding("gb2312"); string temp = HttpContext.Current.Server.MapPath("Precious\\" + filename + ".txt"); string str = ""; if (File.Exists(temp)) { StreamReader sr = null; try { sr = new StreamReader(temp, code); str = sr.ReadToEnd(); // 讀取文件 } catch { } sr.Close(); sr.Dispose(); } else { str = ""; } return str; } #endregion #region 取得文件後綴名 /**************************************** * 函數名稱:GetPostfixStr * 功能說明:取得文件後綴名 * 參 數:filename:文件名稱 * 調用示列: * string filename = "aaa.aspx"; * string s = DotNet.Utilities.FileOperate.GetPostfixStr(filename); *****************************************/ /// <summary> /// 取後綴名 /// </summary> /// <param name="filename">文件名</param> /// <returns>.gif|.html格式</returns> public static string GetPostfixStr(string filename) { int start = filename.LastIndexOf("."); int length = filename.Length; string postfix = filename.Substring(start, length - start); return postfix; } #endregion #region 寫文件 /**************************************** * 函數名稱:WriteFile * 功能說明:當文件不存時,則建立文件,並追加文件 * 參 數:Path:文件路徑,Strings:文本內容 * 調用示列: * string Path = Server.MapPath("Default2.aspx"); * string Strings = "這是我寫的內容啊"; * DotNet.Utilities.FileOperate.WriteFile(Path,Strings); *****************************************/ /// <summary> /// 寫文件 /// </summary> /// <param name="Path">文件路徑</param> /// <param name="Strings">文件內容</param> public static void WriteFile(string Path, string Strings) { if (!System.IO.File.Exists(Path)) { System.IO.FileStream f = System.IO.File.Create(Path); f.Close(); f.Dispose(); } System.IO.StreamWriter f2 = new System.IO.StreamWriter(Path, true, System.Text.Encoding.UTF8); f2.WriteLine(Strings); f2.Close(); f2.Dispose(); } #endregion #region 讀文件 /**************************************** * 函數名稱:ReadFile * 功能說明:讀取文本內容 * 參 數:Path:文件路徑 * 調用示列: * string Path = Server.MapPath("Default2.aspx"); * string s = DotNet.Utilities.FileOperate.ReadFile(Path); *****************************************/ /// <summary> /// 讀文件 /// </summary> /// <param name="Path">文件路徑</param> /// <returns></returns> public static string ReadFile(string Path) { string s = ""; if (!System.IO.File.Exists(Path)) s = "不存在相應的目錄"; else { StreamReader f2 = new StreamReader(Path, System.Text.Encoding.GetEncoding("gb2312")); s = f2.ReadToEnd(); f2.Close(); f2.Dispose(); } return s; } #endregion #region 追加文件 /**************************************** * 函數名稱:FileAdd * 功能說明:追加文件內容 * 參 數:Path:文件路徑,strings:內容 * 調用示列: * string Path = Server.MapPath("Default2.aspx"); * string Strings = "新追加內容"; * DotNet.Utilities.FileOperate.FileAdd(Path, Strings); *****************************************/ /// <summary> /// 追加文件 /// </summary> /// <param name="Path">文件路徑</param> /// <param name="strings">內容</param> public static void FileAdd(string Path, string strings) { StreamWriter sw = File.AppendText(Path); sw.Write(strings); sw.Flush(); sw.Close(); sw.Dispose(); } #endregion #region 拷貝文件 /**************************************** * 函數名稱:FileCoppy * 功能說明:拷貝文件 * 參 數:OrignFile:原始文件,NewFile:新文件路徑 * 調用示列: * string OrignFile = Server.MapPath("Default2.aspx"); * string NewFile = Server.MapPath("Default3.aspx"); * DotNet.Utilities.FileOperate.FileCoppy(OrignFile, NewFile); *****************************************/ /// <summary> /// 拷貝文件 /// </summary> /// <param name="OrignFile">原始文件</param> /// <param name="NewFile">新文件路徑</param> public static void FileCoppy(string OrignFile, string NewFile) { File.Copy(OrignFile, NewFile, true); } #endregion #region 刪除文件 /**************************************** * 函數名稱:FileDel * 功能說明:刪除文件 * 參 數:Path:文件路徑 * 調用示列: * string Path = Server.MapPath("Default3.aspx"); * DotNet.Utilities.FileOperate.FileDel(Path); *****************************************/ /// <summary> /// 刪除文件 /// </summary> /// <param name="Path">路徑</param> public static void FileDel(string Path) { File.Delete(Path); } #endregion #region 移動文件 /**************************************** * 函數名稱:FileMove * 功能說明:移動文件 * 參 數:OrignFile:原始路徑,NewFile:新文件路徑 * 調用示列: * string OrignFile = Server.MapPath("../說明.txt"); * string NewFile = Server.MapPath("../../說明.txt"); * DotNet.Utilities.FileOperate.FileMove(OrignFile, NewFile); *****************************************/ /// <summary> /// 移動文件 /// </summary> /// <param name="OrignFile">原始路徑</param> /// <param name="NewFile">新路徑</param> public static void FileMove(string OrignFile, string NewFile) { File.Move(OrignFile, NewFile); } #endregion #region 在當前目錄下建立目錄 /**************************************** * 函數名稱:FolderCreate * 功能說明:在當前目錄下建立目錄 * 參 數:OrignFolder:當前目錄,NewFloder:新目錄 * 調用示列: * string OrignFolder = Server.MapPath("test/"); * string NewFloder = "new"; * DotNet.Utilities.FileOperate.FolderCreate(OrignFolder, NewFloder); *****************************************/ /// <summary> /// 在當前目錄下建立目錄 /// </summary> /// <param name="OrignFolder">當前目錄</param> /// <param name="NewFloder">新目錄</param> public static void FolderCreate(string OrignFolder, string NewFloder) { Directory.SetCurrentDirectory(OrignFolder); Directory.CreateDirectory(NewFloder); } /// <summary> /// 建立文件夾 /// </summary> /// <param name="Path"></param> public static void FolderCreate(string Path) { // 判斷目標目錄是否存在若是不存在則新建之 if (!Directory.Exists(Path)) Directory.CreateDirectory(Path); } #endregion #region 建立目錄 public static void FileCreate(string Path) { FileInfo CreateFile = new FileInfo(Path); //建立文件 if (!CreateFile.Exists) { FileStream FS = CreateFile.Create(); FS.Close(); } } #endregion #region 遞歸刪除文件夾目錄及文件 /**************************************** * 函數名稱:DeleteFolder * 功能說明:遞歸刪除文件夾目錄及文件 * 參 數:dir:文件夾路徑 * 調用示列: * string dir = Server.MapPath("test/"); * DotNet.Utilities.FileOperate.DeleteFolder(dir); *****************************************/ /// <summary> /// 遞歸刪除文件夾目錄及文件 /// </summary> /// <param name="dir"></param> /// <returns></returns> public static void DeleteFolder(string dir) { if (Directory.Exists(dir)) //若是存在這個文件夾刪除之 { foreach (string d in Directory.GetFileSystemEntries(dir)) { if (File.Exists(d)) File.Delete(d); //直接刪除其中的文件 else DeleteFolder(d); //遞歸刪除子文件夾 } Directory.Delete(dir, true); //刪除已空文件夾 } } #endregion #region 將指定文件夾下面的全部內容copy到目標文件夾下面 果目標文件夾爲只讀屬性就會報錯。 /**************************************** * 函數名稱:CopyDir * 功能說明:將指定文件夾下面的全部內容copy到目標文件夾下面 果目標文件夾爲只讀屬性就會報錯。 * 參 數:srcPath:原始路徑,aimPath:目標文件夾 * 調用示列: * string srcPath = Server.MapPath("test/"); * string aimPath = Server.MapPath("test1/"); * DotNet.Utilities.FileOperate.CopyDir(srcPath,aimPath); *****************************************/ /// <summary> /// 指定文件夾下面的全部內容copy到目標文件夾下面 /// </summary> /// <param name="srcPath">原始路徑</param> /// <param name="aimPath">目標文件夾</param> public static void CopyDir(string srcPath, string aimPath) { try { // 檢查目標目錄是否以目錄分割字符結束若是不是則添加之 if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar) aimPath += Path.DirectorySeparatorChar; // 判斷目標目錄是否存在若是不存在則新建之 if (!Directory.Exists(aimPath)) Directory.CreateDirectory(aimPath); // 獲得源目錄的文件列表,該裏面是包含文件以及目錄路徑的一個數組 //若是你指向copy目標文件下面的文件而不包含目錄請使用下面的方法 //string[] fileList = Directory.GetFiles(srcPath); string[] fileList = Directory.GetFileSystemEntries(srcPath); //遍歷全部的文件和目錄 foreach (string file in fileList) { //先看成目錄處理若是存在這個目錄就遞歸Copy該目錄下面的文件 if (Directory.Exists(file)) CopyDir(file, aimPath + Path.GetFileName(file)); //不然直接Copy文件 else File.Copy(file, aimPath + Path.GetFileName(file), true); } } catch (Exception ee) { throw new Exception(ee.ToString()); } } #endregion #region 獲取指定文件夾下全部子目錄及文件(樹形) /**************************************** * 函數名稱:GetFoldAll(string Path) * 功能說明:獲取指定文件夾下全部子目錄及文件(樹形) * 參 數:Path:詳細路徑 * 調用示列: * string strDirlist = Server.MapPath("templates"); * this.Literal1.Text = DotNet.Utilities.FileOperate.GetFoldAll(strDirlist); *****************************************/ /// <summary> /// 獲取指定文件夾下全部子目錄及文件 /// </summary> /// <param name="Path">詳細路徑</param> public static string GetFoldAll(string Path) { string str = ""; DirectoryInfo thisOne = new DirectoryInfo(Path); str = ListTreeShow(thisOne, 0, str); return str; } /// <summary> /// 獲取指定文件夾下全部子目錄及文件函數 /// </summary> /// <param name="theDir">指定目錄</param> /// <param name="nLevel">默認起始值,調用時,通常爲0</param> /// <param name="Rn">用於迭加的傳入值,通常爲空</param> /// <returns></returns> public static string ListTreeShow(DirectoryInfo theDir, int nLevel, string Rn)//遞歸目錄 文件 { DirectoryInfo[] subDirectories = theDir.GetDirectories();//得到目錄 foreach (DirectoryInfo dirinfo in subDirectories) { if (nLevel == 0) { Rn += "├"; } else { string _s = ""; for (int i = 1; i <= nLevel; i++) { _s += "│ "; } Rn += _s + "├"; } Rn += "<b>" + dirinfo.Name.ToString() + "</b><br />"; FileInfo[] fileInfo = dirinfo.GetFiles(); //目錄下的文件 foreach (FileInfo fInfo in fileInfo) { if (nLevel == 0) { Rn += "│ ├"; } else { string _f = ""; for (int i = 1; i <= nLevel; i++) { _f += "│ "; } Rn += _f + "│ ├"; } Rn += fInfo.Name.ToString() + " <br />"; } Rn = ListTreeShow(dirinfo, nLevel + 1, Rn); } return Rn; } /**************************************** * 函數名稱:GetFoldAll(string Path) * 功能說明:獲取指定文件夾下全部子目錄及文件(下拉框形) * 參 數:Path:詳細路徑 * 調用示列: * string strDirlist = Server.MapPath("templates"); * this.Literal2.Text = DotNet.Utilities.FileOperate.GetFoldAll(strDirlist,"tpl",""); *****************************************/ /// <summary> /// 獲取指定文件夾下全部子目錄及文件(下拉框形) /// </summary> /// <param name="Path">詳細路徑</param> ///<param name="DropName">下拉列表名稱</param> ///<param name="tplPath">默認選擇模板名稱</param> public static string GetFoldAll(string Path, string DropName, string tplPath) { string strDrop = "<select name=\"" + DropName + "\" id=\"" + DropName + "\"><option value=\"\">--請選擇詳細模板--</option>"; string str = ""; DirectoryInfo thisOne = new DirectoryInfo(Path); str = ListTreeShow(thisOne, 0, str, tplPath); return strDrop + str + "</select>"; } /// <summary> /// 獲取指定文件夾下全部子目錄及文件函數 /// </summary> /// <param name="theDir">指定目錄</param> /// <param name="nLevel">默認起始值,調用時,通常爲0</param> /// <param name="Rn">用於迭加的傳入值,通常爲空</param> /// <param name="tplPath">默認選擇模板名稱</param> /// <returns></returns> public static string ListTreeShow(DirectoryInfo theDir, int nLevel, string Rn, string tplPath)//遞歸目錄 文件 { DirectoryInfo[] subDirectories = theDir.GetDirectories();//得到目錄 foreach (DirectoryInfo dirinfo in subDirectories) { Rn += "<option value=\"" + dirinfo.Name.ToString() + "\""; if (tplPath.ToLower() == dirinfo.Name.ToString().ToLower()) { Rn += " selected "; } Rn += ">"; if (nLevel == 0) { Rn += "┣"; } else { string _s = ""; for (int i = 1; i <= nLevel; i++) { _s += "│ "; } Rn += _s + "┣"; } Rn += "" + dirinfo.Name.ToString() + "</option>"; FileInfo[] fileInfo = dirinfo.GetFiles(); //目錄下的文件 foreach (FileInfo fInfo in fileInfo) { Rn += "<option value=\"" + dirinfo.Name.ToString() + "/" + fInfo.Name.ToString() + "\""; if (tplPath.ToLower() == fInfo.Name.ToString().ToLower()) { Rn += " selected "; } Rn += ">"; if (nLevel == 0) { Rn += "│ ├"; } else { string _f = ""; for (int i = 1; i <= nLevel; i++) { _f += "│ "; } Rn += _f + "│ ├"; } Rn += fInfo.Name.ToString() + "</option>"; } Rn = ListTreeShow(dirinfo, nLevel + 1, Rn, tplPath); } return Rn; } #endregion #region 獲取文件夾大小 /**************************************** * 函數名稱:GetDirectoryLength(string dirPath) * 功能說明:獲取文件夾大小 * 參 數:dirPath:文件夾詳細路徑 * 調用示列: * string Path = Server.MapPath("templates"); * Response.Write(DotNet.Utilities.FileOperate.GetDirectoryLength(Path)); *****************************************/ /// <summary> /// 獲取文件夾大小 /// </summary> /// <param name="dirPath">文件夾路徑</param> /// <returns></returns> public static long GetDirectoryLength(string dirPath) { if (!Directory.Exists(dirPath)) return 0; long len = 0; DirectoryInfo di = new DirectoryInfo(dirPath); foreach (FileInfo fi in di.GetFiles()) { len += fi.Length; } DirectoryInfo[] dis = di.GetDirectories(); if (dis.Length > 0) { for (int i = 0; i < dis.Length; i++) { len += GetDirectoryLength(dis[i].FullName); } } return len; } #endregion #region 獲取指定文件詳細屬性 /**************************************** * 函數名稱:GetFileAttibe(string filePath) * 功能說明:獲取指定文件詳細屬性 * 參 數:filePath:文件詳細路徑 * 調用示列: * string file = Server.MapPath("robots.txt"); * Response.Write(DotNet.Utilities.FileOperate.GetFileAttibe(file)); *****************************************/ /// <summary> /// 獲取指定文件詳細屬性 /// </summary> /// <param name="filePath">文件詳細路徑</param> /// <returns></returns> public static string GetFileAttibe(string filePath) { string str = ""; System.IO.FileInfo objFI = new System.IO.FileInfo(filePath); str += "詳細路徑:" + objFI.FullName + "<br>文件名稱:" + objFI.Name + "<br>文件長度:" + objFI.Length.ToString() + "字節<br>建立時間" + objFI.CreationTime.ToString() + "<br>最後訪問時間:" + objFI.LastAccessTime.ToString() + "<br>修改時間:" + objFI.LastWriteTime.ToString() + "<br>所在目錄:" + objFI.DirectoryName + "<br>擴展名:" + objFI.Extension; return str; } #endregion }
備註:此文章轉載自博主我的技術站點,博主我的站致力於分享相關技術文章,同時也分享Windows服務器和Linux服務器運維等知識:IT技術小趣屋。
異步多線程 Async
/// 耗時方法
/// </summary>
/// <param name="name"></param>
private void DoSomeThing(string name)
{
Console.WriteLine($"開始執行{name}, {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,{DateTime.Now}");
int num = 1;
for (int i = 0; i < 100000000; i++)
{
num++;
}
Thread.Sleep(1000);
Console.WriteLine($"結束執行{name}, {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,{DateTime.Now},{num}");
}
/// 同步方法 按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
Action<string> act = this.DoSomeThing;
for (int i = 0; i < 5; i++)
{
act.Invoke("button1_Click");
}
Console.WriteLine("計算以後幹什麼");
}
/// 異步方法
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
Action<string> act = this.DoSomeThing;
AsyncCallback asyncCallback = ar => Console.WriteLine("回調函數"); //回調函數
IAsyncResult result = null;
for (int i = 0; i < 5; i++)
{
result = act.BeginInvoke("button2_Click", asyncCallback, "小豬");
}
act.EndInvoke(result);
IAsyncResult iAsyncResult = atc.BeginInvoke("上傳文件", ar => Console.WriteLine("執行回調函數"), null);
int i = 1;
while (!iAsyncResult.IsCompleted)
{
if (i < 10)
{
Console.WriteLine($"文件上傳{i++ * 10}");
}
else
{
Console.WriteLine($"已完成99%....立刻結束");
}
Thread.Sleep(100);
}
Console.WriteLine("上傳完成");
.net 多線程 Thread ThreadPool Task
/// 耗時方法
/// </summary>
/// <param name="name"></param>
private void DoSomeThing(string name)
{
Console.WriteLine($"開始執行{name}, {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,{DateTime.Now}");
int num = 1;
for (int i = 0; i < 100000000; i++)
{
num++;
}
Thread.Sleep(1000);
Console.WriteLine($"結束執行{name}, {Thread.CurrentThread.ManagedThreadId.ToString("00")} ,{DateTime.Now},{num}");
}
Action callback = () => Console.WriteLine("這是回調函數");
/// 基於Thread封裝帶返回的
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="funcT"></param>
/// <returns></returns>
private Func<T> ThreadWithReturn<T>(Func<T> funcT)
{
T t = default(T);
ThreadStart startNew = new ThreadStart(()=> {
t = funcT.Invoke();
});
Thread thread = new Thread(startNew);
thread.Start();
return new Func<T>(()=>
{
thread.Join();
return t;
});
}
Func<int> func = this.ThreadWithReturn(() => 222);
Console.WriteLine( func.Invoke());
}
Thread.Sleep(2000);
this.DoSomeThing("ThreadPool");
mre.Set();//這個設置以後
});
mre.WaitOne();//當mre.Set以後,主線程就能夠等待子線程執行完成以後再執行
Console.WriteLine($"this is end ");
tasks.Add(taskFactory.ContinueWhenAny(tasks.ToArray(), t => { Console.WriteLine("執行一個任務後,執行,不卡界面"); }));
Task tack= taskFactory.StartNew(t => Console.WriteLine("新的一個任務"),"標識Token"); //設置標識
Console.WriteLine(tack.AsyncState.ToString());//獲取標識而且打印 tack.AsyncState
//int result = task.Result;
//Console.WriteLine(result);
.Net 反射學習
foreach (var item in assembly.GetModules()) //遍歷類庫的dll文件
{
Console.WriteLine(item.Name);
}
foreach (var item in assembly.GetTypes())//遍歷類庫的類型
{
Console.WriteLine(item.Name);
foreach (var act in item.GetMethods())//遍歷類的方法
{
Console.WriteLine(act.Name);
}
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show1");//無參方法
method.Invoke(ob1, null);
}
{
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show2", new Type[] { typeof(int) });//有一個參方法
method.Invoke(ob1, new object[] { 12 });
}
{
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show3", new Type[] { typeof(int), typeof(string) });//有兩個參方法
method.Invoke(ob1, new object[] { 12, "haha" });
}
{
//Type myType1 = assembly.GetType("WeiAi.DB.MysqlHelper.GenericMethod");
//object ob1 = Activator.CreateInstance(myType1);
//MethodInfo method = myType1.GetMethod("Show");
//MethodInfo methodNew= method.MakeGenericMethod(new Type[] { typeof(int),typeof(string),typeof(double) });
//methodNew.Invoke(ob1,new object[] { 12,"Jianghao",123456});
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show4");
MethodInfo methodNew = method.MakeGenericMethod(new Type[] { typeof(int) });//泛型方法
methodNew.Invoke(ob1, new object[] { 123123123 });
}
{
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show5");//靜態方法
method.Invoke(null, null);
}
{
object ob1 = Activator.CreateInstance(myType);
MethodInfo method = myType.GetMethod("Show6");//帶返回值的方法
object result = method.Invoke(ob1, null);
Console.WriteLine(result);
}