Тип: Булево. Признак доступности произвольного изменения позиции чтения/записи в потоке.
Полное описание, параметры и ограничения
ПотокВПамяти.ДоступноИзменениеПозиции (MemoryStream.CanSeek)
ПотокВПамяти (MemoryStream)
ДоступноИзменениеПозиции (CanSeek)
Доступен, начиная с версии 8.3.9.
Использование:
Только чтение.
Описание:
Тип: Булево.
Признак доступности произвольного изменения позиции чтения/записи в потоке.
Доступность:
Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер, интеграция.
Использование в версии:
Доступен, начиная с версии 8.3.9.
Методическая информация
Практические примеры
Записать и прочитать собственный JSON через ПотокВПамяти
Получаем настоящий UTF-8 поток, перемещаем его позицию к началу и читаем то же сообщение обратно. Сравниваем все поля, затем получаем байты и текст для просмотра без файла и сети.
Где и как запускать
Полный серверный общий модуль УчебныйJSON своего пустого файлового стенда УчебныйJSONВводВывод85 и отдельный полный модуль формы. В1С не запускался.
Подготовка
НОВАЯ пустая отдельная учебная файловая база на собственном Windows-компьютере; точная платформа8.5.1.1343. Имя конфигурации УчебныйJSONВводВывод85, совместимость Не использовать, язык Русский. Нет бизнес-метаданных, расширений, подписок и заданий. Все модули пусты, кроме своего учебного модуля. Рабочие базы не используются.
Конфигуратор → Общие модули → УчебныйJSON: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Вставьте ВЕСЬ основной код только выбранного урока. У разных уроков одинаковые имена процедур: не склеивайте их в одном модуле.
Собственная внешняя обработка УчебныйJSONВводВывод85 → управляемая Форма: команда Выполнить, действие Выполнить, связанная с ней кнопка; реквизиты не нужны. Весь отдельный модуль формы приведён ниже. Будущая ручная подготовка: сохранить конфигурацию, обновить конфигурацию базы (F7), открыть новый собственный тонкий клиент и свою обработку.
Четыре поля пакета создаются самим кодом: sku=BOOK85, title содержит кириллицу, двойные кавычки и перевод строки, quantity — Число3, enabled — БулевоИстина. Имена ключей пригодны для Структура. Это учебный контракт, не контракт Avito или другого сервиса.
Процедура ВыполнитьПример() Экспорт
ПроверитьСвойПустойСтенд();
Поток = Новый ПотокВПамяти;
Запись = Новый ЗаписьJSON;
Чтение = Новый ЧтениеJSON;
ЗаписьОткрыта = Ложь;
ЧтениеОткрыто = Ложь;
Ошибка = "";
Попытка
ЗаписьОткрыта = Истина;
Запись.ОткрытьПоток(Поток, "UTF-8", Ложь);
ЗаписатьJSON(Запись, СвойПакетJSON());
Запись.Закрыть();
ЗаписьОткрыта = Ложь;
Если Не Поток.ДоступноЧтение Или Не Поток.ДоступноИзменениеПозиции Тогда
ВызватьИсключение "Свой поток должен оставаться доступным для обратного чтения";
КонецЕсли;
Если Поток.Размер() <= 0 Тогда
ВызватьИсключение "Не получены байты собственного JSON";
КонецЕсли;
Если Поток.Перейти(0, ПозицияВПотоке.Начало) <> 0 Тогда
ВызватьИсключение "JSON-читатель должен начинать с первого байта, не с конца записи";
КонецЕсли;
ЧтениеОткрыто = Истина;
Чтение.ОткрытьПоток(Поток, "UTF-8");
Пакет = ПрочитатьJSON(Чтение, Ложь);
Чтение.Закрыть();
ЧтениеОткрыто = Ложь;
ПроверитьСвойПакетJSON(Пакет);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Если ТипЗнч(Данные) <> Тип("ДвоичныеДанные") Или Данные.Размер() <= 0 Тогда
ВызватьИсключение "Нужны реальные непустые байты собственного сообщения";
КонецЕсли;
Текст = ПолучитьСтрокуИзДвоичныхДанных(Данные, КодировкаТекста.UTF8);
ЧтениеОткрыто = Истина;
Чтение.УстановитьСтроку(Текст);
ИзТекста = ПрочитатьJSON(Чтение, Ложь);
Чтение.Закрыть();
ЧтениеОткрыто = Ложь;
ПроверитьСвойПакетJSON(ИзТекста);
Исключение
Ошибка = ОписаниеОшибки();
КонецПопытки;
ЗакрытьСвойЧитательJSON(Чтение, ЧтениеОткрыто, Ошибка);
ЗакрытьСвойПисательJSON(Запись, ЗаписьОткрыта, Ошибка);
Попытка
Поток.Закрыть();
Исключение
Ошибка = Ошибка + Символ(10) + "Закрытие собственного потока: " + ОписаниеОшибки();
КонецПопытки;
Если Ошибка <> "" Тогда
ВызватьИсключение Ошибка;
КонецЕсли;
Сообщить(Текст);
Сообщить("Два обратных чтения собственного JSON проверены; все ресурсы закрыты");
КонецПроцедуры
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
Функция СвойПакетJSON()
Возврат Новый Структура("sku,title,quantity,enabled", "BOOK85",
"Книга ""JSON""" + Символ(10) + "Учебная строка", 3, Истина);
КонецФункции
Процедура ПроверитьСвойПакетJSON(Пакет)
Если ТипЗнч(Пакет) <> Тип("Структура") Тогда
ВызватьИсключение "Нужен собственный JSON-объект, прочитанный в Структура";
КонецЕсли;
Эталон = СвойПакетJSON();
Если Пакет.Количество() <> Эталон.Количество() Тогда
ВызватьИсключение "В учебном пакете должно быть ровно четыре поля";
КонецЕсли;
Для Каждого Пара Из Эталон Цикл
Если Не Пакет.Свойство(Пара.Ключ, Факт) Тогда
ВызватьИсключение "Не найдено обязательное поле " + Пара.Ключ;
КонецЕсли;
Если ТипЗнч(Факт) <> ТипЗнч(Пара.Значение) Или Факт <> Пара.Значение Тогда
ВызватьИсключение "Не совпали тип или полное значение поля " + Пара.Ключ;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ЗакрытьСвойЧитательJSON(Чтение, ЧтениеОткрыто, Ошибка)
Если ЧтениеОткрыто Тогда
Попытка
Чтение.Закрыть();
ЧтениеОткрыто = Ложь;
Исключение
Ошибка = Ошибка + Символ(10) + "Закрытие своего JSON-читателя: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Процедура ЗакрытьСвойПисательJSON(Запись, ЗаписьОткрыта, Ошибка)
Если ЗаписьОткрыта Тогда
Попытка
Запись.Закрыть();
ЗаписьОткрыта = Ложь;
Исключение
Ошибка = Ошибка + Символ(10) + "Закрытие своего JSON-писателя: " + ОписаниеОшибки();
КонецПопытки;
КонецЕсли;
КонецПроцедурыУчебныйJSONВводВывод85.Форма
Своя внешняя обработка УчебныйJSONВводВывод85 → управляемая Форма → Модуль
Полный отдельный модуль формы с вызовом своего серверного общего модуля; не выполнялся.
&НаКлиенте
Процедура Выполнить(Команда)
ВыполнитьНаСервере();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
УчебныйJSON.ВыполнитьПример();
КонецПроцедурыРазбор по шагам
ПотокВПамяти создаётся пустым самим кодом. ЗаписьJSON.ОткрытьПоток получает объект потока, строковое имя кодировки UTF-8 и явное Ложь для BOM. Это не путь к файлу и не УстановитьСтроку.
ЗаписатьJSON сериализует собственную Структура в подготовленный поток. Сначала завершаем JSON-писатель; возвращаемое значение его Закрыть не выдаём за строку JSON, потому что получателем был поток.
Читаемость, возможность перемещения и непустой размер проверяются. Перейти(0,ПозицияВПотоке.Начало) должен вернуть0: без перехода reader окажется в конце записанных байтов.
ЧтениеJSON.ОткрытьПоток получает тот же поток и явную UTF-8. ПрочитатьJSON(...,Ложь) создаёт Структура. Все четыре поля проверяются по известному эталону с точными типами.
После закрытия JSON-reader ЗакрытьИПолучитьДвоичныеДанные отдаёт реальные байты и завершает собственный поток. Для просмотра переводим их в текст с КодировкаТекста.UTF8 и ещё раз разбираем этот текст, не принимая красивый вывод за доказательство сохранности данных.
На любом ошибочном пути отдельно пробуем закрыть reader, writer и собственный поток. Закрыть потока допускает повторный вызов; после ЗакрытьИПолучитьДвоичныеДанные другие рабочие методы потока не вызываются.
Как проверить результат
Будущий результат: оба обратных чтения имеют четыре правильных поля, quantity — число3, enabled — булевоИстина; кавычки, кириллица и перевод строки title восстановлены полностью. Выводится текст JSON и итог успеха.
Будущий отрицательный контроль: сразу после Пакет = ПрочитатьJSON(Чтение,Ложь); добавьте Пакет.quantity = "3";. Проверка должна отклонить пакет по типу, не сообщая успех. Верните исходный модуль после проверки.
Файл не создаётся, JSON никому не отправляется. Оба поточных метода доступны на сервере/тонком/толстом клиенте и внешнем соединении; этот урок исполнялся только в статических тестах Python, не в1С.
Ожидаемый результат
Своя Структура → реальный поток UTF-8 → проверенная Структура → байты → читаемый текст → повторно проверенная Структура.
На что обратить внимание
runtimeVerifiedScenarios=0: BSL, форма, файловые операции и сериализация в1С здесь не запускались. Проверены источники и статические контракты, а не поведение будущего клиента.
JSON не сохраняет произвольные прикладные типы автоматически. Здесь только четыре скалярных значения; ссылки, даты, двоичные вложения и функции восстановления не добавляйте без отдельного контракта.
Проверка разбирает известные имена, типы и полные значения, а не порядок свойств или одинаковый текст форматирования. Число3 и строка "3" для этого пакета различны.
Закрытие reader и writer выполняется независимо. Исходная ошибка не теряется при ошибке освобождения второго ресурса. Сообщение об успехе появляется только после всех проверок и закрытия.
ОткрытьПоток не имеет параметра ЗакрыватьПоток или LeaveOpen: не добавляйте несуществующий аргумент. Жизненный цикл собственного потока обрабатывается отдельно, доступность проверяется до перехода; фактическое поведение освобождения в1С здесь не подтверждено.
В памяти находится весь маленький учебный пакет. Название поточного API не означает ограниченный расход памяти при ПрочитатьJSON, который создаёт целый объект. Для больших внешних сообщений нужны отдельные лимиты и алгоритм.
Переданный writer параметр Кодировка — Строка; для перевода двоичных данных в текст используется настоящий enum КодировкаТекста.UTF8. Не подменяйте эти два контракта одним догаданным аргументом.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Записать байты в поток, прочитать часть и скопировать остаток
Поток хранит текущую позицию. Начальная ёмкость не означает заполненный размер; после записи чтение начинается с конца, пока позиция не изменена.
Где и как запускать
Учебная база: создайте серверный общий модуль УчебныеЗадачи (флаг Сервер). Код без директив вставьте в тело процедуры ВыполнитьПример() Экспорт. Вызовите её из серверного обработчика команды учебной обработки. Не запускайте в рабочей базе.
Подготовка
Выполняйте на сервере; все потоки в памяти, файлов нет.
Исходные четыре байта: 1, 2, 3, 4; ёмкость первого потока 64 — резерв памяти, не число данных.
Буфер = Новый БуферДвоичныхДанных(4);
Для Номер = 0 По 3 Цикл
Буфер.Установить(Номер, Номер + 1);
КонецЦикла;
Поток = Новый ПотокВПамяти(64);
Копия = Новый ПотокВПамяти;
Попытка
Сообщить(Поток.Размер());
Сообщить(Поток.ДоступнаЗапись);
Сообщить(Поток.ДоступноЧтение);
Сообщить(Поток.ДоступноИзменениеПозиции);
Поток.Записать(Буфер, 0, 4);
Поток.СброситьБуферы();
Сообщить(Поток.ТекущаяПозиция());
Поток.Перейти(0, ПозицияВПотоке.Начало);
Прочитанное = Новый БуферДвоичныхДанных(2);
Прочитано = Поток.Прочитать(Прочитанное, 0, 2);
Сообщить(Прочитано);
Сообщить(Прочитанное.Получить(0));
Поток.КопироватьВ(Копия, 2);
Сообщить(Копия.Размер());
ДанныеКопии = Копия.ЗакрытьИПолучитьДвоичныеДанные();
Копия = Неопределено;
Сообщить(ПолучитьHexСтрокуИзДвоичныхДанных(ДанныеКопии));
Поток.УстановитьРазмер(3);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Поток = Неопределено;
Исключение
Если Копия <> Неопределено Тогда
Копия.Закрыть();
КонецЕсли;
Если Поток <> Неопределено Тогда
Поток.Закрыть();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Сообщить(ПолучитьHexСтрокуИзДвоичныхДанных(Данные));
Основа = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Данные);
ПотокИзБуфера = Новый ПотокВПамяти(Основа);
Сообщить(ПотокИзБуфера.Размер());
ПотокИзБуфера.Закрыть();Разбор по шагам
Создаём два потока и проверяем размер пустого потока: 0.
После записи позиция 4; Перейти перемещает её к началу для чтения.
Прочитать возвращает фактическое число байтов. КопироватьВ начинает с текущей позиции, поэтому копирует только 3 и 4.
УстановитьРазмер сокращает первый поток до трёх байтов; ЗакрытьИПолучитьДвоичныеДанные выдаёт содержимое и закрывает поток.
Как проверить результат
Прочитано 2 байта, первый равен 1; содержимое копии в Hex — 0304.
После сокращения исходные данные в Hex — 010203; поток, созданный на их буфере, имеет размер 3.
Ожидаемый результат
Частичное чтение, копирование остатка и сокращение потока выполнены без файлов.
На что обратить внимание
После ЗакрытьИПолучитьДвоичныеДанные поток больше не используйте.
Прочитать может вернуть меньше запрошенного количества, особенно у сетевых потоков: всегда проверяйте возвращённое число.
НачальнаяЁмкость — объём резервирования, УстановитьРазмер — изменение фактических данных; это разные операции.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.