Форум программистов, компьютерный форум CyberForum.ru

Удалить записанный экземпляр класса из двоичного файла - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.92
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.10.2012, 07:18     Удалить записанный экземпляр класса из двоичного файла #1
Задача - удалить записанный экземпляр класса из дв. файла.
(В моём решении, удаленный экземпляр просто затирается последним)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
for (UINT i=0; i<patientsCount; ++i)
    {
        //fseek(patientsDatabase, (sizeof(patientsCount)+i*Size()), SEEK_SET); // X-ACTION
        ReadFile(patientsDatabase); //считываю экземпляр класса из дв. файла. Это метод\
Всё происходит в this
        if (_id == idRequired) // Требуемый Id для удаления
        {
            //DeleteCard(databases);
            if (patientsRequiredCount == 0)
                printf(Rus("-\nУдаленные записи\n"));
            printf(Rus("\nЗапись #%u\n"), i+1);
            //Print(); 
            PrintIdFile(patientsIdDatabase); // записываю this в дв. файл
            if (i < (patientsCount-1))
            {
                fseek(patientsDatabase, (sizeof(patientsCount)+(patientsCount-1)*Size()), SEEK_SET); // перехожу к последней записи дв. файла (Size() - размер структуры. Считает корректно)
                ReadFile(patientsDatabase); // считываю this
                fseek(patientsDatabase, (sizeof(patientsCount)+i*Size()), SEEK_SET); // перехожу к удаляемой записи
                PrintFile(patientsDatabase); // перезаписываю её
            }
            ++patientsRequiredCount;
            --patientsCount; // уменьшаю счетчик кол-ва записей
        }
    }
Проблема в том, что она не работает, если оставить всё так, как есть. Если разкомментировать строчку с fseek X-MOMENT, то всё начнет работать. Причем сам fseek никуда не двигает каретку в дв. файле. До X-MOMENT каретка стоит на 104 байте, после момента так же на 104 байте, но при этом следующий за ней ReadFile считывает все корректно.
Отчего такая феерическая ошибка? Может ли быть так, что, когда я сделал fseek на последнюю запись и считал её (ушел в EOF), то как-то нарушил всю суть работы? Хотя PrintFile после возврата каретки на текущую запись всё же отработал D:

Добавлено через 6 минут
Вместо X-ACTION можно вставить и такое. Тоже поможет :
C++
1
2
3
UINT id;
        fread(&id, sizeof(id), 1, patientsDatabase);
        fseek(patientsDatabase, -long(sizeof(id)), SEEK_CUR);
Ещё помогает передача параметра в ReadFile в виде FILE*& (с ссылкой)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.10.2012, 07:18     Удалить записанный экземпляр класса из двоичного файла
Посмотрите здесь:

Можно ли считывать поля класса из двоичного файла одним fread C++
Создание экземпляр класса из другого класса C++
Обращение к методам класса через указатель на экземпляр класса C++
C++ Как построить экземпляр дочернего класса на основе готового экземпляра базового класса?
Как сделать членом класса экземпляр этого же класса C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
24.10.2012, 14:56     Удалить записанный экземпляр класса из двоичного файла #2
Цитата Сообщение от nexen Посмотреть сообщение
Может ли быть так, что, когда я сделал fseek на последнюю запись и считал её (ушел в EOF), то как-то нарушил всю суть работы?
Код не смотрел, говорю на вскидку. Если поток дошёл до EOF, то потом, чтобы fseek работал, нужно сбросить флаги (по крайней мере, так с потоками в С++)
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
24.10.2012, 15:44  [ТС]     Удалить записанный экземпляр класса из двоичного файла #3
alsav22, что значит "сбросить флаги"? И почему тогда работает даже после EOF при том хаке, что я написал?

