安全地访问MemoryStream中的数据

时间:2012-09-06 16:40:47

标签: c# bytearray memorystream

假设我有一个MemoryStream和一个按字节操作的函数。

目前的代码是这样的:

void caller()
{
    MemoryStream ms = // not important
    func(ms.GetBuffer(), 0, (int)ms.Length);
}

void func(byte[] buffer, int offset, int length)
{
    // not important
}

我无法更改func,但我希望尽量减少在func内更改流数据的可能性。

我怎样才能/应该重写代码以确保不会更改流数据?

或者这不能做到?

编辑:

对不起,我没有提到我想不复制数据。

5 个答案:

答案 0 :(得分:5)

致电.ToArray

func(ms.GetBuffer().ToArray(), 0, (int)ms.Length);

来自MSDN(强调我的):

  

请注意,缓冲区包含可能未使用的已分配字节。   例如,如果字符串“test”被写入MemoryStream   对象,从GetBuffer返回的缓冲区的长度是256,而不是   4,未使用252字节。 要仅获取缓冲区中的数据,请使用   ToArray方法;但是,ToArray会在其中创建数据的副本   存储器


理想情况下,您可以将func更改为IEnumerable<byte>。一旦方法具有数组,您就相信如果您不希望它们,则不会修改数据。如果合同 提供IEnumerable<byte>,则实施者必须决定是否需要副本进行编辑。

答案 1 :(得分:3)

如果您无法复制(ToArray,如其他答案所示)并且无法更改func函数的签名,则唯一剩下的就是尝试验证该函数是否未更改数据。

您可以在通话之前/之后计算某种哈希值并检查它是否相同。它不能保证func没有改变底层数据(由于哈希冲突),但至少会给你很好的机会来知道它是否发生。可能对非生产代码很有用......

真正的解决方案是将数据副本提供给不受信任的代码,或者传递一些不允许数据更改的包装器接口/对象(需要对func进行签名更改/重写)。

答案 2 :(得分:2)

使用ms.ToArray()将数据复制出流。显然,会有性能受到打击。

答案 3 :(得分:2)

您不能仅将数组的“切片”传递给方法。您将数组的副本传递给方法并将结果复制回来:

byte[] slice = new byte[length];
Buffer.BlockCopy(bytes, offset, slice, 0, length);
func(slice, 0, length);
Buffer.BlockCopy(slice, 0, bytes, offset, length);

或者,如果您可以更改方法,则传递某种包装数组的代理对象,并检查每个访问是否在允许的范围内:

class ArrayView<T>
{
    private T[] array;
    private int offset;
    private int length;

    public T this[int index]
    {
        get
        {
            if (index < offset || index >= offset + length)
                throw new ArgumentOutOfRange("index");
            return array[index];
        }
        set
        {
            if (index < offset || index >= offset + length)
                throw new ArgumentOutOfRange("index");
            array[index] = value;
        }
    }
}

答案 4 :(得分:0)

您是否尝试确保func()实际上永远无法更改内存流,或者如果 更改了某些内容,您的代码是否会引发异常,这是否足够?听起来像你想要做的事情:

void caller()
{
    MemoryStream ms = // not important
    var checksum = CalculateMyChecksum(ms);
    func(ms.GetBuffer(), 0, (int)ms.Length);
    if(checksum != CalculateMyChecksum(ms)){
        throw new Exception("Hey! Someone has been fiddling with my memory!");
    }
}

虽然对于任何重要/重要的事情,我都不会感到很自在。你能提供更多信息吗?也许有更好的解决方案可以解决您的问题,并且可以完全避免这个问题。