diff --git a/src/OneScript.StandardLibrary/Binary/FileStreamContext.cs b/src/OneScript.StandardLibrary/Binary/FileStreamContext.cs index 6386898a6..70f517935 100644 --- a/src/OneScript.StandardLibrary/Binary/FileStreamContext.cs +++ b/src/OneScript.StandardLibrary/Binary/FileStreamContext.cs @@ -22,7 +22,7 @@ namespace OneScript.StandardLibrary.Binary /// Следует учитывать, что помимо буферизации существует кэширование чтения и записи файлов в операционной системе, на которое невозможно повлиять программно. /// [ContextClass("ФайловыйПоток", "FileStream")] - public class FileStreamContext : AutoContext, IStreamWrapper, IDisposable + public class FileStreamContext : AutoContext, IDisposable, IStreamWrapper { private readonly FileStream _underlyingStream; diff --git a/src/OneScript.StandardLibrary/Json/JSONReader.cs b/src/OneScript.StandardLibrary/Json/JSONReader.cs index 444907ee2..866cd54b9 100644 --- a/src/OneScript.StandardLibrary/Json/JSONReader.cs +++ b/src/OneScript.StandardLibrary/Json/JSONReader.cs @@ -5,15 +5,16 @@ This Source Code Form is subject to the terms of the at http://mozilla.org/MPL/2.0/. ----------------------------------------------------------*/ -using System; -using System.IO; using Newtonsoft.Json; using OneScript.Commons; using OneScript.Contexts; using OneScript.Exceptions; +using OneScript.StandardLibrary.Binary; using OneScript.StandardLibrary.Text; using ScriptEngine.Machine; using ScriptEngine.Machine.Contexts; +using System; +using System.IO; namespace OneScript.StandardLibrary.Json { @@ -40,7 +41,6 @@ public override bool Read() } /// - /// /// Предназначен для последовательного чтения JSON-данных из файла или строки. /// [ContextClass("ЧтениеJSON", "JSONReader")] @@ -50,7 +50,6 @@ public class JSONReader : AutoContext private JsonReaderInternal _reader; /// - /// /// Возвращает true если для объекта чтения json был задан текст для парсинга. /// private bool IsOpen() => _reader != null; @@ -71,49 +70,25 @@ public static JSONReader Constructor() } /// - /// /// Указывает на позицию, находящуюся сразу после прочитанного значения. /// При ошибке чтение остается на позиции последнего успешно считанного символа. /// /// Число (Number), Неопределено (Undefined) [ContextProperty("ТекущаяПозиция", "CurrentPosition")] public IValue CurrentPosition - { - get - { - if (IsOpen()) - { - return ValueFactory.Create(_reader.LinePosition); - } - - return ValueFactory.Create(); // Неопределено - } - } + => IsOpen() ? ValueFactory.Create(_reader.LinePosition) : ValueFactory.Create(); /// - /// /// Указывает на позицию сразу после прочитанного значения. /// Например, перед чтением первого элемента - 0, после чтения первого элемента -1 . /// /// Число (Number), Неопределено (Undefined) [ContextProperty("ТекущаяСтрока", "CurrentLine")] public IValue CurrentLine - { - get - { - if (IsOpen()) - { - return ValueFactory.Create(_reader.LineNumber); - } - - return ValueFactory.Create(); // Неопределено - } - } + => IsOpen() ? ValueFactory.Create(_reader.LineNumber) : ValueFactory.Create(); /// - /// /// Содержит текущее значение: - /// /// - Число - если ТипТекущегоЗначения имеет значение Число; /// - Строка - если ТипТекущегоЗначения имеет одно из следующих значений: /// - Комментарий, @@ -160,7 +135,6 @@ public IValue CurrentValue default: throw JSONReaderException.CannotGetValue(); - ; } } } @@ -168,7 +142,6 @@ public IValue CurrentValue public object ReaderValue => _reader.Value; /// - /// /// Тип текущего значения в документе JSON во внутреннем формате. /// null - если чтение еще не началось или достигнут конец файла. /// @@ -183,7 +156,6 @@ public JsonToken CurrentJsonTokenType } /// - /// /// Тип текущего значения в документе JSON. /// Неопределено - если чтение еще не началось или достигнут конец файла. /// @@ -217,10 +189,8 @@ public JSONValueTypeEnum CurrentValueType } /// - /// /// Завершает чтение текста JSON из файла или строки. /// - /// [ContextMethod("Закрыть", "Close")] public void Close() { @@ -232,10 +202,10 @@ public void Close() } /// - /// - /// Открывает JSON-файл для чтения данным объектом. Если перед вызовом данного метода уже производилось чтение JSON из другого файла или строки, то чтение прекращается и объект инициализируется для чтения из указанного файла. + /// Открывает JSON-файл для чтения данным объектом. + /// Если перед вызовом данного метода уже производилось чтение JSON из другого файла или строки, + /// то чтение прекращается и объект инициализируется для чтения из указанного файла. /// - /// /// /// Имя файла, содержащего текст JSON. /// @@ -243,17 +213,14 @@ public void Close() [ContextMethod("ОткрытьФайл", "OpenFile")] public void OpenFile(string JSONFileName, IValue encoding = null) { - if (IsOpen()) - Close(); + Close(); StreamReader _fileReader; try - { - if (encoding != null) - _fileReader = FileOpener.OpenReader(JSONFileName, TextEncodingEnum.GetEncoding(encoding)); - else - _fileReader = FileOpener.OpenReader(JSONFileName, System.Text.Encoding.UTF8); + { + var enc = encoding != null ? TextEncodingEnum.GetEncoding(encoding) : System.Text.Encoding.UTF8; + _fileReader = FileOpener.OpenReader(JSONFileName, enc); } catch (Exception e) { @@ -266,11 +233,35 @@ public void OpenFile(string JSONFileName, IValue encoding = null) }; } + /// + /// Устанавливает поток для чтения JSON данным объектом. + /// Если перед вызовом данного метода уже производилось чтение JSON из другого файла, строки или потока, + /// то чтение прекращается и объект инициализируется для чтения из указанного потока. + /// + /// + /// Поток для чтения текста JSON. + /// + /// Позволяет задать кодировку входного потока. + [ContextMethod("ОткрытьПоток", "OpenStream")] + public void OpenStream(IStreamWrapper streamContext, IValue encoding = null) + { + Close(); + + var stream = streamContext?.GetUnderlyingStream() + ?? throw new ArgumentNullException(nameof(streamContext)); + + var enc = encoding != null ? TextEncodingEnum.GetEncoding(encoding) : System.Text.Encoding.UTF8; + + _reader = new JsonReaderInternal(new StreamReader(stream, enc, leaveOpen:true)) + { + SupportMultipleContent = true + }; + } + /// /// Если текущее значение – начало массива или объекта, то пропускает его содержимое и конец. /// Для остальных типов значений работает аналогично методу Прочитать(). /// - /// [ContextMethod("Пропустить", "Skip")] public bool Skip() { @@ -287,29 +278,22 @@ public bool Skip() /// /// Выполняет чтение значения JSON. /// - /// [ContextMethod("Прочитать", "Read")] public bool Read() { CheckIfOpen(); return _reader.Read(); - } /// - /// /// Устанавливает строку, содержащую текст JSON для чтения данным объектом. Если перед вызовом данного метода уже производилось чтение JSON из другого файла или строки, то чтение прекращается и объект инициализируется для чтения из указанной строки. /// - /// /// /// Строка, содержащая текст в формате JSON. - /// - /// [ContextMethod("УстановитьСтроку", "SetString")] public void SetString(string JSONString) { - if (IsOpen()) - Close(); + Close(); _reader = new JsonReaderInternal(new StringReader(JSONString)) { diff --git a/tests/json/test-json_reader.os b/tests/json/test-json_reader.os index a3e98504a..fdc3b5dc5 100644 --- a/tests/json/test-json_reader.os +++ b/tests/json/test-json_reader.os @@ -24,6 +24,10 @@ СписокТестов.Добавить("Тест_Должен_ПроверитьПропускНезавершенногоМассива"); СписокТестов.Добавить("Тест_Должен_ПроверитьПропускМассиваСВложенными"); СписокТестов.Добавить("Тест_Должен_ПроверитьПропускОбъектаСВложениями"); + + СписокТестов.Добавить("Тест_Должен_ПроверитьОткрытиеПотока"); + СписокТестов.Добавить("Тест_Должен_ПроверитьПовторноеОткрытиеПотока"); + СписокТестов.Добавить("Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытияЧтения"); Возврат СписокТестов; КонецФункции @@ -219,3 +223,36 @@ юТест.ПроверитьРавенство(ТипЗначенияJSON.Число, Чтение.ТипТекущегоЗначения); юТест.ПроверитьРавенство(5, Чтение.ТекущееЗначение); КонецПроцедуры + +Процедура Тест_Должен_ПроверитьОткрытиеПотока() Экспорт + БДД = ПолучитьБуферДвоичныхДанныхИзСтроки("{""ответ"":42}"); + Поток = Новый ПотокВПамяти(БДД); + Чтение = Новый ЧтениеJSON; + Чтение.ОткрытьПоток(Поток); + Json = ПрочитатьJSON(Чтение); + + юТест.ПроверитьРавенство(42, Json.Ответ); +КонецПроцедуры + +Процедура Тест_Должен_ПроверитьПовторноеОткрытиеПотока() Экспорт + БДД = ПолучитьБуферДвоичныхДанныхИзСтроки("{""ответ"":42}"); + Поток = Новый ПотокВПамяти(БДД); + Чтение = Новый ЧтениеJSON; + Чтение.ОткрытьПоток(Поток); + Чтение.ОткрытьПоток(Поток); // повторно + Json = ПрочитатьJSON(Чтение); + + юТест.ПроверитьРавенство(42, Json.Ответ); +КонецПроцедуры + +Процедура Тест_Должен_ПроверитьСохранениеПотокаПослеЗакрытияЧтения() Экспорт + БДД = ПолучитьБуферДвоичныхДанныхИзСтроки("{""ответ"":42}"); + Поток = Новый ПотокВПамяти(БДД); + Чтение = Новый ЧтениеJSON; + Чтение.ОткрытьПоток(Поток); + Чтение.Закрыть(); + Чтение.ОткрытьПоток(Поток); // Поток должен остаться открытым + Json = ПрочитатьJSON(Чтение); + + юТест.ПроверитьРавенство(42, Json.Ответ); +КонецПроцедуры