ПотокВПамяти.ДоступноИзменениеПозиции

Свойства · CanSeek

Тип: Булево. Признак доступности произвольного изменения позиции чтения/записи в потоке.

Полное описание, параметры и ограничения

ПотокВПамяти.ДоступноИзменениеПозиции (MemoryStream.CanSeek)

ПотокВПамяти (MemoryStream)

ДоступноИзменениеПозиции (CanSeek)

Доступен, начиная с версии 8.3.9.

Использование:
Только чтение.
Описание:
Тип: Булево.
Признак доступности произвольного изменения позиции чтения/записи в потоке.
Доступность:

Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер, интеграция.

Использование в версии:

Доступен, начиная с версии 8.3.9.

Методическая информация

Практические примеры

Записать и прочитать собственный JSON через ПотокВПамяти

Получаем настоящий UTF-8 поток, перемещаем его позицию к началу и читаем то же сообщение обратно. Сравниваем все поля, затем получаем байты и текст для просмотра без файла и сети.

Где и как запускать

Полный серверный общий модуль УчебныйJSON своего пустого файлового стенда УчебныйJSONВводВывод85 и отдельный полный модуль формы. В1С не запускался.

Подготовка

  1. НОВАЯ пустая отдельная учебная файловая база на собственном Windows-компьютере; точная платформа8.5.1.1343. Имя конфигурации УчебныйJSONВводВывод85, совместимость Не использовать, язык Русский. Нет бизнес-метаданных, расширений, подписок и заданий. Все модули пусты, кроме своего учебного модуля. Рабочие базы не используются.

  2. Конфигуратор → Общие модули → УчебныйJSON: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Вставьте ВЕСЬ основной код только выбранного урока. У разных уроков одинаковые имена процедур: не склеивайте их в одном модуле.

  3. Собственная внешняя обработка УчебныйJSONВводВывод85 → управляемая Форма: команда Выполнить, действие Выполнить, связанная с ней кнопка; реквизиты не нужны. Весь отдельный модуль формы приведён ниже. Будущая ручная подготовка: сохранить конфигурацию, обновить конфигурацию базы (F7), открыть новый собственный тонкий клиент и свою обработку.

  4. Четыре поля пакета создаются самим кодом: 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.ВыполнитьПример();
КонецПроцедуры

Разбор по шагам

  1. ПотокВПамяти создаётся пустым самим кодом. ЗаписьJSON.ОткрытьПоток получает объект потока, строковое имя кодировки UTF-8 и явное Ложь для BOM. Это не путь к файлу и не УстановитьСтроку.

  2. ЗаписатьJSON сериализует собственную Структура в подготовленный поток. Сначала завершаем JSON-писатель; возвращаемое значение его Закрыть не выдаём за строку JSON, потому что получателем был поток.

  3. Читаемость, возможность перемещения и непустой размер проверяются. Перейти(0,ПозицияВПотоке.Начало) должен вернуть0: без перехода reader окажется в конце записанных байтов.

  4. ЧтениеJSON.ОткрытьПоток получает тот же поток и явную UTF-8. ПрочитатьJSON(...,Ложь) создаёт Структура. Все четыре поля проверяются по известному эталону с точными типами.

  5. После закрытия JSON-reader ЗакрытьИПолучитьДвоичныеДанные отдаёт реальные байты и завершает собственный поток. Для просмотра переводим их в текст с КодировкаТекста.UTF8 и ещё раз разбираем этот текст, не принимая красивый вывод за доказательство сохранности данных.

  6. На любом ошибочном пути отдельно пробуем закрыть reader, writer и собственный поток. Закрыть потока допускает повторный вызов; после ЗакрытьИПолучитьДвоичныеДанные другие рабочие методы потока не вызываются.

Как проверить результат

  1. Будущий результат: оба обратных чтения имеют четыре правильных поля, quantity — число3, enabled — булевоИстина; кавычки, кириллица и перевод строки title восстановлены полностью. Выводится текст JSON и итог успеха.

  2. Будущий отрицательный контроль: сразу после Пакет = ПрочитатьJSON(Чтение,Ложь); добавьте Пакет.quantity = "3";. Проверка должна отклонить пакет по типу, не сообщая успех. Верните исходный модуль после проверки.

  3. Файл не создаётся, JSON никому не отправляется. Оба поточных метода доступны на сервере/тонком/толстом клиенте и внешнем соединении; этот урок исполнялся только в статических тестах Python, не в1С.

Ожидаемый результат

Своя Структура → реальный поток UTF-8 → проверенная Структура → байты → читаемый текст → повторно проверенная Структура.

