Что происходит под капотом при создании файлового потока?

250
11 августа 2018, 12:40

Сейчас читаю вот эту статью Difference between Buffer & Stream in C# и хотел бы для себя сначала уяснить что правильно понимаю, что происходит под капотом при выполнении инструкции FileStream stream = new FileStream("filepath.txt", FileMode.open).

Мое понимание происходящего

На HDD/SSD лежит некий файл filepath.txt, который может быть размером даже больше RAM. И при выполнении вышеприведенной инструкции, исполняющая среда как-бы подносит к началу этого файла шланг и открывает краник. Водичка (байты) сразу не течет, а просто на готове.

Правильно ли я все описал?

Answer 1

Грубо говоря, поток - это место, откуда можно читать или куда модно писать данные. Это, если можно так выразиться, абстрактное понятие. Вот, например, мы создаем поток для доступа к файлу

using(var fileStream = File.OpenRead(path))
{
  ....
}

В примере создается экземпляр класса FileStream, который наследован от Stream. Это позволяет нам читать и писать в файл. Тип MemoryStream - представляет собой поток чтения/записи в память. NetworkStream - сеть. И так далее.

Итак, до этого момента мы говорили о потоке, который является источником и/или приемником данных. Но, помимо таких потоков, есть потоки - декораторы. Декораторы сами по себе не являются источниками или приемноками данных. Они принимают поток как параметр и используют его для операций чтения и записи. Для чего они нужны? Читаем далее.

Далее, BufferedStream - это декоратор над Stream. Он позволяет буферизировать запись/чтение в поток. Это полезно при файловом вводе/выводе, так как чтение/запись с использованием буфера уменьшает количество записей/считываний, что увеличивает производительность. Его можно использовать с любым потоком, например

using(var bufferedFileStream = 
  new BufferedStream(File.OpenRead(path), 1024*1024)) // буфер в мегабайт
{
  ....
}

Как я сказал, BufferedStream - это декоратор, то есть он только расширяет возможности декорируемого потока. Вот пример другого декоратора - я его использовал для мониторинга операций чтения/записи

public class StreamSpy : Stream
{
    private readonly Stream _inner;
    private readonly ILog _log;
    public StreamSpy(Stream inner, ILog log)
    {
        _inner = inner;
        _log = log;
    }
    public override void Flush()
    {
        _inner.Flush();
        _log.Debug("Flush!");
    }
    public override long Seek(long offset, SeekOrigin origin)
    {
        return _inner.Seek(offset, origin);
    }
    public override void SetLength(long value)
    {
        _inner.SetLength(value);
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
        _log.Debug($"READ buffer {buffer.Length}, offset {offset}, count {count}, POSITION: {Position}");
        return _inner.Read(buffer, offset, count);
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
        _inner.Write(buffer, offset, count);
        _log.Debug($"WRITE buffer {buffer.Length}, offset {offset}, count {count}");
    }
    public override bool CanRead => _inner.CanRead;
    public override bool CanSeek => _inner.CanSeek;
    public override bool CanWrite => _inner.CanWrite;
    public override long Length => _inner.Length;
    public override long Position
    {
        get => _inner.Position;
        set => _inner.Position = value;
    }
    public override void Close()
    {
        base.Close();
        _inner.Close();
        _log.Info("CLOSE");
    }
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        _inner.Dispose();
        _log.Info("DISPOSE");
    }
}

Так как это просто декораторы, то их можно объединять, например

using(var bufferedFileStream = 
  new BufferedStream(new StreamSpy(File.OpenRead(path), mylog), 1024*1024)) // буфер в мегабайт
{
  ....
}

теперь конечный поток bufferedFileStream представляет собой буферизированный поток чтения/записи в файл с логгированием операций.

Соответсвенно, если вы читаете байт используя просто FileStream - вы прочитаете ровно байт. Если вы читаете байт из файловго потока, который декорирован буфером, то вы либо читаете с диска весь буфер, либо читаете данные из буфера в памяти.

READ ALSO
Производительность OpenCL

Производительность OpenCL

Возникла проблема оптимизации алгоритма поиска пути на карте (двухмерный массив), уперся в производительность, которая после 200 элементов...

226
Блокировка с задержкой

Блокировка с задержкой

День добрый, требуется заблокировать textbox`s на минуту, а потом снять блокировку, и если были введены неверные значения более двух разЕсли в третий...

251
На сервере не работает $_POST

На сервере не работает $_POST

Работаю с Retrofit2, Volley даже уже Postman тестилНе работает $_POST на сервере

254
Добавление пользователя к facebook webhook

Добавление пользователя к facebook webhook

Есть следующий код и при его выполнении выбивает ошибку,расположенную нижеВ чем может быть причина?

275