Вход

Просмотр полной версии : Всё-таки как правильно работать с файлами?



Андрей Шатохин
12.02.2016, 22:37
Коллеги!

http://forum-ru.codesys.com/viewtopic.php?t=850 здесь рекомендуют выполнять не больше одной операции с файлом за один цикл работы ПЛК.

Так ли это критично?

Yegor
13.02.2016, 08:26
Вот этот кусок важен:
Функции эти имеют несложные параметры, но при их использовании надо учесть, что реакция системы контроллера на каждую команду (вызов функции) может быть больше времени перехода от одной команды к другой. т.е. Функции не блокирующиеЯ не находил подтверждения тому, что это неблокирующие функции. Да и существование библиотеки SysLibFileAsync (в противоположность обсуждаемой SysLibFile) говорит об обратном. Вообще было бы очень странно, если б та же SysFileOpen возвращала дескриптор преждевременно (откуда она его взяла тогда?) или SysFileRead возвращала число прочитанных байт до того, как система их прочитала.

Может, подробнее расскажете о своей задаче для более предметного разговора?

Андрей Шатохин
13.02.2016, 09:55
Всё началось с того момента как сели батарейки на ПЛК-110 и я озадачился сохранением ритэйнов в файлах......

Ритэйнов не мало, чуть меньше 512 байт. Сохраняю часто - по изменению, при активном использовании объекта периодичность - 2,5 сек.
И похоже я начал совершать все возможные ошибки при работе с файлами.
Причем ошибки фатальные, чуть что не так - ПЛК уходит в перезагрузку по срабатыванию исключения. Оказалось исключения это не только вотчдог, к перезагрузке могут приводить и косяки при работе с файлами, к примеру закрытие закрытого файла. Вот так. Причем ПЛК из этого дохлого цикла перезагрузок не возвращается. И в ряде случаев пришлось прошивать сам ПЛК. У меня в проекте есть объект button, поэтому остановить выполнение проекта не всегда получается (но иногда кстати получается, что тоже странно).

Напоролся уже на такое явление - нельзя злоупотреблять удалением файлов. Я без всякой задней мысли каждый раз удалял файл перед сохранением ритэйна, а это до 40-50 тыс раз в сутки. Это привело к тому (это мне уже в техподдержке овен пояснили), что в файловой системе ПЛК увеличивается какой-то счетчик, причем при создании следующего файла файловая система пробегает этот весь диапазон до текущего значения счетчика и чего-то там проверяет, а это может подвесить ПЛК более чем на допустимый для выполнения шага контроллера интервал и вызвать срабатывание вотчдога. Это я уже прошёл. Что я не прошёл ещё?????

По-поэтому вопрос корректной работы с файлами для меня очень важен,
вот я и занялся изучением чего я ещё не знаю о работе с файлами, всякие возможные и невероятные версии =)

Подскажите где ещё можно напороться с файлами? Пока не было траблов с ритейнами проект был стабилен....
Проект показать не могу.... чисто гипотетически , что НЕЛЬЗЯ ДЕЛАТЬ С ФАЙЛАМИ?????

Дмитрий Артюховский
13.02.2016, 10:49
Основная проблема - что да, нельзя удалять файлы, ибо они реально не удаляются! (после каждого удаления у вас в каталоге на один файл больше и когда-то наступает краш каталога) это, скажем так, особенность реализации файловой системы с контролем количества перезаписей блоков флэша.

Файл нужно перезаписывать! Открываете файл с именем "my_ret" (ну или че фантазия подскажет), позиционируете на ноль и пишите свои данные, закрываете файл. Далее ОС разберется. Ну и надо выделять время на физическую запись - цикл open, pos, write, close - можно выполнить в одном цикле ПЛК, затем нужно запретить повторную перезапись на некоторое время (ну хотя бы на 50-100мс). И наступит счастье.

модификатор "wr" не поддерживается. Ну вроде все, но при такой интенсивной перезаписи имеет смысл думать о внешней флэшке, ну и с нетерпением ждать "новый" плк110 - там другой тип памяти, лишенный существующих недостатков )))

