locked
Windows Store中各种流的转换 RRS feed

  • 常规讨论

  • 在文章之前,我们先阐述一下流的概念,流最初的设计是为了避免冗余的IO交互,让流作为一个缓冲的介质。所以在C++中,流大概分三种:
    1. 与输入输出设备交互的流,比如键盘输入cin,和显示器输出cout
    2. 与磁盘文件交互的流,比如fstream
    3. 一块连续的内存区域,这里可以是字符串流,比如strstream


    而在.NET中,除了上述三种用途之外,流有一些更广泛的应用。
    常见的关于流的类如下
    Stream类:流的基类,定义流的基本操作。
    FileStream类:用于对文件执行读写操作,支持同步和异步读写。
    MemoryStream类:无缓存的流,该流以内存作为数据流。
    NetWorkStream类:以网络为数据源的流,可以通过此流发送或接收网络数据。
    TextReader类:StreamReader对象的抽象基类,定义基本字符读取操作。
    TextWriter类:StreamWriter对象的抽象基类,定义基本字符写入操作。
    StreamWriter类:向流写入字符。
    StreamReader类:实现从流读取字符操作。

    在.NET中访问流的方式,大概可以分两种:
    一种是直接赋值法,
                int numPixels = 300;
                byte[] pixels = new byte[numPixels];
                FileStream fs = new FileStream("temp.txt",
                                FileMode.Create, FileAccess.Write, FileShare.None,
                                numPixels, false);
    
                fs.Write(pixels, 0, pixels.Length);
                fs.Flush();
                fs.Close();
    另一种就是通过Reader或者Writer去操作这个流。
                BinaryReader binReader = new BinaryReader(File.Open("temp.txt", FileMode.Open));
                int a=binReader.ReadInt16();
    有了Reader之后,我们对于流的操作就会更有效一些,比如控制流的编码,读取特定位置的流,读取特定类型的流。

    在Windows Runtime中的流和.NET中的类似,但在使用上,由于文件访问机制的不同,有些地方还是不同的。

    举个例子,比如说我们要访问一个文件的流,在.NET中,直接初始化一个文件流,传入文件名称即可。但是在Windows Runtime中,我们要进行这几步。
    1. 得到这个文件的实例
    2. 用openasync的方法获取到一个内存流。
    3. 用Datareader或者Datawriter去操作这个内存流,当然你也可以选择直接通过readasync 或者writeasync的方法对内存流直接赋值。
    4. 一般来说reader需要的是IInputStream接口,这个可以从GetInputStreamAt获得,而writer需要的是IOutputStream接口,这个可以从GetOutputStreamAt获得。

    在Windows Runtime中,我们主要用这几个流的接口
    IInputStream
    IOutputStream
    IRandomAccessStream

    所以,.NET,WIN32 和Windows Runtime中的流转换,就是各自的基本的流类型,到这三大接口的互相转换。其转换的思想就是先找到用于转换的API,如果没有的话尝试通过直接赋值,或者通过Reader和Writer读取并创建新的目标流。

    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us


    2012年10月29日 5:17
    版主

全部回复

  • .NET里面的流和Windows Runtime 中的流互相转换

    .NET中的一些流比如FileStream,NetWorkStream在Windows Runtime不可用,但有替代的类。
    TextReader,TextWriter这些接口可以用Windows Runtime中的DataReader或者DataWriter替代,当然这些接口在Windows Runtime也可以使用。

    剩下的就是Stream到Windows Runtime的转换。

    WindowsRuntimeStreamExtensions,这个类提供了一些便捷的转换方法。

    Stream 转成IIputStream
    var inputstream=stream.AsInputStream();  
    Stream转成IOutputStream
    var outputstream=stream.AsOutputStream();  
    Stream转成 IRandomAccess:
    此处没有直接提供扩展方法,我们用Reader和Writer来做:
                IBuffer buffer = null;
                var inputstream = stream.AsInputStream();
                using (var dataReader = new DataReader(inputstream))
                {
                    await dataReader.LoadAsync((uint)stream.Length);
                    buffer = dataReader.DetachBuffer();
                }
                var randomAccessStream = new InMemoryRandomAccessStream();
                await randomAccessStream.WriteAsync(buffer);
    而Windows Runtime到.NET的Stream就简单多了
    stream = inputStream.AsStreamForRead();  
    stream = outputStream.AsStreamForWrite();  
    stream = randomAccess.AsStream();  



    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us


    2012年10月29日 5:20
    版主
  • COM中的流和Windows Runtime 中的流互相转换

    对于COM中的流IStream,在C++/CX中可以通过CreateStreamOverRandomAccessStreamCreateRandomAccessStreamOverStream 函数去转换IStream和IRandomAccess,其他的接口可以通过IRandomAccess转换。

    IRandomAccess到IStream
    ComPtr<IStream> stream ;
    
    HRESULT hr=CreateStreamOverRandomAccessStream(randomAccessStream, IID_PPV_ARGS(&stream));
    if (FAILED(hr)) 
    { 
    throw Platform::Exception::CreateException(hr); 
    }
    IStream到IRandomAccess
    Windows::Storage::Streams::IRandomAccessStream^ comRAS;
    IUnknown* p11 = reinterpret_cast<IUnknown *>(comRAS);
    
    static const GUID guidIRandomAccessStream = 
    { 0x905a0fe1, 0xbc53, 0x11df, { 0x8c, 0x49, 0x00, 0x1e, 0x4f, 0xc6, 0x86, 0xda } };
    
    hr = CreateRandomAccessStreamOverStream(stream.Get(), BSOS_DEFAULT, guidIRandomAccessStream, (void**)&p11);
    使用这两个函数时要记得把shcore.lib 引用到项目中去。

    对于Win32中其他的流,比如说文件流等,由于Windows Runtime的限制,很少被用到,这里就不详细说明了,如果是在需要转换的话,可以考虑用writer去一点点写,还有一个API可以直接读文件的流CreateRandomAccessStreamOnFile

    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us


    2012年10月29日 5:22
    版主
  • IBuffer 接口的转换

    IBuffer 这个接口与Windows Runtime中三大接口的转换直接调用ReadAsync或者WriteAsync即可。

                // IBuffer to IRandomAccess
                IBuffer buffer=null;
                InMemoryRandomAccessStream inStream = new InMemoryRandomAccessStream();
                await inStream.WriteAsync(buffer);
    
                // IRandomAccess to IBuffer
                await inStream.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None);
    和byte数组的转换可以通过WindowsRuntimeBufferExtensions 这个类来完成。
                // IBuffer to bytes
                byte[] bytes = WindowsRuntimeBufferExtensions.ToArray(buffer, 0, (int)buffer.Length);
    
                // bytes to IBuffer
                buffer = WindowsRuntimeBufferExtensions.AsBuffer(bytes, 0, bytes.Length);
    

    另外,如果只是想快捷的写入或读取文件,我们可以直接使用FileIO 这个类,通过流来操作文件里面的内容。

    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us


    2012年10月29日 5:24
    版主