Просмотр полной версии : Всё-таки как правильно работать с файлами?
Андрей Шатохин
12.02.2016, 22:37
Коллеги!
http://forum-ru.codesys.com/viewtopic.php?t=850 здесь рекомендуют выполнять не больше одной операции с файлом за один цикл работы ПЛК.
Так ли это критично?
Вот этот кусок важен:
Функции эти имеют несложные параметры, но при их использовании надо учесть, что реакция системы контроллера на каждую команду (вызов функции) может быть больше времени перехода от одной команды к другой. т.е. Функции не блокирующиеЯ не находил подтверждения тому, что это неблокирующие функции. Да и существование библиотеки 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. Это сильно плохо? Разнести их по времени?
Чтобы узнать есть файл или нет надо попробовать его открыть. Если дескриптор равен нулю, то файла нет и работать с ним нет смысла.
За один цикл только одна операция с файлом.
Чтение и запись может занять несколько циклов (зависит от размера файла).
Узнать окончание записи или чтения можно по количеству реально записанных (прочитанных) байт, которые возвращает функция.
Пока не закончится одна операция с файлом к другой не переходить.
Андрей Шатохин
13.02.2016, 12:11
у меня считываются несколько структур, т.е. мне следует сначала считать весь файл в несколько заходов, если это потребуется, в некоторый буфер, а уже из него раскидать данные по структурам, так получается? жеееееесть.....
Что мешает в качестве буфера использовать ФБ. В этот ФБ копируете все свои структуры, после чего задаете его параметром для функции записи. То же самое при чтении. Функциональный блок это по сути та же структура.
Внесу свои пять копеек.
Андрей Шатохин писал, Ритэйнов не мало, чуть меньше 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 диких особенностей =)) ). Вот я и выясняю че да как. А заводской сброс тема отличная, это тот сброс что в кодесисе? Так при постоянном перезапуске контроллера никакой кодесис не может присоединиться к контроллеру - увы и ах. Есть конечно способ остановить прогу - зажать старт/стоп и держать пока контроллер загрузится без прикладного приложения, это работает, но не всегда, видимо что-то моя прога ломает и в файловой системе самой ОС. Кароче, тока теории. Работаю.
Есть ещё наблюдения по особенностям работы ФС?
Если у кого то получился свой архиватор на 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 байт в другом файле этого не потребуется.
Что ещё добавим?
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
Чувствую, что как раз 4 пункт Вам придется реализовать, т.к. за один цикл такой объем не запишется, в первом блоке отправляется 448 байт, в остальных по 512 байт.
Андрей Шатохин
13.02.2016, 17:59
Если я на перле напишу:
open($H, ">file.txt"); - открыл на запись
то file.txt будет стёрт
я как-то к этому привык и в других средах также вроде, это только на ПЛК такая штука меня подстерегла.
Я как бы не жалуюсь, меня это даже позабавило.
За ссылку спасибо!
Андрей Шатохин
13.02.2016, 18:01
Чувствую, что как раз 4 пункт Вам придется реализовать, т.к. за один цикл такой объем не запишется, в первом блоке отправляется 448 байт, в остальных по 512 байт.
А вот это очень и очень интересно! У меня сложилось аналогичное наблюдение при работе с сокетами (это ещё кроме отсечки на 1536).
Откуда следует что 448 байт?
А на чтение?
Вот нашел ссылку, где это видел ссылка (http://www.owen.ru/forum/showthread.php?t=7648&p=43488&viewfull=1#post43488)
Если я на перле напишу:
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
в общем ключе программирования - каждый вызов системной библиотеки много дороже по ресурсам чем основной поток приложения. В плк, кроме того, запись на флэш выполняется вне (после) основного цикла программы, и мало кто знает, сможет софт ОС объединить все ваши вызовы в один, либо он на каждый вызов сделает очередь, которая и будет записывать по блоку (странице мс) на каждую вашу переменную ))
Ок, спасибо!
Перепелил все в итоге. =)
Ок, спасибо!
Перепелил все в итоге. =)
Ну покажите что в итоге и как нужно правильно работать.
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot