Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Lazarus: построчное чтение данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Мужики,
понадобилось читать и писать вывод запускаемой внешней программы (примерно как в этом примере) в наследник TStrings построчно, а не прочтенными блоками. Причем чтение должно осуществляться из пополняемого в это время контейнера/памяти (а не как в выше приведенном примере, после окончания отработки внешней программы).

Подскажите, плз, в каком направлении двигаться? Может ссылки на материал, который можно почитать?
=================
Док.

Win7 Ultim x64/Deb 10 (MATE; gtk3) amd64:
FB 3.0.4.33054, Lazarus 2.1(r.61313); FPC 3.3.1 (r.42151), IBX by -Rik-
2 сен 19, 17:32    [21962076]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Док,

Так в примере же есть поблочное чтение. Остаётся только найти окончание строки и скопировать её. Если читаешь на виндах, то вывод необходимо сначала перекодировать OemToAnsi.
2 сен 19, 17:46    [21962082]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Kazantsev Alexey
Так в примере же есть поблочное чтение.

в примере все телодвижения начинаются лишь после того, как запись в память закончена, а мне бы понять, как из постоянно пополняемого MemoryStream читать и парсить строки. Пока не догоняю...
2 сен 19, 18:38    [21962107]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Док,

Вот там чтение блока:
BytesRead := AProcess.Output.Read(Buffer, BUF_SIZE);

Блок прочитал, ищи конец строки. Не нашёл, складывай данные в накопительный буффер. Нашёл - клади часть данных до маркера новой строки в накопительный буффер и конвертируй накопительный буффер в строку. Накопительный буффер сделай строковым:
type
 OEMString = type AnsiString(CP_OEMCP);
var
 accBfr : OEMString;

Потом строку получишь приведением типа: string(accBuf);
2 сен 19, 18:50    [21962114]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
+ Моя процедура выделения строки. Для дельфей.
//
Procedure TBuilder.ParseDccOutput(Const ABuffer; ACount : Integer);
Var

 CPos       : MarshaledAString; // PAnsiChar;
 Index      : Integer;
 StartIndex : Integer;

 //
 Procedure _AccBuffer(AIndex : Integer);
 Var

  IncSize : Integer;
  OldSize : Integer;

 Begin

  IncSize := AIndex - StartIndex;

  If IncSize > 0 Then
   Begin

    OldSize := Length(FBuffer);
    SetLength(FBuffer, OldSize + IncSize);

    CopyMem(PByte(@ABuffer) + StartIndex, PByte(FBuffer) + OldSize, IncSize);

   End;

  StartIndex := AIndex + 1;

 End;
 //

 //
 Procedure _ProcessLine;
 Begin

  _AccBuffer(Index);

  Try

   ProcessDccLine(String(FBuffer)); // Твоя обработка готовой строки

  Finally

   FBuffer := ''; // тот самый накопительный буфер

  End;

 End;
 //

Begin

 CPos       := @ABuffer;
 Index      := 0;
 StartIndex := 0;

 For Index := 0 To ACount - 1 Do
  Begin

   Case CPos[Index] Of

    #10 : Begin

           If FLastChar = 13 Then
            Inc(StartIndex)
           Else
            _ProcessLine;

          End;

    #13 : _ProcessLine;

   End;

   FLastChar := Ord(CPos[Index]); // FLastChar : Byte;

  End;

 _AccBuffer(ACount);

End;
//
2 сен 19, 18:57    [21962119]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Kazantsev Alexey,

спасибо, смотрю...
2 сен 19, 20:36    [21962141]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
stanilar
Member

Откуда: Спб
Сообщений: 847
Memory Mapped File

Вроде как даже рекомендованный способ совместного доступа к одному файлу. Или он базируется на нем.

В свое время накатал исходник по расширению менеджера памяти для датасета. Собирался к лазарю прикрутить... Но вот времени не было сделать, а теперь уже бывший дельфиец...
3 сен 19, 16:42    [21962682]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Василий 2
Member