Андрей Шатохин
13.02.2016, 11:07
1. Внешняя флэшка это аддон к плк или по сети как-нить мутить?
2. А можно допускать выполнение команды удаления файла которого нет (пока нет - это стартовый нюанс)?
3. Можно спрашивать длину файла которого нет (пока нет - это стартовый нюанс)?
4. Ниже мой код про ритэйны, там уже нет удаления каждый раз. Но справедливости ради нужно сказать, что в той версии что сейчас повесила мои два ПЛК не было условия sfo > 0 (это я уже сейчас добавил). Это может приводить к исключениям? Может ли операционка ПЛК по каким-либо своим причинам не давать ссылку на файл после выполнения SysFileOpen (я такого ни разу не видел просто)? Ведь если это не проверять получится что я буду делать SysFileClose с сылкой на файл 0, а это уже приведёт к исключению и перезагрузке ПЛК. Так ведь?




Вот так я пишу свой ритэйн


FUNCTION save_main_retain : BOOL
VAR_INPUT
END_VAR
VAR
sfo: DWORD;
sfw: DWORD;
sfc: BOOL;
size: DWORD;
END_VAR

sfo:=SysFileOpen('retain_file','w');
IF sfo > 0 THEN
sfw:=SysFileWrite(sfo, ADR(b), SIZEOF(b));
sfw:=SysFileWrite(sfo, ADR(m), SIZEOF(m));
sfw:=SysFileWrite(sfo, ADR(dta), SIZEOF(dta));
sfw:=SysFileWrite(sfo, ADR(c), SIZEOF(c));
sfw:=SysFileWrite(sfo, ADR(sta), SIZEOF(sta));
sfw:=SysFileWrite(sfo, ADR(cl), SIZEOF(cl));
sfw:=SysFileWrite(sfo, ADR(ers), SIZEOF(ers));
sfw:=SysFileWrite(sfo, ADR(mst), SIZEOF(mst));
sfc:=SysFileClose(sfo);
retain_cnt:=retain_cnt+1;
END_IF;
RETURN;



во так я его читаю


FUNCTION init_main_retain : BOOL
VAR_INPUT
END_VAR
VAR
sfo: DWORD;
sfc: BOOL;
sfgs: DWORD;
size: DWORD;
END_VAR
sfgs:=SysFileGetSize('retain_file');
IF (sfgs = SIZEOF(b)+SIZEOF(m)+SIZEOF(dta)+SIZEOF(c)+
SIZEOF(sta)+SIZEOF(cl)+SIZEOF(ers)+SIZEOF(mst))
THEN
sfo:=SysFileOpen('retain_file','r');
IF sfo > 0 THEN
SysFileRead(sfo, ADR(b), SIZEOF(b));
SysFileRead(sfo, ADR(m), SIZEOF(m)); m_:=m;
SysFileRead(sfo, ADR(dta), SIZEOF(dta)); dta_:=dta;
SysFileRead(sfo, ADR(c), SIZEOF(c)); c_:=c;
SysFileRead(sfo, ADR(sta), SIZEOF(sta));
SysFileRead(sfo, ADR(cl), SIZEOF(cl)); cl_:=cl;
SysFileRead(sfo, ADR(ers), SIZEOF(ers));
SysFileRead(sfo, ADR(mst), SIZEOF(mst)); mst_:=mst;
sfc:=SysFileClose(sfo);
END_IF;
ELSE
SysFileDelete('retain_file');
init_microstat();
init_costs();
init_config();
init_client();
init_inkass();
b.block_to_counter:=0;
b.FLAG_POST_BLOCKED := FALSE;
calc_event_request(8);
END_IF

RETURN;

Андрей Шатохин
13.02.2016, 11:15
И похоже у меня на старте возможен вариант когда к одному и тому же файлу за один цикл ПЛК возможен многократная операция open, write, close. Это сильно плохо? Разнести их по времени?

