網站首頁 編程語言 正文
1、文件操作
這段代碼在?System.Private.CoreLib
?下,對 System.IO.File 中的代碼進行精簡,供 CLR 使用。
當使用文件時,要提前判斷文件路徑是否存在,日常項目中要使用到文件的地方應該不少,可以統一一個判斷文件是否存在的方法:
public static bool Exists(string? path) { try { // 可以將 string? 改成 string if (path == null) return false; if (path.Length == 0) return false; path = Path.GetFullPath(path); // After normalizing, check whether path ends in directory separator. // Otherwise, FillAttributeInfo removes it and we may return a false positive. // GetFullPath should never return null Debug.Assert(path != null, "File.Exists: GetFullPath returned null"); if (path.Length > 0 && PathInternal.IsDirectorySeparator(path[^1])) { return false; } return InternalExists(path); } catch (ArgumentException) { } catch (NotSupportedException) { } // Security can throw this on ":" catch (SecurityException) { } catch (IOException) { } catch (UnauthorizedAccessException) { } return false; }
建議項目中對路徑進行最終處理的時候,都轉換為絕對路徑:
Path.GetFullPath(path)
當然,相對路徑會被 .NET 正確識別,但是對于運維排查問題和各方面考慮,絕對路徑容易定位具體位置和排錯。
在編寫代碼時,使用相對路徑,不要寫死,提高靈活性;在運行階段將其轉為絕對路徑;
上面的?NotSupportedException
?等異常是操作文件中可能出現的各種異常情況,對于跨平臺應用來說,這些異常可能都是很常見的,提前將其異常類型識別處理,可以優化文件處理邏輯以及便于篩查處理錯誤。
2、讀取文件
這段代碼在 System.Private.CoreLib 中。
有個讀取文件轉換為 byte[] 的方法如下:
public static byte[] ReadAllBytes(string path) { // bufferSize == 1 used to avoid unnecessary buffer in FileStream using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1)) { long fileLength = fs.Length; if (fileLength > int.MaxValue) throw new IOException(SR.IO_FileTooLong2GB); int index = 0; int count = (int)fileLength; byte[] bytes = new byte[count]; while (count > 0) { int n = fs.Read(bytes, index, count); if (n == 0) throw Error.GetEndOfFile(); index += n; count -= n; } return bytes; } }
可以看到 FileStream 的使用,如果單純是讀取文件內容,可以參考里面的代碼:
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1)
上面的代碼同樣也存在?File.ReadAllBytes
?與之對應, File.ReadAllBytes 內部是使用?InternalReadAllBytes
?來處理文檔讀?。?/p>
private static byte[] InternalReadAllBytes(String path, bool checkHost) { byte[] bytes; // 此 FileStream 的構造函數不是 public ,開發者不能使用 using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, FileStream.DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, checkHost)) { // Do a blocking read int index = 0; long fileLength = fs.Length; if (fileLength > Int32.MaxValue) throw new IOException(Environment.GetResourceString("IO.IO_FileTooLong2GB")); int count = (int) fileLength; bytes = new byte[count]; while(count > 0) { int n = fs.Read(bytes, index, count); if (n == 0) __Error.EndOfFile(); index += n; count -= n; } } return bytes; }
這段說明我們可以放心使用?File
?靜態類中的函數,因為里面已經處理好一些邏輯了,并且自動釋放文件。
如果我們手動?new FileStream
?,則要判斷一些情況,以免使用時報錯,最好參考一下上面的代碼。
.NET 文件流緩存大小默認是?4096
?字節:
internal const int DefaultBufferSize = 4096;
這段代碼在 File 類中定義,開發者不能設置緩存塊的大小,大多數情況下,4k 是最優的塊大小。
ReadAllBytes 的文件大小上限是 2 GB。
3、Debug 、Trace類
這兩個類的命名空間為?System.Diagnostics
,Debug 、Trace 提供一組有助于調試代碼的方法和屬性。
Debug 中的所有函數都不會在 Release 中有效,并且所有輸出流不會在控制臺顯示,必須注冊偵聽器才能讀取這些流。
Debug 可以打印調試信息并使用斷言檢查邏輯,使代碼更可靠,而不會影響發運產品的性能和代碼大小。
這類輸出方法有 Write 、WriteLine 、 WriteIf 和 WriteLineIf 等,這里輸出不會直接打印到控制臺。
如需將調試信息打印到控制臺,可以注冊偵聽器:
ConsoleTraceListener console = new ConsoleTraceListener(); Trace.Listeners.Add(console);
注意, .NET Core 2.x 以上 Debug 沒有 Listeners ,因為 Debug 使用的是 Trace 的偵聽器。
我們可以給 Trace.Listeners 注冊偵聽器,這樣相對于?Debug
?等效設置偵聽器。
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); Debug.WriteLine("aa");
.NET Core 中的監聽器都繼承了 TraceListener,如 TextWriterTraceListener、ConsoleTraceListener、DefaultTraceListener。
如果需要輸出到文件中,可以自行繼承?TextWriterTraceListener
?,編寫文件流輸出,也可以使用 DelimitedListTraceListener。
示例:
TraceListener listener = new DelimitedListTraceListener(@"C:\debugfile.txt"); // Add listener. Debug.Listeners.Add(listener); // Write and flush. Debug.WriteLine("Welcome");
處理上述方法輸出控制臺,也可以使用
ConsoleTraceListener console=... ...Listeners.Add(console); // 等效于 var console = new TextWriterTraceListener(Console.Out)
為了格式化輸出流,可以使用 一下屬性控制排版:
屬性 | 說明 |
---|---|
AutoFlush | 獲取或設置一個值,通過該值指示每次寫入后是否應在 Flush() 上調用 Listeners。 |
IndentLevel | 獲取或設置縮進級別。 |
IndentSize | 獲取或設置縮進的空格數。 |
// 1. Debug.WriteLine("One"); // Indent and then unindent after writing. Debug.Indent(); Debug.WriteLine("Two"); Debug.WriteLine("Three"); Debug.Unindent(); // End. Debug.WriteLine("Four"); // Sleep. System.Threading.Thread.Sleep(10000);
One Two Three Four
.Assert()
?方法對我們調試程序很有幫助,Assert 向開發人員發送一個強消息。在 IDE 中,斷言會中斷程序的正常操作,但不會終止應用程序。
.Assert()
?的最直觀效果是輸出程序的斷言位置。
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); int value = -1; // A. // If value is ever -1, then a dialog will be shown. Debug.Assert(value != -1, "Value must never be -1."); // B. // If you want to only write a line, use WriteLineIf. Debug.WriteLineIf(value == -1, "Value is -1.");
---- DEBUG ASSERTION FAILED ---- ---- Assert Short Message ---- Value must never be -1. ---- Assert Long Message ---- at Program.Main(String[] args) in ...Program.cs:line 12 Value is -1.
Debug.Prinf()
?也可以輸出信息,它跟 C 語言的 printf 函數行為一致,將后跟行結束符的消息寫入,默認行終止符為回車符后跟一個換行符。
在 IDE 中運行程序時,使用?Debug.Assert()
、Trace.Assert()
?等方法 ,條件為 false 時,IDE 會斷言,這相當于條件斷點。
在非 IDE 環境下,程序會輸出一些信息,但不會有中斷效果。
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); Trace.Assert(false);
Process terminated. Assertion Failed at Program.Main(String[] args) in C:\ConsoleApp4\Program.cs:line 44
個人認為,可以將 Debug、Trace 引入項目中,與日志組件配合使用。Debug、Trace 用于記錄程序運行的診斷信息,便于日后排查程序問題;日志用于記錄業務過程,數據信息等。
.Assert()
?的原理, 在 true 時什么都不做;在 false 時調用 Fail 函數;如果你不注冊偵聽器的話,默認也沒事可做。
.Assert()
?唯一可做的事情是等條件為 false 時,執行 Fail 方法,當然我們也可以手動直接調用 Fail 方法,Fail 的代碼如下:
public static void Fail(string message) { if (UseGlobalLock) { lock (critSec) { foreach (TraceListener listener in Listeners) { listener.Fail(message); if (AutoFlush) listener.Flush(); } } } else { foreach (TraceListener listener in Listeners) { if (!listener.IsThreadSafe) { lock (listener) { listener.Fail(message); if (AutoFlush) listener.Flush(); } } else { listener.Fail(message); if (AutoFlush) listener.Flush(); } } } }
原文鏈接:https://www.cnblogs.com/whuanle/p/14141213.html
相關推薦
- 2022-06-27 ASP.net?Core微信平臺開發配置Token_實用技巧
- 2023-01-30 python多進程程序打包成exe的問題_python
- 2022-11-09 ORACLE中常用的幾種正則表達式小結_oracle
- 2022-07-08 Python基礎篇之字符串的最全常用操作方法匯總_python
- 2022-05-11 C#實現搶紅包算法的示例代碼_C#教程
- 2022-04-07 代碼詳解Python的函數基礎(1)_python
- 2022-09-14 Gstreamer基礎知識教程_C 語言
- 2022-09-30 C++?多態虛函數的底層原理深入理解_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支