首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 主控台應用程式處理 Ctrl+Z 輸入結束的正確做法

     編輯:關於C#

前言

在撰寫 C# 主控台應用程式時,常見需求是讓使用者從鍵盤輸入多行文字,並以 Ctrl+Z(Windows 系統下的 EOF,End-Of-File 標記)作為輸入結束的信號。然而,ConsoleKey 列舉中並沒有直接對應 Ctrl 鍵的值,導致許多開發者不知道如何正確偵測 Ctrl+Z。本文將分享透過 單步偵錯 觀察 ConsoleKeyInfo.KeyChar 數值,並利用 ASCII 控制字元 0x1A (十進位 26) 來精準判斷 Ctrl+Z 的完整解決方案,並附上模擬 DOS COPY CON 指令的完整範例程式碼。

核心觀念:ConsoleKeyInfo.KeyChar 的秘密

  • Console.ReadKey() 回傳 ConsoleKeyInfo 結構,包含 Key(ConsoleKey 列舉)、KeyChar(實際字元)、Modifiers(Shift/Alt/Ctrl 修飾鍵)。
  • ConsoleKey 列舉沒有 Ctrl 鍵,但 Ctrl+Z 產生的 KeyChar 為 ASCII SUB (Substitute, 0x1A / 十進位 26)。
  • 因此,判斷條件可寫為:(int)cki.KeyChar == 26 或 cki.KeyChar == '\u001A'。

完整範例:模擬 DOS COPY CON 指令

以下程式碼實作一個 DOSCopyCon 類別,支援:

  1. copy con filename.txt:從主控台讀取輸入,直到 Ctrl+Z 或 End 鍵,寫入檔案。
  2. copy filename.txt con:讀取檔案內容輸出到主控台。
  3. 指令解析、錯誤處理、資源釋放(StreamWriter/StreamReader)。
using System;
using System.IO;

namespace ConsoleCopyConDemo
{
    /// 
    /// 模擬 DOS COPY CON 指令行為
    /// 
    public class DOSCopyCon
    {
        private string _inputCommandText = "";

        public DOSCopyCon(string inputCommandText = "")
        {
            _inputCommandText = inputCommandText;
        }

        public string InputCommandText
        {
            get => _inputCommandText;
            set
            {
                if (!string.IsNullOrWhiteSpace(value))
                    _inputCommandText = value;
            }
        }

        /// 
        /// 執行 COPY CON 指令
        /// 
        public void ExecuteCopyConCommand(string inputCommandText = null)
        {
            if (!string.IsNullOrWhiteSpace(inputCommandText))
                _inputCommandText = inputCommandText;

            if (string.IsNullOrWhiteSpace(_inputCommandText))
            {
                Console.WriteLine("** 指令不可為空 **");
                return;
            }

            DoCopyCon();
        }