amn
13.02.2016, 11:35
Чтобы узнать есть файл или нет надо попробовать его открыть. Если дескриптор равен нулю, то файла нет и работать с ним нет смысла.
За один цикл только одна операция с файлом.
Чтение и запись может занять несколько циклов (зависит от размера файла).
Узнать окончание записи или чтения можно по количеству реально записанных (прочитанных) байт, которые возвращает функция.
Пока не закончится одна операция с файлом к другой не переходить.

Андрей Шатохин
13.02.2016, 12:11
у меня считываются несколько структур, т.е. мне следует сначала считать весь файл в несколько заходов, если это потребуется, в некоторый буфер, а уже из него раскидать данные по структурам, так получается? жеееееесть.....

amn
13.02.2016, 12:48
Что мешает в качестве буфера использовать ФБ. В этот ФБ копируете все свои структуры, после чего задаете его параметром для функции записи. То же самое при чтении. Функциональный блок это по сути та же структура.

Scream
13.02.2016, 16:36
Внесу свои пять копеек.
Андрей Шатохин писал, Ритэйнов не мало, чуть меньше 512 байт. Сохраняю часто - по изменению, при активном использовании объекта периодичность - 2,5 сек.
Весьма интересно, как писать "ритэйн" каждые 2,5 секунды? Как их вообще можно писать??

Причем ПЛК из этого дохлого цикла перезагрузок не возвращается. И в ряде случаев пришлось прошивать сам ПЛК.
Про заводской сброс не слышали?


...
Файл нужно перезаписывать! Открываете файл с именем "my_ret" (ну или че фантазия подскажет), позиционируете на ноль и пишите свои данные, закрываете файл. Далее ОС разберется. Ну и надо выделять время на физическую запись - цикл open, pos, write, close - можно выполнить в одном цикле ПЛК, затем нужно запретить повторную перезапись на некоторое время (ну хотя бы на 50-100мс). И наступит счастье. ...
И зачем это одноразовая запись? Хранить позицию где то надо, чтобы дозаписать файл чтоли или сколько читать потом.

Я хотел написать свой архиватор, потому что штатный убог, он только для иконки на сайте и для засерания менеджерами мозги покупателям, не более.
Проштудировал форум, выписал все косяки, начал писать библиотеку, но всё в пустую.
Если сегодня файл создался, записался, проситался и удалился, то завтра я не могу почему то использовать этоже имя, только хард резет.
Нет абсолютно никакой уверенности что данные не пропадут.
Если у кого то получился свой архиватор на 100й линейке плк, то буду благодарен за пример, но думаю таких людей нет.

Андрей Шатохин
13.02.2016, 17:12
Внесу свои пять копеек.
Андрей Шатохин писал, Ритэйнов не мало, чуть меньше 512 байт. Сохраняю часто - по изменению, при активном использовании объекта периодичность - 2,5 сек.
Весьма интересно, как писать "ритэйн" каждые 2,5 секунды? Как их вообще можно писать??

Причем ПЛК из этого дохлого цикла перезагрузок не возвращается. И в ряде случаев пришлось прошивать сам ПЛК.
Про заводской сброс не слышали?


И зачем это одноразовая запись? Хранить позицию где то надо, чтобы дозаписать файл чтоли или сколько читать потом.

Я хотел написать свой архиватор, потому что штатный убог, он только для иконки на сайте и для засерания менеджерами мозги покупателям, не более.
Проштудировал форум, выписал все косяки, начал писать библиотеку, но всё в пустую.
Если сегодня файл создался, записался, проситался и удалился, то завтра я не могу почему то использовать этоже имя, только хард резет.
Нет абсолютно никакой уверенности что данные не пропадут.
Если у кого то получился свой архиватор на 100й линейке плк, то буду благодарен за пример, но думаю таких людей нет.