Откуда:
Сообщений: 746
Есть же TStringReader
4 сен 19, 10:14    [21963034]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
vavan
Member

Откуда: Казань
Сообщений: 3386
stanilar
расширению менеджера памяти для датасета
не поясните о чем речь?
4 сен 19, 10:36    [21963055]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5194
Док,

обычно автомат делают

несмотря на всю теорию, на практике в простейших случаях как этот, это обычно набор Case в которых происходит установка текущего состояния

у вас ещё и под разные платформы, так что стоит сразу заложиться на все возможные разделители #13, #10, #10#13


если номер строчки неважен, то можно считать любой из символов #13 или #10 разделителем и если аддитивный буфер непустой считать его новой строкой
4 сен 19, 11:08    [21963097]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Vizit0r
Member

Откуда: Одесса
Сообщений: 661
kealon(Ruslan)
у вас ещё и под разные платформы, так что стоит сразу заложиться на все возможные разделители #13, #10, #10#13


sLineBreak же.
4 сен 19, 11:34    [21963141]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
kealon(Ruslan)
Member

Откуда: Нижневартовск
Сообщений: 5194
Vizit0r,

даже мелкомягкие иногда просто #13 или #10 скидывают, и такие сбои нужно обрабатывать корректно
4 сен 19, 11:40    [21963160]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
kealon(Ruslan)
стоит сразу заложиться на все возможные разделители #13, #10, #10#13

В моём варианте, как раз, поддерживается #10, #13, #13#10.
4 сен 19, 11:51    [21963188]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Kazantsev Alexey,

спасибо за пинок в нужном направлении. Правда, для простоты я реализовал через строки, а не через указатели (скорость выполнения дял меня не критична, в моих задачах не планируется длинный вывод). Выглядит примерно так (пояснения в тексте для себя-склеротика и нубов, которые будут читать код после меня. "Лишние" переменные остались после отладки, в итоговом коде почищу)

+
procedure TForm1.btnGoClick(Sender: TObject);
{$IFDEF MSWINDOWS}
type
  WinCpString = type AnsiString(CP_ACP);//uses LConvEncoding
{$ENDIF}
const
  BUF_SIZE = 1024*2; // Размер буфера для чтения выходных данных блоками
var
  {$IFDEF MSWINDOWS}
  Buffer: WinCpString = '';
  {$ELSE}
  Buffer: string = '';
  {$ENDIF}

  DebugStr: String = '';//отладочная строка
  BufferStr: String = '';//буфер-накопитель
  BytesRead: LongInt = 0;//кол-во считанных из буфера байт
  LineEndingPos: Integer = 0;//позиция начала перевода строки
  StrPartLineEndingAhead //часть строки до LineEnding
  , StrPartLineEndingBehind //часть строки после LineEnding
                :String;
  StrCounter: Integer = 0;//счетчик выводимых memoOutput строк
