C# 从控制台C上的位置读取#
我需要从控制台中的特定位置读取文本,例如5,5 如果我需要写信到这个位置,它只会是:C# 从控制台C上的位置读取#,c#,console,C#,Console,我需要从控制台中的特定位置读取文本,例如5,5 如果我需要写信到这个位置,它只会是: Console.SetCursorPosition(5, 5); Console.Write("My text"); 有没有什么方法可以让我以类似的方式阅读 我想澄清一下: 我不想停下来接受用户的输入,即使输入不是来自用户,也有可能是以前打印出来的。我真的想要一些: Console.GetCharAtLocation(5,5)或类似功能。此功能不存在。从理论上讲,您可以覆盖控制台上的输入和输出流,以保留您自己
Console.SetCursorPosition(5, 5);
Console.Write("My text");
有没有什么方法可以让我以类似的方式阅读
我想澄清一下:
我不想停下来接受用户的输入,即使输入不是来自用户,也有可能是以前打印出来的。我真的想要一些:
Console.GetCharAtLocation(5,5)或类似功能。此功能不存在。从理论上讲,您可以覆盖控制台上的输入和输出流,以保留您自己可以读取的控制台缓冲区副本,但这并不简单(并且可能不支持所有边缘情况,例如外部程序挂接到控制台并对其进行读写).此功能不存在。从理论上讲,您可以覆盖控制台上的输入和输出流,以保留您自己可以读取的控制台缓冲区副本,但这并不简单(并且可能无法支持所有边缘情况,例如外部程序挂接到控制台并对其进行读写)。关于:
class Program {
static void Main( string[ ] args ) {
CustomizedConsole.WriteLine( "Lorem Ipsum" ); //Lorem Ipsum
Console.WriteLine( CustomizedConsole.ReadContent( 6, 5 ) ); //Ipsum
Console.WriteLine( CustomizedConsole.GetCharAtLocation( 0, 0 ) ); //L
}
}
static class CustomizedConsole {
private static List<char> buffer = new List<char>();
private static int lineCharCount = 0;
public static void Write(string s){
lineCharCount += s.Length;
buffer.AddRange( s );
Console.Write( s );
}
public static void WriteLine(string s ) {
for ( int i = 0; i < Console.BufferWidth - lineCharCount - s.Length; i++ )
s += " ";
buffer.AddRange( s );
Console.WriteLine( s );
lineCharCount = 0;
}
public static string ReadContent( int index, int count ) {
return new String(buffer.Skip( index ).Take( count ).ToArray());
}
public static char GetCharAtLocation( int x, int y ) {
return buffer[ Console.BufferHeight * x + y ];
}
}
类程序{
静态void Main(字符串[]参数){
CustomizedConsole.WriteLine(“Lorem Ipsum”);//Lorem Ipsum
Console.WriteLine(CustomizedConsole.ReadContent(6,5));//Ipsum
Console.WriteLine(CustomizedConsole.GetCharAtLocation(0,0));//L
}
}
静态类定制控制台{
私有静态列表缓冲区=新列表();
私有静态int-lineCharCount=0;
公共静态无效写入(字符串s){
lineCharCount+=s.长度;
缓冲区。添加范围;
控制台。写入;
}
公共静态无效写线(字符串s){
对于(int i=0;i
编辑:
正如其他人所说,这只是一个微不足道的案例,还有很多其他方面需要改进。但我写这篇文章只是作为一个起点。关于:
class Program {
static void Main( string[ ] args ) {
CustomizedConsole.WriteLine( "Lorem Ipsum" ); //Lorem Ipsum
Console.WriteLine( CustomizedConsole.ReadContent( 6, 5 ) ); //Ipsum
Console.WriteLine( CustomizedConsole.GetCharAtLocation( 0, 0 ) ); //L
}
}
static class CustomizedConsole {
private static List<char> buffer = new List<char>();
private static int lineCharCount = 0;
public static void Write(string s){
lineCharCount += s.Length;
buffer.AddRange( s );
Console.Write( s );
}
public static void WriteLine(string s ) {
for ( int i = 0; i < Console.BufferWidth - lineCharCount - s.Length; i++ )
s += " ";
buffer.AddRange( s );
Console.WriteLine( s );
lineCharCount = 0;
}
public static string ReadContent( int index, int count ) {
return new String(buffer.Skip( index ).Take( count ).ToArray());
}
public static char GetCharAtLocation( int x, int y ) {
return buffer[ Console.BufferHeight * x + y ];
}
}
类程序{
静态void Main(字符串[]参数){
CustomizedConsole.WriteLine(“Lorem Ipsum”);//Lorem Ipsum
Console.WriteLine(CustomizedConsole.ReadContent(6,5));//Ipsum
Console.WriteLine(CustomizedConsole.GetCharAtLocation(0,0));//L
}
}
静态类定制控制台{
私有静态列表缓冲区=新列表();
私有静态int-lineCharCount=0;
公共静态无效写入(字符串s){
lineCharCount+=s.长度;
缓冲区。添加范围;
控制台。写入;
}
公共静态无效写线(字符串s){
对于(int i=0;i
编辑:
正如其他人所说,这只是一个微不足道的案例,还有很多其他方面需要改进。但我写这篇文章只是作为一个起点。正如@Servy所说,没有任何内置功能(我知道或可以找到)可以做你想要的。然而,有一个解决办法(这是一个有点黑客,但它的工作) 您可以在内存或磁盘上创建自己的缓冲区。无论何时输出到控制台,也要输出到缓冲区。然后,您可以使用缓冲区以控制台无法使用的方式进行读取 缓冲区有两种方式:在磁盘上或在内存中。您可以使用
Console.BufferWidth
和Console.BufferHeight
属性来查找缓冲区大小。我发现在内存中使用字符串数组更简单(每个字符串都是一行输出,如果我没记错的话,数组中有许多字符串等于缓冲区高度
)。一位同事最后在磁盘上做了同样的事情
您需要创建一个方法来替换Console.Write
和Console.WriteLine
,以便可以同时写入两个缓冲区。比如:
public void MyWrite( string output ) {
Console.Write( output );
Array.Write( output ); // obvious pseudo-code
}
我发现围绕数组包装一个类并实现支持它的方法很有帮助。。。然后,您可以实现您的
GetCharAtLocation(inti,intj)
方法,以及您需要的任何其他功能。正如@Servy所述,没有任何内置功能(我知道或可以找到)可以实现您想要的功能。然而,有一个解决办法(这是一个有点黑客,但它的工作)
您可以在内存或磁盘上创建自己的缓冲区。无论何时输出到控制台,也要输出到缓冲区。然后,您可以使用缓冲区以控制台无法使用的方式进行读取
缓冲区有两种方式:在磁盘上或在内存中。您可以使用Console.BufferWidth
和Console.BufferHeight
属性来查找缓冲区大小。我发现在内存中使用字符串数组更简单(每个字符串都是一行输出,如果我没记错的话,数组中有许多字符串等于缓冲区高度
)。一位同事最后在磁盘上做了同样的事情
您需要创建一个方法来替换Console.Write
和Console.WriteL
public class ConsoleReader
{
public static IEnumerable<string> ReadFromBuffer(short x, short y, short width, short height)
{
IntPtr buffer = Marshal.AllocHGlobal(width * height * Marshal.SizeOf(typeof(CHAR_INFO)));
if (buffer == null)
throw new OutOfMemoryException();
try
{
COORD coord = new COORD();
SMALL_RECT rc = new SMALL_RECT();
rc.Left = x;
rc.Top = y;
rc.Right = (short)(x + width - 1);
rc.Bottom = (short)(y + height - 1);
COORD size = new COORD();
size.X = width;
size.Y = height;
const int STD_OUTPUT_HANDLE = -11;
if (!ReadConsoleOutput(GetStdHandle(STD_OUTPUT_HANDLE), buffer, size, coord, ref rc))
{
// 'Not enough storage is available to process this command' may be raised for buffer size > 64K (see ReadConsoleOutput doc.)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
IntPtr ptr = buffer;
for (int h = 0; h < height; h++)
{
StringBuilder sb = new StringBuilder();
for (int w = 0; w < width; w++)
{
CHAR_INFO ci = (CHAR_INFO)Marshal.PtrToStructure(ptr, typeof(CHAR_INFO));
char[] chars = Console.OutputEncoding.GetChars(ci.charData);
sb.Append(chars[0]);
ptr += Marshal.SizeOf(typeof(CHAR_INFO));
}
yield return sb.ToString();
}
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
[StructLayout(LayoutKind.Sequential)]
private struct CHAR_INFO
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] charData;
public short attributes;
}
[StructLayout(LayoutKind.Sequential)]
private struct COORD
{
public short X;
public short Y;
}
[StructLayout(LayoutKind.Sequential)]
private struct SMALL_RECT
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct CONSOLE_SCREEN_BUFFER_INFO
{
public COORD dwSize;
public COORD dwCursorPosition;
public short wAttributes;
public SMALL_RECT srWindow;
public COORD dwMaximumWindowSize;
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool ReadConsoleOutput(IntPtr hConsoleOutput, IntPtr lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, ref SMALL_RECT lpReadRegion);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(int nStdHandle);
}
static void Populate_Console()
{
Console.Clear();
Console.Write(@"
┌───────┐
1│C D E F│
2│G H I J│
3│K L M N│
4│O P Q R│
└───────┘
2 4 6 8 ".Trim());
}
[DllImport("kernel32", SetLastError = true)]
static extern IntPtr GetStdHandle(int num);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.Bool)] // ̲┌──────────────────^
static extern bool ReadConsoleOutputCharacterA(
IntPtr hStdout, // result of 'GetStdHandle(-11)'
out byte ch, // A̲N̲S̲I̲ character result
uint c_in, // (set to '1')
uint coord_XY, // screen location to read, X:loword, Y:hiword
out uint c_out); // (unwanted, discard)
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)] // ̲┌───────────────────^
static extern bool ReadConsoleOutputCharacterW(
IntPtr hStdout, // result of 'GetStdHandle(-11)'
out Char ch, // U̲n̲i̲c̲o̲d̲e̲ character result
uint c_in, // (set to '1')
uint coord_XY, // screen location to read, X:loword, Y:hiword
out uint c_out); // (unwanted, discard)
static void Windows_Console_Readback()
{
var stdout = GetStdHandle(-11);
for (uint coord, y = 1; y <= 4; y++)
{
coord = (5 - y) * 2; // loword <-- X coord to read
coord |= y << 16; // hiword <-- Y coord to read
if (!ReadConsoleOutputCharacterA(
stdout,
out byte chAnsi, // result: single ANSI char
1, // # of chars to read
coord, // (X,Y) screen location to read (see above)
out _)) // result: actual # of chars (unwanted)
throw new Win32Exception();
Console.Write(" " + (Char)chAnsi + " ");
}
}