从流中读取字符串

本文关键字:字符串 读取 | 更新日期: 2023-09-27 18:07:02

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

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

那么我该如何处理字符串呢?写字符串没有问题。但是读取字符串的技巧是知道要读取多少字节,然后才能将其转换回字符串。

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

请注意,StringReader在这里不是一个选项,因为我想要处理文件数据的选项,可能比我想要加载到内存的大。

从流中读取字符串

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

下面是一些示例代码:
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;
}

想到的解决方案是提供一个预定的哨兵值来表示字符串的结束(例如,ASM使用0字节),或者在每个新数据类型之前提供一个固定长度的元数据块。在元数据块中应该包含类型和长度,以及您认为有用的任何其他信息。

为了紧凑起见,如果sentinel值在您的系统中可以工作,我将使用它