На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела Visual Basic: Общие вопросы
Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.

Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ!
4. Используйте теги [ code=vba ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта user posted image FAQ Раздела user posted image Кладовка user posted image Наши Исходники user posted image API-Guide user posted image Поиск по Разделу user posted image MSDN Library Online user posted image Google

Ваше мнение о модераторах: user posted image SCINER, user posted image B.V.
Модераторы: SCINER, B.V.
  
> Как избежать сбоя при записи в файл?
    Есть у меня прога, которая постоянно держит открытым файл (For Random) и записывает в него данные по 128 байт. Сегодня обнаружил в этом файле мусор. Предполагаю, что мусор туда попал при аварийной перезагрузке компа. Заметил, что часто сбой происходит при открытом сайте vk.com (слушаю музыку), у них там постоянно баги вылазят. Из любопытства просмотрел данные мусора - там оказался текстовый код из часто открытого у меня ДРУГОГО проекта VB, т.е. из оперативки или временных файлов VB(?). Интересно, но не суть важно. Запись в файл происходит приблизительно 3 раза в минуту. Есть ли смысл постоянно закрывать/открывать файл, чтобы уменьшить вероятность записи в данные мусора или же так больше вероятность нарваться на ошибку и стоп проги? Или лучше пожалеть винт (скорость проги не играет роли)?
    Сообщение отредактировано: BlackSun -
      Цитата BlackSun @
      Есть ли смысл постоянно закрывать/открывать файл, чтобы уменьшить вероятность записи в данные мусора

      Да.

      Цитата BlackSun @
      или же так больше вероятность нарваться на ошибку и стоп проги?

      Вообще-то ошибки принято обрабатывать, стараясь восстановить нормальную работу программы.

      Цитата BlackSun @
      Или лучше пожалеть винт

      Дополнительной нагрузки на хард практически не будет - последние блоки файла стопроцентно лежат в файловом кэше ОС.
        Цитата BlackSun @
        . Есть ли смысл постоянно закрывать/открывать файл, чтобы уменьшить вероятность записи в данные мусора или же так больше вероятность нарваться на ошибку и стоп проги? Или лучше пожалеть винт (скорость проги не играет роли)?

        Сбрасывай буфер файла после каждой записи. FlushFileBuffers или что-то типа того.
          Олег М
          Да у него по 20 секунд между записями, а autoflush емнип 2 секунды...
            Цитата Akina @
            последние блоки файла стопроцентно лежат в файловом кэше ОС
            так значит отсюда мусор попадает ко мне? таки надо делать сброс кеша сразу...

            Добавлено
            А если я буду писать единовременно по несколько записей, столько, чтобы заполнить весь этот буфер сразу - места мусору не будет. Какой у него размер?
              Нет, мусор из буфера записи дисковой подсистемы ОС. Запись же идёт блоками (ну считай кластерами), а итоговый размер пишется только при фиксации (закрытии) файла. Вот всё, что за реальным концом, и будет забито случайным хламом.

              Цитата BlackSun @
              Какой у него размер?

              Вот кто бы знал... в первом приближении - кратно размеру кластера накопителя, но ещё и делит нацело стандартный блок предчтения. Так что нечто бинарно-круглое от 4 кбайт до 2 Мбайт. А с учётом того, что буферов не один, а несколько независимо-последовательных (дисковая-файловая-приложения, и это на самом деле не всё), гадать вообще бессмысленно.

              Разумнее записывать не по 128, а поболе, довешивая этим 128 ещё контрольную сумму. Тогда по её невалидности инфо от хлама отличить - раз плюнуть.
                Можно довешивать CRC, но не хочется увеличивать объём данных. Хотелось понять принцип попадания мусора в данные. Если в буфер попадают данные с разных приложений, то там же должны быть какие-то разграничители? При сбое просто не записывается конец файла и файл остаётся с мусором в конце? Этот мусор тогда не должен превышать по размеру размер буфера ОС? Он имеет произвольную длину или кратную 2^n (вместе с моей записью в начале)? Или как?
                  Цитата BlackSun @
                  . Хотелось понять принцип попадания мусора в данные.

                  Покажи код, как ты пишешь в файл.
                    Цитата BlackSun @
                    Хотелось понять принцип попадания мусора в данные.

                    Очень просто.
                    Ты открываешь файл. Под него резервируется буфер в памяти. Само собой там изначально мусор.
                    Ты что-то пишешь в файл, а на самом деле в этот буфер. Соответственно в той части буфера, куда байты не кладутся, остаётся мусор.
                    При сбросе на диск ОС записывает весь блок (минимально - кластер). Соответственно в неиспользованной с твоей точки зрения части кластера пишется мусор.
                    Пока файл открыт, ОС фиксирует только занятые файлом кластеры. Только при закрытии она в элементе каталога укажет точный размер в байтах, а пока формальный размер файла округлён вверх до кластера, причём эти сведения есть только в оперативке.
                    Если происходит аварийное завершение, данные об актуальном размере записаны не будут. В то время как данные об использовании кластеров - уже записаны (они пишутся непосредственно в момент их корректировки).
                    При следующем старте ОС обнаружит в журнале тома сведения, что файл не закрыт корректно. Сведения об истинном размере - утрачены. Соответственно будет установлен такой размер, чтобы гарантированно ничего не потерять - т.е. по максимуму.
                    Итог - тот мусор, который находится в неиспользованной части кластера и считался бы несуществующим при штатном закрытии, стал легитимным содержимым файла.
                      Цитата Akina @
                      Ты открываешь файл. Под него резервируется буфер в памяти. Само собой там изначально мусор.

                      Не "само собой". Если речь идет о системном файловом кэше, то он работает по принципу файл-маппинга, при котором под буфер всегда выделяются предварительно обнуленные страницы памяти (из соображений безопасности\приватности\конфиденциальности). Соотв-но, если в винде размер кластера равен или кратен размеру страницы, то мусор в конце файла может возникнуть только в случае, когда ОС сначала выделяет новые кластеры для файла и изменяет его размер, и только потом записывает данные - тогда при сбое\прерывании записи в конце файла может остаться мусор от старых данных на диске.
                        Цитата leo @
                        Если речь идет о системном файловом кэше

                        Речь о всех буферах - формируемых VB, формируемых файловым кэшем ОС, а если есть - и других.

                        Цитата leo @
                        только в случае, когда ОС сначала выделяет новые кластеры для файла и изменяет его размер, и только потом записывает данные

                        Если изменяется цепь занимаемых файлом кластеров, Win всегда сначала пишет в тело файла, потом помечает кластеры как использованные, и только потом изменяет цепь кластеров файла. Такая последовательность действий минимизирует вероятность возникновения ошибки, а в случае её возникновения - минимизирует тяжесть повреждения. Когда пишется изменённый размер файла, точно не скажу, надо смотреть у Руссиновича, но в случае скоропостижной смерти ОС после автовосстановления при старте размеры открытых на момент падения ОС файлов или корректны, или увеличиваются до кратности кластеру, так что скорее всего размер меняется в самую последнюю очередь, уже после работы с занимаемыми кластерами..
                          У меня размер кластера на томе винта 16КБ и насколько я знаю, минимальная порция записи на диск 512 байт. Сбой случается редко, максимум 2-3 раза мог быть. Я обнаружил мусора в файле >300КБ, и, наверняка, в файле ещё что-то осталось (я отсеивал мусор по некорректным значениям полей UDT-записи). По размерам не сходится, если мусор пишется не более 1 кластера. Т.к. в мусоре был программный код другого проекта, буфера были явно не обнулены. В целом я придумал корректную запись в файл без CRC, но для меня картина записи мусора осталась не прояснённой до конца.
                            Akina
                            Как бы то ни было, а источником мусора в файле может являться только сам диск, когда в результате сбоя последний кластер записывается из памяти на диск не полностью и соотв-но в его хвосте остаются старые мусорные данные на диске.
                            Ни с какими буферами в памяти это невозможно, особенно когда этот мусор представляет собой данные какого-то другого приложения (?!)
                              Насколько я знаю, физически данные записываются секторами, тут просто не записались служебные данные после записи самих данных, а именно размер файла. Так что мусор идёт из памяти. С Akina согласен. Открытым же остался вопрос большого объёма самого мусора... Возможно, файлу устанавливается некий логический размер после сбоя, и добавляются ещё сектора/кластера с диска (и тут уж мусор идёт от этих кластеров).

                              Из сети:
                              Цитата
                              Каждая дорожка разбивается на фрагменты, называемые секторами (sectors) или блоками (blocks), так что все дорожки имеют равное число секторов, в которые можно максимально записать одно и то же число байтов. Сектор имеет фиксированный для конкретной системы размер, выражающийся степенью двойки. Чаще всего размер сектора составляет 512 байтов...
                              Сектор  наименьшая адресуемая единица обмена данными дискового устройства с оперативной памятью....
                              Операционная система при работе с диском использует, как правило, собственную единицу дискового пространства, называемую кластером (cluster). При создании файла место на диске ему выделяется кластерами. Например, если файл имеет размер 2560 байт, а размер кластера в файловой системе определен в 1024 байта, то файлу будет выделено на диске 3 кластера....


                              Добавлено
                              Вспоминая характер мусора, я видел разные значки (как письмо на почте в не той кодировке) - похоже, это был мусор из памяти, а ещё видел код на VB - это могут быть временные файлы VB, которые были удалены с диска, но данные на секторах остались...
                              Сообщение отредактировано: BlackSun -
                                Цитата BlackSun @
                                Так что мусор идёт из памяти

                                Не может он идти из памяти, особенно данные из другого приложения. В противном случае, винду с ее защитой\изоляцией памяти между процессами можно выкинуть коту под хвост.
                                "Нет, Шура. Только кража" (С). Т.е. мусор м.б. только с диска, когда при сбое установленный размер файла превышает размер реально записанных данных.

                                PS: При создании и/или увеличении размера файла защита тоже действует, поэтому в штатном режиме 1) данные пишутся на диск всегда целыми кластерами с обнуленным хвостом последнего кластера, чтобы затереть старые данные на диске, 2) при записи с пропусками (установкой SetFilePointer за пределы текущего размера файла с последующим вызовом WriteFile или SetEndOfFile) в образовавшуюся дырку автоматически записываются нули.

                                Цитата BlackSun @
                                Вспоминая характер мусора, я видел разные значки (как письмо на почте в не той кодировке) - похоже, это был мусор из памяти

                                Это м.б. данные какого-то двоичного файла на диске - удаленного или урезанного
                                Сообщение отредактировано: leo -
                                  leo тогда откуда вообще мусор берётся? Накидывает доп. кластеры файлу? Не обнулённые? Akina утверждал, что мусор - это часть данных внутри неполного кластера. Я же вижу, что мусора очень много, >300КБ (жаль не проверил, последовательные это записи или нет). Что касается мусора из памяти, то коль уж Вин записывает данные кластерами, то почему бы ей не брать данных на весь кластер из моего процесса и записывать, упреждая т.о. будущую запись? Да, безопасность ниже, но выше производительность. Если я пишу 128 байт из массива UDT, Вин может спокойно брать в целом 16 КБ данных от начала моей записи и писать их в файл... Она же не знает, что я записываю только последнюю запись массива, а далее мусор. Обычно в прогах запись данных идёт последовательно, и, если идёт запись некого большого массива, то такой механизм упреждения записи очень выгоден (особенно если побайтовая запись)... И тут можно кидать данные в буфер и проверять, были ли они записаны ранее, если да - то можно не писать. И может, механизм записи зависит от самой Винды.

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


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0451 ]   [ 17 queries used ]   [ Generated: 25.04.24, 05:32 GMT ]