Если вы только последовательно считываете данные из HugeStream, тогда ему просто нужно прочитать каждый дочерний поток (и добавить его в локальный файл, а также вернуть прочитанные данные вызывающей стороне), пока дочерний поток не будет исчерпан, тогда перейти к следующему дочернему потоку. Если операция поиска используется для перехода «назад» в данных, вы должны начать чтение из файла локального кэша; когда вы достигнете конца файла кэша, вы должны возобновить чтение текущего дочернего потока, с которого вы остановились.
Пока что все это довольно просто реализовать - вам просто нужно перенаправить вызовы 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
}
Чтобы разрешить поиск в обратном направлении, вам просто нужно ввести новый локальный файловый поток, в который вы копируете все данные во время чтения (см. Комментарий в моем псевдокоде выше). Вам нужно ввести состояние, чтобы вы знали, что вы читаете из файла кеша, а не из текущего дочернего потока, а затем просто получаете прямой доступ к кешу (поиск и т. Д. Прост, потому что кеш представляет всю историю данных, прочитанных из HugeStream поэтому смещения поиска одинаковы для HugeStream и Cache - вам просто нужно перенаправить любые вызовы Read, чтобы вытащить данные из потока кэша)
Если вы читаете или пытаетесь вернуться к концу потока кэша, вам необходимо возобновить чтение данных из текущего дочернего потока. Просто вернитесь к приведенной выше логике и продолжайте добавлять данные в ваш поток кеша.
Если вы хотите иметь возможность поддерживать полный произвольный доступ в HugeStream, вам нужно будет поддерживать поиск «вперед» (за пределами текущего конца потока кэша). Если вы заранее не знаете длины дочерних потоков, у вас нет другого выбора, кроме как просто читать данные в свой кэш, пока не достигнете смещения поиска. Если вы знаете размеры всех потоков, то вы можете искать прямо и более эффективно в нужном месте, но тогда вам придется разработать эффективный способ хранения данных, которые вы читаете, в файл кеша и записи, какие части кеша файл содержит действительные данные, которые еще не были прочитаны из БД - это немного сложнее.
Я надеюсь, что это имеет смысл для вас и дает вам лучшее представление о том, как действовать ...
(Вам не нужно реализовывать намного больше, чем интерфейсы Read и Seek, чтобы это работало).