PDA

Просмотр полной версии : Работа с текстовым файлом, обработка строк



ShikuS
11.12.2023, 01:28
Здравствуйте!

Пожалуйста, подскажите, как правильно можно работать с файлом (и с процессом в общем) в следующей ситуации, возможно можно пойти иным путем, но пока вижу так:
При работе условного цикла пошагово проводится запись строковых параметров в текстовый файл, примерно так:


№ t[ч:м:с] t[м:с] P[мбар] T[°C]
3 ВАКУУМ
00:01:14 00:28 79 41.4
4 ПОДАЧА
00:01:58 00:43 1151 103.7
...



Процесс идет следующим образом:
1. При возникновении условий происходит запись строки в файл - Выполняется SysFile.SysFileWrite
2. В окне Текстовый редактор (режим чтения) открывается записанный файл для отображения шагов программы
3. При добавлении записи в файл, для обновления строк в Текстовом редакторе проводится закрытие и открытие файла и перевод курсора на конец файла

По окончании процесса файл TXT становится файлом отчета, который в последующем можно прочитать и при желании провести распечатку.

Каким образом после чтения файла текст можно разделить на строки для последующей раздельной обработки построчно (в частности будет производиться печать на POS принтере)?
Возможно ли отобразить текст из файла в текстовом поле и обновлять его в ходе процесса?


Спасибо,

Евгений Кислов
11.12.2023, 11:47
Добрый день.


Каким образом после чтения файла текст можно разделить на строки для последующей раздельной обработки построчно

Например - с помощью функции SplitStringByToken из библиотеки OwenStringUtils (или WSplitStringByToken, если вы используете WSTRING) - при условии, что у строк есть какой-то разделитель (например, символы переноса строк \r\n и т.п.).


Возможно ли отобразить текст из файла в текстовом поле и обновлять его в ходе процесса?

Возможно.

Cs-Cs
11.12.2023, 11:47
Хм. Ну на VC++ я писал когда-то чтение из байтового потока данных (не из файла).
Новые строки отслеживал по символам 0x10 и 0x13 (в си это "\r\n") - это символы CR, LF (возврат курсора на начало строки и создание новой строки). Эти символы могут встретиться оба, а могут по отдельности. Я записывал данные сам и всегда сам ставил их два.
Вот мой кривой код времён 2003 года:

//Читает строку из потока IStream - до символов \r\n
HRESULT ReadLineFromStream(IStream *pStm, CString *pLine)
{
//algorithm: read by char to combination "\r\n" or to eof
ASSERT(pStm!=NULL); //Check pointer

DWORD pw=1; //initial value
CString tmpS,tmpBuf;
LPSTR buf;
HRESULT hr=S_OK; //initial value

buf=new char[1]; //allocate bufer

//read symbols from stream
while ((hr==S_OK) && (pw))
{
hr=pStm->Read(buf,1,&pw); //get n-char line
tmpBuf=buf;
tmpBuf=tmpBuf.Left(pw); //get a physical n-char string

tmpS+=tmpBuf;

//check new line symbols
if(strcmp(tmpS.Right(2),_T("\r\n"))==0)
{
tmpS=tmpS.Left(tmpS.GetLength()-2);
hr=S_FALSE; //read complete
}
}
*pLine=tmpS; //return result
delete buf; //delete buffer
return true;
}

ShikuS
11.12.2023, 14:44
Евгений Кислов, Cs-Cs

Спасибо,

Как я понимаю, при считывании текста из файла, мы берем его из буфера и обрабатываем уже, как считаем нужным.
При формировании и записи файла, перенос строк проводился посредствам $N, но уже в сформированном файле как таковых символов \r\n нет, т.е., вероятно, нужно в конце каждой строки делать какой то разделитель

Попробую разобраться, спасибо,

Cs-Cs
11.12.2023, 14:55
Нет, не до конца так: как раз вот "$N" внутри файла превращается или в 0x0D, 0x0A или только в 0x0D или только в 0x0A (надо посмотреть сам файл).
Просто в программе эти символы перевода строки не ввести так просто (они не печатные) и, чтобы не париться, разработчики сред разработки выдумывают их заполнители. У кого-то - $N, у кого-то \r\n, у кого-то только \n. В реальном файле будут переводы строк. И это тоже символы.
Вот, показываю тестовый файл в двоичном виде и стрелками эти символы.
72298

