日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C#文件操作、讀取文件、Debug/Trace類用法_C#教程

作者:癡者工良 ? 更新時間: 2022-06-01 編程語言

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

欄目分類
最近更新