Mat*_*kan 3 c# iostream stream
我想创建一个在其构造函数中采用 an 的类(我们称之为 HugeStream 类)。这个HugeStream应该实现Stream抽象类。IEnumerable
<Stream
>
基本上,我有来自数据库的 1 到许多 UTF8 流,当它们组合在一起时,会形成一个巨大的 XML 文档。HugeStream 需要文件支持,以便我可以随时返回到整个缝合在一起的流的位置 0。
有人知道如何快速实施这一点吗?
我在此页面上看到了类似的内容,但它对于处理大量大流来说似乎并不是最佳选择。效率是关键。
顺便说一句,我在可视化 Streams 方面遇到了麻烦,并且现在我需要实现自己的 Stream,我有点困惑。如果有人知道有关于实现 Stream 类的好教程,请告诉我;逛了一圈没发现什么好文章。我只是看到很多关于使用已有的 FileStreams 和 MemoryStreams 的文章。我是一个非常视觉化的学习者,由于某种原因找不到任何有用的东西来研究这个概念。
谢谢,
马特
如果您只从 HugeStream 中顺序读取数据,那么它只需要读取每个子流(并将其附加到本地文件中,并将读取的数据返回给调用者),直到子流耗尽,然后继续下一个子流。如果使用Seek操作在数据中“向后”跳转,则必须从本地缓存文件开始读取;当到达缓存文件末尾时,必须从上次中断的位置继续读取当前子流。
到目前为止,这一切实现起来都非常简单 - 您只需将 Read 调用间接到适当的流,并在每个流用完数据时切换流。
引用文章的低效之处在于,每次阅读时它都会遍历所有的流来确定从哪里继续阅读。为了改进这一点,您需要仅在需要时打开子流,并跟踪当前打开的流,以便您可以继续从当前流中读取更多数据,直到它耗尽。然后打开下一个流作为“当前”流并继续。这非常简单,因为您有一个线性序列的流,因此您只需逐一遍历它们即可。即类似:
int currentStreamIndex = 0;
Stream currentStream = childStreams[currentStreamIndex++];
...
public override int Read(byte[] buffer, int offset, int count)
{
while (count > 0)
{
// Read what we can from the current stream
int numBytesRead = currentSteam.Read(buffer, offset, count);
count -= numBytesRead;
offset += numBytesRead;
// If we haven't satisfied the read request, we have exhausted the child stream.
// Move on to the next stream and loop around to read more data.
if (count > 0)
{
// If we run out of child streams to read from, we're at the end of the HugeStream, and there is no more data to read
if (currentStreamIndex >= numberOfChildStreams)
break;
// Otherwise, close the current child-stream and open the next one
currentStream.Close();
currentStream = childStreams[currentStreamIndex++];
}
}
// Here, you'd write the data you've just read (into buffer) to your local cache stream
}
Run Code Online (Sandbox Code Playgroud)
为了允许向后查找,您只需引入一个新的本地文件流,在阅读时将所有数据复制到其中(请参阅上面我的伪代码中的注释)。您需要引入一个状态,以便您知道您正在从缓存文件而不是当前的子流中读取数据,然后直接访问缓存(查找等很容易,因为缓存代表了从 HugeStream 读取的数据的整个历史记录) ,因此 HugeStream 和 Cache 之间的查找偏移量是相同的 - 您只需重定向任何 Read 调用即可从缓存流中获取数据)
如果读取或回溯到缓存流的末尾,则需要从当前子流中恢复读取数据。只需返回上面的逻辑并继续将数据附加到缓存流即可。
如果您希望能够支持 HugeStream 内的完全随机访问,您将需要支持搜索“向前”(超出缓存流的当前末尾)。如果您事先不知道子流的长度,则别无选择,只能继续将数据读入缓存,直到达到查找偏移量。如果您知道所有流的大小,那么您可以直接更有效地查找到正确的位置,但是您必须设计一种有效的方法来将读取的数据存储到缓存文件并记录缓存的哪些部分文件包含有效数据,并且实际上尚未从数据库中读取数据 - 这是更高级的。
我希望这对您有意义,并让您更好地了解如何继续......
(您不需要实现比 Read 和 Seek 接口更多的内容来实现此功能)。