【问题标题】:Redirect console output to readable memory not to file?将控制台输出重定向到可读内存而不是文件?
【发布时间】:2014-07-31 15:39:09
【问题描述】:

我使用此代码将控制台输出重定向到文件,然后读取并显示它。我想停止使用文件,因为我用这些控制台文件污染了我的文件夹。我怎样才能在内存中做到这一点?我不希望任何文件污染系统。也许我在这里尝试一些奇怪的东西。 我只想让 1 个线程读取同一应用程序的控制台输出

  • 1 个应用程序
  • 多线程写入控制台
  • 1 线程从控制台读取

我的工作文件代码:

private StreamWriter currentOut = null;

private void RedirectConsole()
{
    currentOut = new StreamWriter(new FileStream(filename,
        FileMode.Create, FileAccess.Write, FileShare.Read));
    currentOut.AutoFlush = true;
    Console.SetOut(currentOut);
    ThreadPool.QueueUserWorkItem(o => { Listen(); });
}

private void Listen()
{
    StreamReader fileIn = new StreamReader(new FileStream(filename,
        FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
    while (true)
    {
        try
        {
            if (!fileIn.EndOfStream)
            {
                string a = fileIn.ReadLine();
                MessageBox.Show(a);
            }
            Thread.Sleep(25);
        }
        catch { }
    }
}

This 似乎是我想要的。但我无法实现这一点(帮助?)。文件就像一个缓冲区。您从一端写入并从另一端读取。我需要同样的记忆。

【问题讨论】:

  • 您是否每次都创建一个新文件?您可以只使用一个文件并在程序关闭时将其清除吗?我不知道将其重定向到另一个线程,但您似乎至少不需要“污染”您的文件夹。
  • @eddie_cat 是的,每次启动应用程序时我都会打开一个新文件。对于多实例,我每次都选择一个新文件名。例如,当应用程序崩溃时,文件将保留。我认为寻找要删除的文件或其他什么是一个糟糕的解决方案。
  • 如果您希望在应用崩溃时保留文件,您唯一的选择可能是将其写入文件。
  • @Joshpbarron 不,我不想要任何文件。

标签: c# multithreading file memory console


【解决方案1】:

试试:

private StreamWriter currentOut = null;
private MemoryStream ms = new MemoryStream();

private void RedirectConsole()
{
    currentOut = new StreamWriter(ms);
    currentOut.AutoFlush = true;
    Console.SetOut(currentOut);
    ThreadPool.QueueUserWorkItem(o => { Listen(); });
}

private void Listen()
{
    StreamReader fileIn = new StreamReader(ms);
    // ...
}

【讨论】:

  • 我也试过了。但我在我的读者线程上没有得到任何东西。也许缺少缓冲区或其他什么?
  • 对我也不起作用。不知道为什么。你真的试过了吗? Here 是我的解决方案,完全符合我的要求。
  • 这是对我过去所做的一些有效的事情的总结。很高兴您找到了可行的解决方案。
【解决方案2】:

使用 MemoryStream 的问题是读取位置随着写入位置而前进。管道(System.IO.Pipes 命名空间)是用作临时缓冲区的更好选择,其中读取位置需要独立于写入位置而前进。诚然,这或多或少与您的工作解决方案完全一样,尽管它消除了您自己实现缓冲区的需要。

class ConsoleRedirector : IDisposable
{
    private TextWriter originalOut = Console.Out;
    private AnonymousPipeServerStream consoleOutServerPipe;
    private StreamWriter currentOut;

    public ConsoleRedirector()
    {
        this.consoleOutServerPipe = new AnonymousPipeServerStream(PipeDirection.Out);
        this.currentOut = new StreamWriter(this.consoleOutServerPipe);
        this.currentOut.AutoFlush = true;
        Console.SetOut(this.currentOut);
        ThreadPool.QueueUserWorkItem(o => { this.Listen(); });
    }

    private void Listen()
    {
        AnonymousPipeClientStream consoleOutClientPipe = new AnonymousPipeClientStream(PipeDirection.In, this.consoleOutServerPipe.ClientSafePipeHandle);
        using (StreamReader fileIn = new StreamReader(consoleOutClientPipe))
        {
            // ...
        }
    }

    public void Dispose()
    {
        this.currentOut.Dispose();
        Console.SetOut(this.originalOut);
    }
}

【讨论】:

  • 仅供参考,看起来 System.IO.Pipes 命名空间是在 .NET 3.5 中添加的,因此如果您受限于 .NET 3.0 或更低版本,这将不起作用。
【解决方案3】:

我最终编写了一个派生流类并将FileStream 替换为我自己的流。我可能应该避免这种情况。但由于我找不到工作解决方案,这也是一个很好的做法。像这样的:

public class MyStream: Stream
{
    private byte[] internalBuffer = new byte[4096];

    // ...

    public override int Read(byte[] buffer, int offset, int count)
    {
        // used by StreamReader
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        // used by StreamWriter
    }
}

override 所有其他东西,处理多线程,同时扩大internalBuffer 并处理传递的数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-28
    • 2023-03-19
    • 2021-10-21
    • 2013-12-07
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 2013-04-27
    相关资源
    最近更新 更多