ShikuS
11.12.2023, 15:07
Cs-Cs,

Спасибо, все понял о чем идет речь

Cs-Cs
11.12.2023, 15:13
Ага, вот (иногда мне самому сложно подобрать слова, чтобы пояснить).
Эти самые 0x0A и будут нужными разделителями строк.

ShikuS
12.12.2023, 16:31
Добрый день!

В продолжении темы.

1. Использование Текстового редактора:
Логику отрабатывает хорошо), за исключением того, что не отображает кириллицу.
Возможно ли исправить ситуацию, т.е. возможность отображения в Текстовом редакторе кириллицы?
Сейчас строки в файл сохраняются как STRING, может быть все сохранять в WSTRING и тогда проблем быть не должно, но в последующем для вывода на принтер снова преобразовывать...
А можно ли сохранить файл из WSTRING. Библиотека FileSys ругается и просит предварительно преобразовать в строку UTF-8, но при этом сохраняются кракозябры

2. Также рассмотрел вариант отображения в текстовом поле, но столкнулся с ограничением STRING 255 символов и при переводе в WSTRING, наверное, также будут ограничения. А какое ограничение символов WSTRING?
Но этот путь несколько неправильный, т.к. возможный текст может иметь много строк, которые не смогут вместиться в текстовое поле и придется придумывать стрелки вниз/вверх для перелистывания или сдвигания текста в поле, а это отдельный код. Т.е. смотрю в сторону Текстового редактора

Cs-Cs
12.12.2023, 17:52
...так может всё же вести текстовый лог отдельно, а на экране - отдельно?

ShikuS
12.12.2023, 18:23
Cs-Cs,

Похоже, когда все идеи иссякнут, то что то придется придумывать, но хочется сделать универсальность, а не получается.

...так может всё же вести текстовый лог отдельно, а на экране - отдельно?
Так сделать можно, если в онлайн будет, как я предполагаю: вывод в текстовое поле лога WSTRING, будет идет печать на POS и отдельно запись в файл.
Другой вопрос, что WSTRING 255 символов. Даже есть где-то возможность преобразования в более длинные тексты, но с учетом многострочности, также придется продумывать некий код для перемотки вперед назад.
Далее - файл - это история для хранения и возможности распечатки в дальнейшем, т.е. файл мне все равно нужно сохранять для последующего просмотра и печати и в таком случае мы возвращаемся к вопросу отображения, но вести текстовый лог уже не сможем, т.к. все данные нужно тянуть из файла.(или шаблон текста заводить отдельно и отдельно параметры)

Сейчас имеем:
При записи файла через библиотеку SYSFILE получаем кодировку UTF-8, при которой текст не отображается в нормальном виде при открытии файла ни в блоке Текстового редактора, ни при отображении в текстовом поле. Хотя вытягивал из файла текст 255 символов в текстовое поле, переводил через CP1251_TO_UNICODE в WSTRING и было все хорошо. но только 255 символов

Т.е. технически сохранять в файл UTF-8 кириллицу и когда требуется, вытягивать, условно +-2000 символов, преобразовывать в WSTRING, отображать и печатать...как костыль - можно.
С другой стороны POS принтер печатает кириллицу при этом хорошо, с UTF-16 пока пробовал 1 раз, не очень с наката получилось...вернее пока не получилось).

Текстовый редактор может сохранять файлы с UTF-16, проверено. Может быть попробовать создавать файл из Текстового редактора и дозаписывать его вставкой текста, однако не вижу переменной/или функции вставки текста в редактор или через буфер...как то все усложняется..думаю есть способ легче, найти бы его)

Может быть @Евгений Кислов или кто о еще имел опыт с подобным

Евгений Кислов
12.12.2023, 18:51
Может быть @Евгений Кислов или кто о еще имел опыт с подобным

Сформулируйте, пожалуйста, конкретные вопросы, которые у вас остались к данному моменту (и которые будут заканчиваться знаком вопроса).

ShikuS
12.12.2023, 20:06
Евгений Кислов,