Штатный ритэйн я здесь даже не упоминал, под словом ритэйн я имею в виду свой набор переменных значения которых я хочу сохранить при отключении питания. Для меня критично сохранить самую актуальную инфу поэтому я их пишу сразу как только обнаруживаю изменения, изменения я ищу с периодичностью в 2,5 секунды - так надо. Переменные у меня сгруппированы в структуры и в принципе пишутся нормально и читаются нормально, глюки возникают периодически при неустановленных обстоятельствах и приводят они к исключениям и перезапуску контроллера. Последующая загрузка контроллера опять приводит к исключениям - получаю дохлый цикл. Глюки явно уровня прикладного приложения, и вызваны они моим незнанием каких-то процессов файловой системы ПЛК (я уже выяснил штуки 4 диких особенностей =)) ). Вот я и выясняю че да как. А заводской сброс тема отличная, это тот сброс что в кодесисе? Так при постоянном перезапуске контроллера никакой кодесис не может присоединиться к контроллеру - увы и ах. Есть конечно способ остановить прогу - зажать старт/стоп и держать пока контроллер загрузится без прикладного приложения, это работает, но не всегда, видимо что-то моя прога ломает и в файловой системе самой ОС. Кароче, тока теории. Работаю.

Есть ещё наблюдения по особенностям работы ФС?

amn
13.02.2016, 17:29
Если у кого то получился свой архиватор на 100й линейке плк, то буду благодарен за пример, но думаю таких людей нет.

Есть такие люди. Вот ссылка (http://www.owen.ru/forum/showthread.php?t=16563&p=128500&viewfull=1#post128500) на эту тему.

Андрей Шатохин
13.02.2016, 17:30
Пока итог по особенностям ФС ПЛК ОВЕН такой:

0. Файл открытый на запись (w) не перезаписывается, т.е. если файл новой записью не был перезаписан полностью, в нём останется инфа от предыдущих записей (если открыть файл размером 10 байт и записать в него 3 байта то первые 3 байта будут новыми остальные 7 останутся старыми).
1. Файлы удалять нельзя (массово).
2. Тщательно контролируем открытие файла, и не допускаем повторное закрытие файла, закрытие закрытого файла приводит к перезагрузке.
3. Желательно один цикл "open-write-close" отделить по времени от следующего такого же - дать ФС доделать эту операцию.
4. По некоторым данным лучше даже все операции с файлом разделить по времени - выполнять в разных циклах работы контроллера, а совсем если быть точным, то даже контролировать количество записанных и считанных байтов, сверяя их с запланированным к чтению или записи количеству байт. Т.е. даже сами операции записи и чтения выполнять в течении нескольких циклов (если это требуется, если объём инфы большой).

Вот пункт 4 я че-то прям не очень хочу реализовывать, надеюсь для моих 512 байт в одном файле и 1024 байт в другом файле этого не потребуется.

Что ещё добавим?

Yegor
13.02.2016, 17:47
0. Файл открытый на запись (w) не перезаписывается, т.е. если файл новой записью не был перезаписан полностью, в нём останется инфа от предыдущих записей (если открыть файл размером 10 байт и записать в него 3 байта то первые 3 байта будут новыми остальные 7 останутся старыми).Я иного поведения и не встречал нигде.
Вот пункт 4 я че-то прям не очень хочу реализовывать, надеюсь для моих 512 байт в одном файле и 1024 байт в другом файле этого не потребуется.Это несложно (п. 4, 2 абз (http://www.owen.ru/forum/showthread.php?t=22498)).

Андрей Шатохин
13.02.2016, 17:50
А раз пошла такая пьянка что это за файлы?

INNER_RETAIN.1
DOWNLOAD.SDB

amn
13.02.2016, 17:51
Чувствую, что как раз 4 пункт Вам придется реализовать, т.к. за один цикл такой объем не запишется, в первом блоке отправляется 448 байт, в остальных по 512 байт.

Андрей Шатохин
13.02.2016, 17:59
Если я на перле напишу:

open($H, ">file.txt"); - открыл на запись

то file.txt будет стёрт

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

Я как бы не жалуюсь, меня это даже позабавило.

За ссылку спасибо!

Андрей Шатохин
13.02.2016, 18:01
Чувствую, что как раз 4 пункт Вам придется реализовать, т.к. за один цикл такой объем не запишется, в первом блоке отправляется 448 байт, в остальных по 512 байт.

А вот это очень и очень интересно! У меня сложилось аналогичное наблюдение при работе с сокетами (это ещё кроме отсечки на 1536).
Откуда следует что 448 байт?
А на чтение?

amn
13.02.2016, 18:17
Вот нашел ссылку, где это видел ссылка (http://www.owen.ru/forum/showthread.php?t=7648&p=43488&viewfull=1#post43488)

Yegor
13.02.2016, 19:00
Если я на перле напишу:
open($H, ">file.txt"); - открыл на запись
то file.txt будет стёртВы же сами сказали:
Файл открытый на запись (w)Следует различать открытие на запись и открытие на создание-запись (не в рамках ПЛК или Перла, а вообще). Открытие на запись, как правило, не приводит к стиранию файла.

Дмитрий Артюховский
13.02.2016, 21:56
sfw:=SysFileWrite(sfo, ADR(dta), SIZEOF(dta));
sfw:=SysFileWrite(sfo, ADR(c), SIZEOF(c));
sfw:=SysFileWrite(sfo, ADR(sta), SIZEOF(sta));
sfw:=SysFileWrite(sfo, ADR(cl), SIZEOF(cl));
sfw:=SysFileWrite(sfo, ADR(ers), SIZEOF(ers));

не надо так делать никогда ))) формируете ОДИН буфер и одной операцией отправляете задание в ОС на запись... тоже самое с чтением - читаете весь файл в буфер, а потом достаете что нужно

ретайны - это не архиватор, нужна только одна крайняя запись, поэтому дозаписывать в хвост совершенно не нужно

Андрей Шатохин
14.02.2016, 17:15
sfw:=SysFileWrite(sfo, ADR(dta), SIZEOF(dta));
sfw:=SysFileWrite(sfo, ADR(c), SIZEOF(c));
sfw:=SysFileWrite(sfo, ADR(sta), SIZEOF(sta));
sfw:=SysFileWrite(sfo, ADR(cl), SIZEOF(cl));
sfw:=SysFileWrite(sfo, ADR(ers), SIZEOF(ers));

не надо так делать никогда ))) формируете ОДИН буфер и одной операцией отправляете задание в ОС на запись... тоже самое с чтением - читаете весь файл в буфер, а потом достаете что нужно