        private void DoCopyCon()
        {
            // 解析指令:copy con file.txt  或  copy file.txt con
            var parts = _inputCommandText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            if (parts.Length != 3 || !parts[0].Equals("copy", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("指令格式錯誤!用法:copy con <檔名> 或 copy <檔名> con");
                return;
            }

            // 情況 1:copy con <檔名>  → 從主控台輸入寫入檔案
            if (parts[1].Equals("con", StringComparison.OrdinalIgnoreCase))
            {
                string targetFile = parts[2];
                Console.WriteLine($"開始寫入檔案 {targetFile} (按 Ctrl+Z 或 End 結束):");

                string inputText = "";
                ConsoleKeyInfo cki;

                while (true)
                {
                    cki = Console.ReadKey(true); // true = 不顯示輸入字元

                    // 偵測 Ctrl+Z (ASCII 26) 或 End 鍵
                    if (cki.Key == ConsoleKey.End || (int)cki.KeyChar == 26)
                        break;

                    // 處理 Backspace
                    if (cki.Key == ConsoleKey.Backspace && inputText.Length > 0)
                    {
                        inputText = inputText.Substring(0, inputText.Length - 1);
                        Console.Write("\b \b"); // 視覺上刪除一字元
                        continue;
                    }

                    // 忽略其他控制字元(如 Ctrl+C 等)
                    if (!char.IsControl(cki.KeyChar))
                        inputText += cki.KeyChar;
                }

                try
                {
                    File.WriteAllText(targetFile, inputText);
                    Console.WriteLine($"\n寫入檔案 {targetFile} 成功。");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\n寫入失敗:{ex.Message}");
                }
                return;
            }

            // 情況 2:copy <檔名> con  → 讀取檔案輸出到主控台
            if (parts[2].Equals("con", StringComparison.OrdinalIgnoreCase))
            {
                string sourceFile = parts[1];
                Console.WriteLine($"開始讀取檔案 {sourceFile}:");
                try
                {
                    string content = File.ReadAllText(sourceFile);
                    Console.WriteLine(content);
                    Console.WriteLine("讀取完成。");
                }
                catch (FileNotFoundException)
                {
                    Console.WriteLine($"找不到檔案:{sourceFile}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"讀取失敗:{ex.Message}");
                }
                return;
            }

            Console.WriteLine("不支援的指令格式。");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("=== DOS COPY CON 模擬器 ===");
            Console.WriteLine("指令範例:");
            Console.WriteLine("  copy con test.txt   (輸入文字,Ctrl+Z 結束)");
            Console.WriteLine("  copy test.txt con   (顯示檔案內容)");
            Console.WriteLine();

            var app = new DOSCopyCon();

            while (true)
            {
                Console.Write("\n> ");
                string cmd = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(cmd)) continue;
                if (cmd.Equals("exit", StringComparison.OrdinalIgnoreCase)) break;

                app.ExecuteCopyConCommand(cmd);
            }
        }
    }
}

關鍵程式碼解析

1. 偵測 Ctrl+Z 的核心邏輯

cki = Console.ReadKey(true); // true = 不在螢幕顯示字元
if (cki.Key == ConsoleKey.End || (int)cki.KeyChar == 26)
    break;
  • Console.ReadKey(true) 讓按鍵不自動回顯,適合自行處理 Backspace 等編輯鍵。
  • (int)cki.KeyChar == 26 精準捕捉 Ctrl+Z(ASCII SUB 字元)。
  • 同時支援 End 鍵作為替代結束方式,提升使用者體驗。

2. Backspace 處理技巧

if (cki.Key == ConsoleKey.Backspace && inputText.Length > 0)
{
    inputText = inputText.Substring(0, inputText.Length - 1);
    Console.Write("\b \b"); // 移動游標左、覆寫空白、再移回
    continue;
}

讓使用者在輸入過程中能刪除錯誤字元,體驗更接近真實編輯器。

3. 使用 File.WriteAllText / ReadAllText 簡化 IO

.NET Framework 2.0+ 內建靜態方法,自動處理 StreamWriter/StreamReader 的建立與關閉,程式碼更簡潔安全。

常見誤區與補充

誤區正確做法
嘗試用 cki.Key == ConsoleKey.Z && cki.Modifiers.HasFlag(ConsoleModifiers.Control)ConsoleKey 無 Ctrl,Modifiers 只能偵測 Shift/Alt,無法偵測 Ctrl 組合鍵
使用 Console.ReadLine() 讀取多行ReadLine 遇到 Enter 就回傳,無法處理 Ctrl+Z 作為 EOF
直接比較 cki.KeyChar == (char)26雖然可行,但建議寫成 (int)cki.KeyChar == 26 或 '\u001A' 以提升可讀性

總結

在 C# 主控台應用程式中處理 Ctrl+Z,關鍵在於理解 ConsoleKeyInfo.KeyChar 會回傳 ASCII 控制字元 26 (0x1A)。透過單步偵錯觀察實際數值,配合 Console.ReadKey(true) 自行處理回顯與編輯鍵,即可實作出健全的多行輸入功能。本文提供的 DOSCopyCon 完整範例已包含指令解析、輸入編輯、檔案讀寫與錯誤處理,可直接套用於實務專案中。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved