• 在.NET中使用管道将输出流转换为输入流


    最近在写一段代码,将本地文件压缩加密后发送到服务器,发送到服务器的类用一个输入流作为参数获取要上传的数据,而压缩类和加密类都是输出流。

    如何将输出流转换为输入流,最直观的方法是缓存输出流的全部内容到内存或文件中,但是当数据变大的时候,这两种方法显然都不太合适。

    通过使用管道,可以将一个输出流转换为输入流。管道是一个操作系统功能,由一个循环缓存区构成,用于进程间通信,将一个进程的输出做为另一个进程的输入,Linux命令行脚本大量的用到管道通信,Windows同样也支持管道。.net对管道有封装的类,使用管道,在两个线程间通信,将一个进程的输出传递到另一个进程作为输入,.net中管道类继承自Stream类,可以将输出流无缝衔接到输入流。

    参照AnonymousPipeClientStream类和AnonymousPipeServerStream类的文档,将进程间通信改为线程间通信,就实现了在一个应用程序中将输出类转换为输入类的功能,代码如下:

     1         [TestMethod]
     2         public void OutputStream2InputStreamUsingPipe()
     3         {
     4             int iStreamSize = 128 * 1024;
     5 
     6             var t = new Thread((data) =>
     7                 {
     8                     using (var pipe = new AnonymousPipeClientStream(
     9                         PipeDirection.Out, (string)data))
    10                     {
    11                         for (var i = 0; i < iStreamSize; i++)
    12                             pipe.WriteByte((byte)'A');
    13                     }
    14                 });
    15 
    16             using (var ms = new MemoryStream())
    17             {
    18                 using (var pipe = new AnonymousPipeServerStream(
    19                     PipeDirection.In, HandleInheritability.Inheritable))
    20                 {
    21                     t.Start(pipe.GetClientHandleAsString());
    22                     var buffer = new byte[8 * 1024];
    23                     int len;
    24                     while ((len = pipe.Read(buffer, 0, buffer.Length)) > 0)
    25                     {
    26                         Thread.Sleep(100);
    27                         ms.Write(buffer, 0, len);
    28                     }
    29                 }
    30                 t.Join();
    31                 Assert.AreEqual(iStreamSize, ms.Length);
    32             }
    33         }

    在上述代码中在一个新建线程中向管道的一端写入数据,在主线程中从管道的另一端读取数据。如果写入前和读取后都需要对数据进行处理的话,若能将数据处理工作分配到两个线程上,既解决了流转换的问题,而且如果数据处理工作占用CPU很多的话双线程带来的效率提升不仅会抵消掉使用管道带来的开销,还能进一步提升整体效率,一举两得。

    代码中Thread.Sleep(100)明确地使管道的写入和读取不同步,以验证管道的功能:当读取线程进入Sleep状态时,管道缓冲区被写满(windows和linux下缓存区可能都是一个内存页4K),写入操作被阻塞。

  • 相关阅读:
    window.open 打开全屏窗口
    H5实现全屏与F11全屏
    泛型 总结
    java 反射
    静态工厂模式
    设计模式---单例模式
    String、List、array相互转换
    将数组转换成list
    将对象转换成json字符串的几种方式
    在map中放入数据时,如果key相同,会替换掉之前的相同key的数据
  • 原文地址:https://www.cnblogs.com/ioexception/p/dotnet_convert_output_stream_to_input_stream_using_pipe.html
Copyright © 2020-2023  润新知