从流中读取字符串

Reading String from Stream

我正在将数据加密到流中。例如,如果我的数据是 Int32 类型,我将使用 BitConverter.GetBytes(myInt) 获取字节,然后将这些字节写入流。

为了读回数据,我读取sizeof(Int32)以确定要读取的字节数,读取这些字节,然后使用BitConverter.ToInt32(byteArray, 0)将字节转换回Int32.

那么我该如何使用字符串来做到这一点呢?写字符串没问题。但是读取字符串时的技巧是知道在将其转换回字符串之前要读取多少字节。

我发现了类似的问题,但他们似乎假设字符串占据了整个流并且只读取到流的末尾。但是在这里,我可以在字符串前后添加任意数量的其他项目。

请注意,StringReader 不是此处的选项,因为我希望选择处理可能大于我想要加载到内存中的文件数据的选项。

想到的解决方案要么提供一个预先确定的标记值来指示字符串的结尾(例如,ASM 为此使用 0 字节),要么提供一个固定长度的元数据块每个新数据类型。在该元数据块中将包含类型和长度,以及您认为包含的任何其他有用信息。

为了紧凑,我会使用标记值,如果它在您的系统中工作的话。

您通常会发送内容长度 header,然后读取由该信息确定的长度。

下面是一些示例代码:

public async Task ContinouslyReadFromStream(NetworkStream sourceStream, CancellationToken token)
{
    while (!ct.IsCancellationRequested && sourceStream.CanRead)
    {
        while (sourceStream.CanRead && !sourceStream.DataAvailable)
        {
            // Avoid potential high CPU usage when doing stream.ReadAsync
            // while waiting for data
            Thread.Sleep(10);
        }

        var lengthOfMessage = BitConverter.ToInt32(await ReadExactBytesAsync(stream, 4, ct), 0);
        var content = await ReadExactBytesAsync(stream, lengthOfMessage, ct);
        // Assuming you use UTF8 encoding
        var stringContent = Encoding.UTF8.GetString(content);

    }
}


protected static async Task<byte[]> ReadExactBytesAsync(Stream stream, int count, CancellationToken ct)
{
    var buffer = new byte[count];
    var totalBytesRemaining = count;
    var totalBytesRead = 0;
    while (totalBytesRemaining != 0)
    {
        var bytesRead = await stream.ReadAsync(buffer, totalBytesRead, totalBytesRemaining, ct);
        ct.ThrowIfCancellationRequested();
        totalBytesRead += bytesRead;
        totalBytesRemaining -= bytesRead;
    }
    return buffer;
}