На что обратить внимание

  1. runtimeVerifiedScenarios=0: BSL, форма, файловые операции и сериализация в1С здесь не запускались. Проверены источники и статические контракты, а не поведение будущего клиента.

  2. JSON не сохраняет произвольные прикладные типы автоматически. Здесь только четыре скалярных значения; ссылки, даты, двоичные вложения и функции восстановления не добавляйте без отдельного контракта.

  3. Проверка разбирает известные имена, типы и полные значения, а не порядок свойств или одинаковый текст форматирования. Число3 и строка "3" для этого пакета различны.

  4. Закрытие reader и writer выполняется независимо. Исходная ошибка не теряется при ошибке освобождения второго ресурса. Сообщение об успехе появляется только после всех проверок и закрытия.

  5. ОткрытьПоток не имеет параметра ЗакрыватьПоток или LeaveOpen: не добавляйте несуществующий аргумент. Жизненный цикл собственного потока обрабатывается отдельно, доступность проверяется до перехода; фактическое поведение освобождения в1С здесь не подтверждено.

  6. В памяти находится весь маленький учебный пакет. Название поточного API не означает ограниченный расход памяти при ПрочитатьJSON, который создаёт целый объект. Для больших внешних сообщений нужны отдельные лимиты и алгоритм.

  7. Переданный writer параметр Кодировка — Строка; для перевода двоичных данных в текст используется настоящий enum КодировкаТекста.UTF8. Не подменяйте эти два контракта одним догаданным аргументом.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Записать байты в поток, прочитать часть и скопировать остаток

Поток хранит текущую позицию. Начальная ёмкость не означает заполненный размер; после записи чтение начинается с конца, пока позиция не изменена.

Где и как запускать

Учебная база: создайте серверный общий модуль УчебныеЗадачи (флаг Сервер). Код без директив вставьте в тело процедуры ВыполнитьПример() Экспорт. Вызовите её из серверного обработчика команды учебной обработки. Не запускайте в рабочей базе.

Подготовка

  1. Выполняйте на сервере; все потоки в памяти, файлов нет.

  2. Исходные четыре байта: 1, 2, 3, 4; ёмкость первого потока 64 — резерв памяти, не число данных.

Буфер = Новый БуферДвоичныхДанных(4);
Для Номер = 0 По 3 Цикл
    Буфер.Установить(Номер, Номер + 1);
КонецЦикла;
Поток = Новый ПотокВПамяти(64);
Копия = Новый ПотокВПамяти;
Попытка
    Сообщить(Поток.Размер());
    Сообщить(Поток.ДоступнаЗапись);
    Сообщить(Поток.ДоступноЧтение);
    Сообщить(Поток.ДоступноИзменениеПозиции);
    Поток.Записать(Буфер, 0, 4);
    Поток.СброситьБуферы();
    Сообщить(Поток.ТекущаяПозиция());
    Поток.Перейти(0, ПозицияВПотоке.Начало);
    Прочитанное = Новый БуферДвоичныхДанных(2);
    Прочитано = Поток.Прочитать(Прочитанное, 0, 2);
    Сообщить(Прочитано);
    Сообщить(Прочитанное.Получить(0));
    Поток.КопироватьВ(Копия, 2);
    Сообщить(Копия.Размер());
    ДанныеКопии = Копия.ЗакрытьИПолучитьДвоичныеДанные();
    Копия = Неопределено;
    Сообщить(ПолучитьHexСтрокуИзДвоичныхДанных(ДанныеКопии));
    Поток.УстановитьРазмер(3);
    Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
    Поток = Неопределено;
Исключение
    Если Копия <> Неопределено Тогда
        Копия.Закрыть();
    КонецЕсли;
    Если Поток <> Неопределено Тогда
        Поток.Закрыть();
    КонецЕсли;
    ВызватьИсключение;
КонецПопытки;
Сообщить(ПолучитьHexСтрокуИзДвоичныхДанных(Данные));
Основа = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Данные);
ПотокИзБуфера = Новый ПотокВПамяти(Основа);
Сообщить(ПотокИзБуфера.Размер());
ПотокИзБуфера.Закрыть();

Разбор по шагам

  1. Создаём два потока и проверяем размер пустого потока: 0.

  2. После записи позиция 4; Перейти перемещает её к началу для чтения.

  3. Прочитать возвращает фактическое число байтов. КопироватьВ начинает с текущей позиции, поэтому копирует только 3 и 4.

  4. УстановитьРазмер сокращает первый поток до трёх байтов; ЗакрытьИПолучитьДвоичныеДанные выдаёт содержимое и закрывает поток.

Как проверить результат

  1. Прочитано 2 байта, первый равен 1; содержимое копии в Hex — 0304.

  2. После сокращения исходные данные в Hex — 010203; поток, созданный на их буфере, имеет размер 3.

Ожидаемый результат

Частичное чтение, копирование остатка и сокращение потока выполнены без файлов.

На что обратить внимание

  1. После ЗакрытьИПолучитьДвоичныеДанные поток больше не используйте.

  2. Прочитать может вернуть меньше запрошенного количества, особенно у сетевых потоков: всегда проверяйте возвращённое число.

  3. НачальнаяЁмкость — объём резервирования, УстановитьРазмер — изменение фактических данных; это разные операции.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.