ретайны - это не архиватор, нужна только одна крайняя запись, поэтому дозаписывать в хвост совершенно не нужно

Вот тоже спасибо за совет!
Я как-то уже к этой мысли начал склоняться.
Делаю буфер и пишу его целиком, причём допускаю, что в несколько этапов его придётся писать и читать.
Еще один нюанс в копилку нюансов.


PS А что может случится если всё-таки так делать? Ведь работает же ... до поры до времени?....

Дмитрий Артюховский
16.02.2016, 19:27
в общем ключе программирования - каждый вызов системной библиотеки много дороже по ресурсам чем основной поток приложения. В плк, кроме того, запись на флэш выполняется вне (после) основного цикла программы, и мало кто знает, сможет софт ОС объединить все ваши вызовы в один, либо он на каждый вызов сделает очередь, которая и будет записывать по блоку (странице мс) на каждую вашу переменную ))

Андрей Шатохин
17.02.2016, 16:37
в общем ключе программирования - каждый вызов системной библиотеки много дороже по ресурсам чем основной поток приложения. В плк, кроме того, запись на флэш выполняется вне (после) основного цикла программы, и мало кто знает, сможет софт ОС объединить все ваши вызовы в один, либо он на каждый вызов сделает очередь, которая и будет записывать по блоку (странице мс) на каждую вашу переменную ))

Ок, спасибо!
Перепелил все в итоге. =)

Scream
17.02.2016, 16:39
Ок, спасибо!
Перепелил все в итоге. =)

Ну покажите что в итоге и как нужно правильно работать.