1. Имеются ли какие-либо библиотеки/скрипты или иные способы записи текстового файла в кодировке UTF-16, что бы имелась возможность записи WSTRING переменных, или преобразование текстовых файлов из UTF-8 в UTF-16 внутренними ресурсами CODESYS?
2. Имеется ли возможность чтения и присваивания переменной STRING/WSTRING (или группе переменных) более 255 символов? Если да, то можно ли найти где либо пример реализации данного процесса?
3. Если отсутствует возможность записи файлов формата UTF16, возможно ли реализовать условный "scroll bar" для возможности перелистывания текста в текстовом поле, если весь не уместится? Если возможно примеры реализации или укажите с какой стороны начать копать

Спасибо,

Евгений Кислов
12.12.2023, 20:25
Евгений Кислов,

1. Имеются ли какие-либо библиотеки/скрипты или иные способы записи текстового файла в кодировке UTF-16, что бы имелась возможность записи WSTRING переменных, или преобразование текстовых файлов из UTF-8 в UTF-16 внутренними ресурсами CODESYS?
2. Имеется ли возможность чтения и присваивания переменной STRING/WSTRING (или группе переменных) более 255 символов? Если да, то можно ли найти где либо пример реализации данного процесса?
3. Если отсутствует возможность записи файлов формата UTF16, возможно ли реализовать условный "scroll bar" для возможности перелистывания текста в текстовом поле, если весь не уместится? Если возможно примеры реализации или укажите с какой стороны начать копать

Спасибо,

1.
1.1. Да. Функции и ФБ записи в файл принимают на вход указатель на записываемые данные - непринципиально, что именно расположено по этому указателю.
1.2. Да. См. библиотеку CmpSysExec, которая позволяет вызывать утилиты Linux, и утилиту iconv, которая позволяет изменять кодировку файлов.
https://linux.die.net/man/1/iconv

2. Да. Ограничение в 255 символов не связано с типами STRING/WSTRING - это ограничение библиотек Standard/Standard64.
См. библиотеку StringUtils, которая позволяет работать со строками любых размеров.
https://content.helpme-codesys.com/en/libs/StringUtils/Current/Public-Parts/fld-Public-Parts.html

Cs-Cs
13.12.2023, 10:05
...ну, можно:
* Закосить под ДРЕГ СКАЛА (это я опять тут про Чернобыль начитываюсь, ахахх - там ДРЕГ выдавала логи действий АЭС на принтер) и выводить лог на принтер онлайн
* Писать его же в файл онлайн (добавили строку в конец файла и всё)
* Загружать его в массив или какой-то список объектов и выводить в таблицу на визуализации построчно.

ShikuS
13.12.2023, 14:56
Евгений Кислов,

Спасибо за ответы..

Нашел почему были иероглифы, сейчас выполнил так:




wsByteOrderMark[0] := 16#FEFF;

hFile:=SysFile.SysFileOpen(strFileName, am := sysfile.AM_APPEND_PLUS, ADR(udiFileErrorCode));
wPrintLine:=WCONCAT( wsByteOrderMark," ");

wPrintLine:=WCONCAT("Версия ПО: ", OSU.CP1251_TO_UNICODE(sSterPV));
wPrintLine:=WCONCAT(wPrintLine, "$N");
SysFile.SysFileWrite(hFile, ADR(wPrintLine), 2*TO_DWORD(WLEN(wPrintLine)), ADR(udiFileErrorCode));
SysFile.SysFileClose(hFile);


Оказывается очень важно:
1. Добавить к файлу маркер кодировки (UTF16 BE) в моем случае 16#FEFF
2. Указывать 2*TO_DWORD в размере, иначе обрубает строку, а также нужно WSTRING(40)- указать длину, иначе также становится непонятное форматирование, сохранение в нужном формате.

Таким образом отделался малой кровью)

Евгений Кислов, Cs-Cs,

Спасибо огромное!

Cs-Cs
13.12.2023, 17:15
Пожалуйста! ^_^

Евгений Кислов
13.12.2023, 19:15
Оказывается очень важно:
1. Добавить к файлу маркер кодировки (UTF16 BE) в моем случае 16#FEFF
2. Указывать 2*TO_DWORD в размере, иначе обрубает строку, а также нужно WSTRING(40)- указать длину, иначе также становится непонятное форматирование, сохранение в нужном формате.



...именно поэтому об этом написано в документе по работе с файлами в п. 6.2. ("Сохранение текстовых файлов в кодировке Unicode")
https://ftp.owen.ru/CoDeSys3/11_Documentation/03_3.5.11.5/CDSv3.5_Archives_v3.0.pdf

Рад, что у вас всё получилось.