This work is licensed with Creative Commons Attribution 3.0 Unported License. You are able: - to Share — to copy, distribute and transmit the work - to Remix — to adapt the work Автор: Leonid Krashenko e-mail: Leonid.Krashenko@gmail.com Перевод данного руководства - одна из тем атома Org1 (орг ван), см. http://trac.assembla.com/org1/wiki/WikiStart = Каналы и буферы = Каналы и буферы формируют основу ввода-вывода Tango. == Каналы == Ввод-вывод на Танго потоково-ориентированный: любой пункт назначения для данных описывается конструкцией, называемой каналом (conduit), который является основой для InputStream и OutputStream. Например, существуют каналы для взаимодействия с файлами, сокетами, с консолью и т.д. Некоторые каналы (например, для сокетов) требуют явного указания конечного пункта назначения, в то время как другие оперируют скрытно (например, файловые и консольные). Существуют также расширения для каналов, которые включают операции асинхронного ввода-вывода, поддерживаемого специальными механизмами ОС (см. tango.io.selector). Каналы являются двухсторонними (...). Чтение использует InputStream, запись - OutputStream; это осуществляется использованием соответствующих методов input() и output(). Обычно, приложение использует методы read() и write(), принимающие на вход массив void и возвращающие число отправленных или полученных байт. При этом возвращаемое значение может быть меньшим, чем размер массива. В частности, если найден конец потока, будет возвращена зарезервированная константа IConduit.Eof. InputStream input(); OutputStream output(); === InputStream === void clear(); IConduit conduit(); uint read (void[] dst); === OutputStream === void flush(); IConduit conduit(); uint write(void[] src); OutputStream copy (InputStream src); Методы OutputStream позволяют опустошить буферы (flush) и скопировать содержимого другого канала. (...) Каналы поддерживают нотацию потоковых фильтров: 1 или несколько фильтров может быть наложено на канал и каждый из них может перехватывать и изменять данные по мере пропускания сквозь себя. Фильтры накладываются с использованием следующих методов, в обратном порядке, каждый из методов возвращает предыдущий фильтр: InputStream attach(InputStream filter); OutputStream attach(OutputStream filter); Фильтры действуют совместно; например, вызов read() в одном фильтре позовет read() у его предшественника. Вместе с тем, фильтры могут менять порядок фильтрации. Базовые классы для фильтров находятся в модуле tango.io.Conduit. (...) Канал по окончании использования необходимо явно закрывать в самом приложении с тем, чтобы выполнить специфические для него операции по освобождению памяти и для отбрасывания примененных фильтров. === Исключения в каналах === Как правило, каналы не бросают исключений, т.к. почти все ошибки расцениваются как некритические. Например, значение IConduit.Eof обычно прямо возвращается в приложение. Тем не менее, исключения могут возникнуть на более низком уровне, если ОС обнаруживает какую-либо проблему. == Буферы == Буферизация канала (...) упрощает многие операции с его содежимым, такие как обработка токенов или конкатенация. Это также может повысить производительность в ряде случаев. Например, буферизация позволяет каналу считывать и записывать большие объемы данных вместо работы с каждым элементом в отдельности; она также предоставляет временное пространство для некоторых алгоритмов с целью повышения эффективности обработки потока, а также поддерживает эффективное отображение записей-данных в память. Буферы являются двухсторонними и поддерживают определенные позиции считывания и записи: например, можно записывать в конец буфера и считывать из начала. Буферы предоставляют множество функций (...), поддерживают многопользовательский режим. Например, несколько "читателей" или "писателей" могут быть подключены к буферу, и он будет синхронизирован с ними. Это может пригодиться, если вы имеете дело со специальным протоколом, где клиенты должны работать совместно, а не раздельно (?). (...) Буфер работает как умный массив, опустощая себя и снова заполняя через канал по необходимости. Буфер можно использовать и без канала - в качестве накопителя данных. В обоих случаях пользователи работают с буфером одинаково, но с одним ограничением: без подключения к каналу буфер не опустошается автоматически при заполнении до отказа, в этом случае будет брошено исключение. (...) Обычно для работы с Buffer используются следующие методы: IBuffer append(void[] src); uint read(void[] dst); void[] slice(); IBuffer fill(); IBuffer flush(); IBuffer clear(); IConduit conduit(); Следующие методы используются реже: bool skip(); bool truncate(uint extent); bool next(uint delegate(void[]) tokenizer); void[] getContent(); IBuffer setContent(void[] content); IBuffer copy(IConduit src); IConduit compress(); Остальные члены класса инкапсулируют различные платформозависимые детали реализации отображения памяти в файл; память в буфере может быть отражена прямо в (обычно большой) файл, который впоследствии может рассматриваться как еще один буфер, а не массив void[]. === Исключения в Buffer === Если буфер не подключен к каналу, при перезаполнения или (?) попытке чтения из пустого буфера будет брошено исключение. При необходимости, надо использовать т.н. растущий буфер для корректной обработки ситуации перезаполнения.