Добавлено через 21 минуту
Цитата Сообщение от alsav22 Посмотреть сообщение
(по крайней мере, так с потоками в С++)
и что это значит?
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
24.10.2012, 16:03     Удалить записанный экземпляр класса из двоичного файла #4
Цитата Сообщение от nexen Посмотреть сообщение
что значит "сбросить флаги"? И почему тогда работает даже после EOF при том хаке, что я написал?
Это предположение, не более того. Код не смотрел.

Цитата Сообщение от nexen Посмотреть сообщение
и что это значит?
C++
1
2
fstream f("file.txt");
f.clear(); // сброс флагов потока
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 14:37  [ТС]     Удалить записанный экземпляр класса из двоичного файла #5
alsav22, а, не, я через FILE* работаю.

Добавлено через 30 минут
Файл открыт r+b. Есть ли какие-либо особенности при работе с файлом, который открыт одновременно для чтения и записи, когда я в него записываю и читаю?

Добавлено через 5 часов 27 минут
Такое ощущение, что фокус в инкапсуляции какой-то.. Изменил всё на FILE*& и FILE**&, в итоге зайдя ещё глубже (из функции чтения передав в ещё одну функцию чтения свой файл), получил опять ту же проблему..

Будет ли какая-то разница, с каким из этих указателей работать?
C++
1
2
3
4
5
6
void f(FILE* f)
{
}
FILE *f1 = fopen("myfile.dat", "r+b");
FILE *f2 = f1, *f3 = f2, *f4 = f3;
f(f4);
Добавлено через 1 час 9 минут
Новый-старый фокус.
C++
1
ReadFile(file); // не работает
----------------------------
C++
1
2
fseek(file, ftell(file), SEEK_SET);
ReadFile(file); // работает
Добавлено через 11 часов 23 минуты
up-to-date

Добавлено через 7 часов 57 минут
Как сказал преподователь по ОС, это может быть из-за того, что, переходя в функцию, создается новый конекст файла, а когда я возвращаюсь из функции, забираю предыдущий контект (который теперь почему-то испорчен). fseek просто обновляет контект, поэтому и решает проблему.
Вопрос, как же тогда пользоваться контекстом?
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 16:16     Удалить записанный экземпляр класса из двоичного файла #6
По ссылке передай.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 16:24  [ТС]     Удалить записанный экземпляр класса из двоичного файла #7
alsav22, вроде бы как я писал, что везде поставил FILE*&..
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 16:36     Удалить записанный экземпляр класса из двоичного файла #8
Цитата Сообщение от nexen Посмотреть сообщение
переходя в функцию, создается новый конекст файла,
Что за контекст файла?

Добавлено через 2 минуты
Цитата Сообщение от nexen Посмотреть сообщение
Ещё помогает передача параметра в ReadFile в виде FILE*& (с ссылкой)
Тогда зачем этот вопрос?
Цитата Сообщение от nexen Посмотреть сообщение
Вопрос, как же тогда пользоваться контекстом?
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
29.10.2012, 16:39     Удалить записанный экземпляр класса из двоичного файла #9
Можете весь код выложить? А то не совсем понятно что у Вас происходит. По сути Вы достигаете eof при считывании последнего экземпляра. Устанавливается флаг EOF. fseek само собой его убирает. Подробней вот тут - http://www.cplusplus.com/reference/c...y/cstdio/feof/

Нужная Вам часть:
Notice that stream's internal position indicator may point to the end-of-file for the next operation, but still, the end-of-file indicator may not be set until an operation attempts to read at that point.