begin
  memoOutput.Clear;

  {$IFDEF MSWINDOWS}
  // В Windows команду dir нельзя использовать напрямую, потому что она является встроенной
  // командой оболочки. Поэтому нужны cmd.exe и дополнительные параметры
  AProcess.Executable := 'c:\windows\system32\cmd.exe';
  AProcess.Parameters.Add('/c');
  AProcess.Parameters.Add('dir /s c:\Windows\System32\drivers');
  {$ENDIF}
  {$IFDEF UNIX}
  AProcess.Executable := '/bin/ls';
  AProcess.Parameters.Add('--recursive');
  AProcess.Parameters.Add('--all');
  AProcess.Parameters.Add('-l');
  {$ENDIF}

  AProcess.Options := [poUsePipes, poStderrToOutPut, poNoConsole];

  //Запуск процесса (выполнение команды dir/ls)
  AProcess.Execute;

  StrPartLineEndingAhead:= '';
  StrPartLineEndingBehind:= '';
  repeat
    memoOutput.Lines.BeginUpdate;
    try
      SetLength(Buffer,BUF_SIZE);//задаем минимальный размер Buffer (как правило размер Pipes в ОС не превышает 2kB)
      BytesRead := AProcess.Output.Read(Buffer[1],Length(Buffer));//читаем в Buffer и получаем кол-во считанных байт BytesRead;
      if BytesRead > 0
      then
        begin
          SetLength(Buffer,BytesRead);
          DebugStr:= CP1251ToUTF8(Buffer);//uses LConvEncoding

          {LineEnding - алиас для sLineBreak:
          Win = #13#10
          Unix = #10
          Mac OS до v.9 = #13}

          //получаем позицию LineEnding в строке
          LineEndingPos:= UTF8Pos(LineEnding,CP1251ToUTF8(Buffer)); //uses LazUTF8

          if LineEndingPos > 0
          then
            repeat
              if LineEndingPos = 1 //LineEnding в начале строки
              then
                begin
                  StrPartLineEndingAhead:= UTF8Copy(DebugStr,1, UTF8Length(LineEnding));//по сути присвоим пустую строку ''
                  Inc(StrCounter);
                  memoOutput.Lines.Add(Format('%d.',[StrCounter]));//добавляем в memoOutput пустую строку
                end
              else //LineEnding не в начале строки
                begin
                  StrPartLineEndingAhead:= UTF8Copy(DebugStr,1, LineEndingPos - 1);//захватываем часть строки до LineEndingPos;
                  BufferStr:= BufferStr + StrPartLineEndingAhead;// добавляем к строке-буферу захваченный до LineEnding текст
                  Inc(StrCounter);
                  memoOutput.Lines.Add(Format('%d. %s',[StrCounter, BufferStr]));//пишем буфер-накопитель в memoOutput
                  BufferStr:= '';//и "обнуляем" его для следующей итерации
                end;

              //захватываем оставшуюся часть строки после LineEndingPos без символов LineEnding
              StrPartLineEndingBehind:= UTF8Copy(DebugStr,LineEndingPos + UTF8Length(LineEnding), UTF8Length(DebugStr));

              DebugStr:= StrPartLineEndingBehind;
              LineEndingPos:= UTF8Pos(LineEnding,DebugStr);
            until LineEndingPos = 0
          else //LineEnding в DebugStr отсутствует 
            begin
             BufferStr:= BufferStr + DebugStr;
             Inc(StrCounter);
             memoOutput.Lines.Add(Format('%d. %s',[StrCounter, BufferStr]));//пишем строку-буфер в memoOutput
            end;
        end;
    finally
      memoOutput.Lines.EndUpdate;
      memoOutput.SelStart := UTF8Length(memoOutput.Text);
    end;
    Sleep(10);
    Application.ProcessMessages;
  until BytesRead = 0;
end;      

Возможно, есть ошибки в коде. Если найду, поправлю.

К сообщению приложен файл. Размер - 34Kb
4 сен 19, 12:07    [21963222]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Док,

Хапнешь горя, когда дефотные строки перестанут быть байтовыми.
4 сен 19, 12:54    [21963322]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30502

кстати, не помешает наверное ещё и по таймауту забирать то, что ещё не завершено #10, #13, #13#10.

Posted via ActualForum NNTP Server 1.5

4 сен 19, 13:05    [21963340]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Kazantsev Alexey
Хапнешь горя, когда дефолтные строки перестанут быть байтовыми.

можно подробнее, о каких строках речь и какими они станут? НЕ ОДНОбайтовыми, ты имеешь ввиду?

Мимопроходящий
кстати, не помешает наверное ещё и по таймауту забирать то, что ещё не завершено #10, #13, #13#10

не совсем догнал - где?
4 сен 19, 14:25    [21963464]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Док
можно подробнее, о каких строках речь и какими они станут? НЕ ОДНОбайтовыми, ты имеешь ввиду?

О дефолтном String, он будет юникодовым в ближайшей перспективе.
4 сен 19, 15:09    [21963531]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30502

04.09.2019 15:09, Kazantsev Alexey пишет:
> О дефолтном String, он будет юникодовым в ближайшей перспективе.

в Лазаре utf8.
а Док на нём и сидит.

Posted via ActualForum NNTP Server 1.5

4 сен 19, 15:40    [21963586]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30502

04.09.2019 14:25, Док пишет:

МП>> кстати, не помешает наверное ещё и по таймауту забирать то, что ещё не завершено #10, #13, #13#10
> не совсем догнал - где?

если я правильно понял твою задачу, ты тащишь данные, которые процесс вываливает в консоль по "трубе".
может так случиться, что ты получил из "трубы" последовательность, которая не заканчивается #10, #13, #13#10
а процесс, который ты отслеживаешь, ничего больше не шлёт (пока).
в этом случае ты этого кусочка можешь ждать ооооооочень долго...

Posted via ActualForum NNTP Server 1.5

4 сен 19, 15:45    [21963594]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Мимопроходящий,

Строковый тип определяется не лазарем, а в фпц он скоро будет юникодовым по дефолту.
4 сен 19, 15:49    [21963599]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
Кстати, уже и лазарь готовится к utf-16.
4 сен 19, 15:58    [21963615]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Kazantsev Alexey
Member

Откуда:
Сообщений: 3794
The goal of FPC project is [/b]to create a Delphi compatible UnicodeString (UTF-16) based solution[/b], but it is not ready yet. It may take some time to be ready.

This UTF-8 solution of LCL in its current form can be considered temporary. In the future, when FPC supports UnicodeString fully in RTL and FCL, Lazarus project will provide a solution for LCL that uses it. At the same time the goal is to preserve UTF-8 support although it may require changes to string types or something. Nobody know the details yet. We will tell when we know...

In essence LCL will probably have 2 versions, one for UTF-8 and one for UTF-16.


Так что, использование конкретизированного строкового типа не просто доброе пожелание, это маст хэв.
4 сен 19, 16:02    [21963621]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 30502

дважды дибилы!

Posted via ActualForum NNTP Server 1.5

4 сен 19, 16:08    [21963630]     Ответить | Цитировать Сообщить модератору
 Re: Посоветуйте с построчным чтением данных из памяти  [new]
Док
Member

Откуда: Казань
Сообщений: 6420
Мимопроходящий
может так случиться, что ты получил из "трубы" последовательность, которая не заканчивается #10, #13, #13#10

так я в коде вроде бы учел этот момент. Нет?
+
          if LineEndingPos > 0
          then
            repeat
            <skiped>
            until LineEndingPos = 0
          else //LineEnding в DebugStr отсутствует 
            begin

Не уверен, но repeat..until в операторные скобки заключать же не надо?

зы. вообще, я пишу для себя кроссплатформенную утилитку с использованием gbak/gfix/gstat/isql - покатаю код еще там...

Kazantsev Alexey
Так что, использование конкретизированного строкового типа не просто доброе пожелание, это маст хэв.

если я правильно тебя понял, все упирается в то, какого типа строка в фпц на момент сборки кода.

Ну дык я же везде повтыкал UTF8-аналоги функций работы со строками, которые корректно работают как с UTF8, так и с ansi. Наверняка, в момент перехода на utf16 окончательно обновятся и аналогичные UTF16-функции, которые (весьма вероятно) будут корректно работать со всеми ansi/utf8/utf16 строками. Вся беда в том, что
автор
...Nobody know the details yet. We will tell when we know...


Или я не так тебя понял и опять чего-то не догоняю?

ps. надеюсь #13 и #10 при любой погоде остануться однобайтными Картинка с другого сайта.. Иначе придется, как в Дельфях, из CodePointSize/UTF8CodepointSize городить огород.
4 сен 19, 16:34    [21963654]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить