我正在将数据加密到流。例如,如果我的数据类型是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值在您的系统中可以工作,我将使用它