This indicator is cleared by a call to clearerr, rewind, fseek, fsetpos or freopen. Although if the position indicator is not repositioned by such a call, the next i/o operation is likely to set the indicator again.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:04  [ТС]     Удалить записанный экземпляр класса из двоичного файла #10
Toshkarik, ага, а потом всё равно происходят ошибки, ведь после того, как я считал последнюю запись, я возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её, а затем, считывая следующую запись, я получаю ошибку.
Кода слишком много. Никто читать не будет >_<" Лишь напугает тех, кто хочет помочь. Описания проблемы будет достаточно. Если что-то непонятно, то так и скажите. Попытаюсь описать детальнее
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
29.10.2012, 17:09     Удалить записанный экземпляр класса из двоичного файла #11
nexen, потому что снова ставится EOF. Поставьте assert`ы feof() и посмотрите сами.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:50  [ТС]     Удалить записанный экземпляр класса из двоичного файла #12
Toshkarik, но почему? Ведь записываю я уже не в конец файла ><
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 17:57     Удалить записанный экземпляр класса из двоичного файла #13
Цитата Сообщение от nexen Посмотреть сообщение
возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её
При перезаписи до конца файла доходишь?

Цитата Сообщение от nexen Посмотреть сообщение
В моём решении, удаленный экземпляр просто затирается последним
Последний в файле? Может здесь до конца файла доходишь?

Добавлено через 55 секунд
Кода нет. Предлагаешь гадать?
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
29.10.2012, 17:58     Удалить записанный экземпляр класса из двоичного файла #14
Ведь написано:
Цитата Сообщение от Toshkarik Посмотреть сообщение
Although if the position indicator is not repositioned by such a call, the next i/o operation is likely to set the indicator again.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 18:09  [ТС]     Удалить записанный экземпляр класса из двоичного файла #15
Toshkarik, так в том то и дело, что он сбросился fseek'ом, как ты и сказал.
Покажу на примере. В файле :
4 1 2 3 4.
Первое число - кол-во записей, остальное - данные.
Считываю 4.
C++
1
for (int i=0; i<count; ++i)
Считываю 1.
Это требуемые к удалению данные. Перемещаюсь на начало 4 (предпоследняя запись, которую я смотрю не по SEEK_END, а по count).
Считываю 4ку. EOF
Перемещаюсь на начало 1. (EOF сбрасывается)
Записываю 4. (EOF не ставится, ибо не конец файла)
*В файле сейчас : 4 4 2 3 4*
Уменьшаю count на 1.
Считываю запись с текущего места (то есть должна быть 2ка, но тут происходит не пойми что и считывается как будто пара байт из 4ки и пара байт из 2ки и выходит 00 00 02 00 (если уже к примеру говорить).

Предположим, ошибки нет, то в конце перезаписываю count и получается файл :
3 4 2 3 4.
Так же, так как for идет до count, а я его уменьшил, то до EOF он уже никогда не дойдет
Запись 1 - удалена.
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 1
29.10.2012, 18:30     Удалить записанный экземпляр класса из двоичного файла #16
Покажите, как Вы вызываете fseek.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:50     Удалить записанный экземпляр класса из двоичного файла #17
Объекты в файле как записаны? Непрерывная последовательность? Без разделителей?

Добавлено через 2 минуты
Цитата Сообщение от nexen Посмотреть сообщение
Считываю запись с текущего места (то есть должна быть 2ка,
Если строго по примеру, то будет не 2-ка, а пробел.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 18:52  [ТС]     Удалить записанный экземпляр класса из двоичного файла #18
Toshkarik, в первом сообщении темы. Строки 17-20.

alsav22, ну это я для наглядности. Пробелов нет. Записываемые классы представляют из себя строго фиксированную последовательность байт. vector/string или подобные нет. Только char*. Только с одинаковым new[STRING_SIZE].
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:59     Удалить записанный экземпляр класса из двоичного файла #19
Зачем цикл, если нужно переписать один объект?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.10.2012, 19:20     Удалить записанный экземпляр класса из двоичного файла
Еще ссылки по теме:

Создание статической функции класса, которая принимает экземпляр этого же класса как объект C++
C++ Классы и объекты в С++, компонента класса и экземпляр класса
C++ Считать из файла массив записанный в столбик

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 19:20  [ТС]     Удалить записанный экземпляр класса из двоичного файла #20
alsav22, планирую добавить удаление не только по id, так что оставил так.
Yandex
Объявления
29.10.2012, 19:20     Удалить записанный экземпляр класса из двоичного файла
Ответ Создать тему
Опции темы

Текущее время: 02:27. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru