实现IRandomAccessStream,不复制缓冲区



我有点困惑,在ReadAsync()实现(win8.1的通用存储应用程序)中我应该如何处理targetBuffer

public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer targetBuffer, uint count, InputStreamOptions options)

问题是,我找不到一种方法来写targetBuffer,并根据我的具体实现要求改变它的Length

我在里面有一个加密流与一些块密码。我想包装它与IRandomAccessStream,所以它可以使用xaml框架组件(,如传递加密图像/视频到ImageMediaElement对象)。在类中,我有一个字节数组,我为每个块重用,将其传递给加密库,加密库填充它并报告块大小。

所以,当IRandomAccessStream.ReadAsync()被调用时,我需要以某种方式将我的字节放入targetBuffer并将其Length设置为适当的值…但我似乎做不到。

我试过了:

var stream = targetBuffer.AsStream();
while(count > 0) {
  /* doing something to get next chunk of data decrypted */
  // byte[] chunk is the array used to hold decrypted data
  // int chunkLength is the length of data (<= chunk.Length)
  count -= chunkLength;
  await stream.WriteAsync(chunk, 0, chunkLength);
}
return targetBuffer;

targetBuffer.Length仍然为零,但如果我试图打印其内容,数据就在那里!

Debug.WriteLine(targetBuffer.GetByte(0..N)); 

我现在有一个naïve实现,它使用内存流(除了字节数组缓冲区),在那里收集数据并从它读回targetBuffer。这种方法有效,但看起来很糟糕。托管流写入byte[]和WinRT流写入IBuffer,我只是找不到一种方法,这样我就不会浪费内存和性能。

我很感激你的建议。

这是它现在的样子。我最终使用字节数组作为解密缓冲区,并使用可调整大小的内存流作为代理。

public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer targetBuffer, uint count, InputStreamOptions options)
{
  return AsyncInfo.Run<IBuffer, uint>(async (token, progress) => {
    Transport.Seek(0); // Transport is InMemoryRandomAccessStream
    var remaining = count;
    while(remaining > 0) {    
      /*
      ReadAsync() overload reads & decrypts data, 
      result length is <= remaining bytes,
      deals with block cipher alignment and the like
      */
      IBuffer chunk = await ReadAsync(remaining); 
      await Transport.WriteAsync(chunk);
      remaining -= chunk.Length;
    }
    Transport.Seek(0);
    // copy resulting bytes to target buffer
    await Transport.ReadAsync(targetBuffer, count, InputStreamOptions.None);
    return targetBuffer;
  });
}

UPDATE:我用7.9Mb的加密图像测试了上面的解决方案。我把它提供给Image实例,像这样:

var image = new BitmapImage();
await image.SetSourceAsync(myCustomStream);
Img.Source = image; // Img is <Image> in xaml

一切正常,直到执行达到await Transport.ReadAsync(targetBuffer, count, InputStreamOptions.None);:那里的内存消耗飙升(从大约33mb到300+mb),这有效地崩溃了手机模拟器(桌面版本显示图像正常,尽管内存消耗相同)。这到底是怎么回事?!

2017年3月解决

首先,我不知怎么地没有意识到我可以在将数据写入缓冲区后直接设置Length。其次,如果你在我的例子中做错了什么(自定义IRandomAccessStream实现是XAML Image元素的来源),应用程序崩溃,不留下任何日志,也不显示任何错误,所以很难找出哪里出了问题。

代码现在是这样的:

public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer targetBuffer, uint count, InputStreamOptions options)
{
    return AsyncInfo.Run<IBuffer, uint>(async (token, progress) => {
        var output = targetBuffer.AsStream();
        while (count > 0) {
            //
            // do all the decryption stuff and get decrypted data
            // to a reusable buffer byte array
            //
            int bytes = Math.Min((int) count, BufferLength - BufferPosition);
            output.Write(decrypted, bufferPosition, bytes);
            targetBuffer.Length += (uint)bytes;
            BufferPosition += bytes;
            progress.Report((uint)bytes);
            count -= (uint)bytes;
        }
    }
    return targetBuffer;
});

using System.Runtime.InteropServices.WindowsRuntime;

(your byte array).CopyTo(targetBuffer);

IBuffer中的Length属性有一个setter

以下代码是完全有效的

targetBuffer.Length = (your integer here)

您有更多的CopyTo变体可供选择。看看这个:

public static void CopyTo(this byte[] source, int sourceIndex, IBuffer destination, uint destinationIndex, int count);

相关内容

  • 没有找到相关文章

最新更新