Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.89/9: Рейтинг темы: голосов - 9, средняя оценка - 4.89
nexen
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
1

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

24.10.2012, 07:18. Просмотров 1631. Ответов 34
Метки нет (Все метки)

Задача - удалить записанный экземпляр класса из дв. файла.
(В моём решении, удаленный экземпляр просто затирается последним)
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*& (с ссылкой)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.10.2012, 07:18
Ответы с готовыми решениями:

Можно ли считывать поля класса из двоичного файла одним fread
Можно ли считывать поля класса из двоичного файла одним fread? fread(this,...

Создание указателя типа базового класса на экземпляр производного класса
Добрый день! Иногда видел коды, где создавался указатель типа базового класса...

Создать экземпляр класса без явного указания членов класса
Если у меня есть два конструктора, один из которых по умолчанию, а второй...

Как построить экземпляр дочернего класса на основе готового экземпляра базового класса?
Если уже есть готовый объект базового класса. Могу я построить экземпляр...

Создание статической функции класса, которая принимает экземпляр этого же класса как объект
Привет. Есть такой код class Model { public: Model(); Model(int...

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

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

Цитата Сообщение от nexen Посмотреть сообщение
и что это значит?
C++
1
2
fstream f("file.txt");
f.clear(); // сброс флагов потока
1
nexen
187 / 180 / 25
Регистрация: 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 просто обновляет контект, поэтому и решает проблему.
Вопрос, как же тогда пользоваться контекстом?
0
alsav22
5442 / 4837 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 16:16 6
По ссылке передай.
0
nexen
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 16:24  [ТС] 7
alsav22, вроде бы как я писал, что везде поставил FILE*&..
0
alsav22
5442 / 4837 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 16:36 8
Цитата Сообщение от nexen Посмотреть сообщение
переходя в функцию, создается новый конекст файла,
Что за контекст файла?

Добавлено через 2 минуты
Цитата Сообщение от nexen Посмотреть сообщение
Ещё помогает передача параметра в ReadFile в виде FILE*& (с ссылкой)
Тогда зачем этот вопрос?
Цитата Сообщение от nexen Посмотреть сообщение
Вопрос, как же тогда пользоваться контекстом?
0
Toshkarik
1150 / 867 / 90
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
29.10.2012, 16:39 9
Можете весь код выложить? А то не совсем понятно что у Вас происходит. По сути Вы достигаете eof при считывании последнего экземпляра. Устанавливается флаг EOF. fseek само собой его убирает. Подробней вот тут - http://www.cplusplus.com/reference/clibrary/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.
1
nexen
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:04  [ТС] 10
Toshkarik, ага, а потом всё равно происходят ошибки, ведь после того, как я считал последнюю запись, я возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её, а затем, считывая следующую запись, я получаю ошибку.
Кода слишком много. Никто читать не будет >_<" Лишь напугает тех, кто хочет помочь. Описания проблемы будет достаточно. Если что-то непонятно, то так и скажите. Попытаюсь описать детальнее
0
Toshkarik
1150 / 867 / 90
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
29.10.2012, 17:09 11
nexen, потому что снова ставится EOF. Поставьте assert`ы feof() и посмотрите сами.
1
nexen
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:50  [ТС] 12
Toshkarik, но почему? Ведь записываю я уже не в конец файла ><
0
alsav22
5442 / 4837 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 17:57 13
Цитата Сообщение от nexen Посмотреть сообщение
возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её
При перезаписи до конца файла доходишь?

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

Добавлено через 55 секунд
Кода нет. Предлагаешь гадать?
0
Toshkarik
1150 / 867 / 90
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 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.
1
nexen
187 / 180 / 25
Регистрация: 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 - удалена.
0
Toshkarik
1150 / 867 / 90
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
29.10.2012, 18:30 16
Покажите, как Вы вызываете fseek.
1
alsav22
5442 / 4837 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:50 17
Объекты в файле как записаны? Непрерывная последовательность? Без разделителей?

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

alsav22, ну это я для наглядности. Пробелов нет. Записываемые классы представляют из себя строго фиксированную последовательность байт. vector/string или подобные нет. Только char*. Только с одинаковым new[STRING_SIZE].
0
alsav22
5442 / 4837 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:59 19
Зачем цикл, если нужно переписать один объект?
0
nexen
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 19:20  [ТС] 20
alsav22, планирую добавить удаление не только по id, так что оставил так.
0
29.10.2012, 19:20
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.10.2012, 19:20

Как сделать членом класса экземпляр этого же класса
class Operation { public: bool type; //true = operation, false = number...

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

Вызов методов класса из двойного указателя на экземпляр класса
Добрый день! Как можно вызвать метод класса по двойному указателя на его...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru