Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.92
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
#1

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

24.10.2012, 07:18. Просмотров 1553. Ответов 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
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Удалить записанный экземпляр класса из двоичного файла (C++):

Можно ли считывать поля класса из двоичного файла одним fread - C++
Можно ли считывать поля класса из двоичного файла одним fread? fread(this, sizeof(*this), 1, myFile); Слышал, что компиляторы по...

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

Создание указателя типа базового класса на экземпляр производного класса - C++
Добрый день! Иногда видел коды, где создавался указатель типа базового класса на объект класса - наследника, для чего это может применяться?

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

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

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

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

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

Добавлено через 2 минуты
Цитата Сообщение от nexen Посмотреть сообщение
Ещё помогает передача параметра в ReadFile в виде FILE*& (с ссылкой)
Тогда зачем этот вопрос?
Цитата Сообщение от nexen Посмотреть сообщение
Вопрос, как же тогда пользоваться контекстом?
0
Toshkarik
1143 / 860 / 51
Регистрация: 03.08.2011
Сообщений: 2,390
Завершенные тесты: 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 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:04  [ТС] #10
Toshkarik, ага, а потом всё равно происходят ошибки, ведь после того, как я считал последнюю запись, я возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её, а затем, считывая следующую запись, я получаю ошибку.
Кода слишком много. Никто читать не будет >_<" Лишь напугает тех, кто хочет помочь. Описания проблемы будет достаточно. Если что-то непонятно, то так и скажите. Попытаюсь описать детальнее
0
Toshkarik
1143 / 860 / 51
Регистрация: 03.08.2011
Сообщений: 2,390
Завершенные тесты: 1
29.10.2012, 17:09 #11
nexen, потому что снова ставится EOF. Поставьте assert`ы feof() и посмотрите сами.
1
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 17:50  [ТС] #12
Toshkarik, но почему? Ведь записываю я уже не в конец файла ><
0
alsav22
5426 / 4821 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 17:57 #13
Цитата Сообщение от nexen Посмотреть сообщение
возвращаюсь не местоположение той, которую надо перезаписать и перезаписываю её
При перезаписи до конца файла доходишь?

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

Добавлено через 55 секунд
Кода нет. Предлагаешь гадать?
0
Toshkarik
1143 / 860 / 51
Регистрация: 03.08.2011
Сообщений: 2,390
Завершенные тесты: 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 / 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 - удалена.
0
29.10.2012, 18:09
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.10.2012, 18:09
Привет! Вот еще темы с ответами:

Обращение к методам класса через указатель на экземпляр класса - C++
Добрый день. Не могу осилить проблему: Описан абстрактный класс. Описаны наследники этого класса уже без абстрактности. Описан...

Вызов методов класса из двойного указателя на экземпляр класса - C++
Добрый день! Как можно вызвать метод класса по двойному указателя на его экземпляр? struct Point { void getPoint(){}; ...

Может ли метод класса возвращать экземпляр этого же класса? - C++
такой вопрос, реально что бы функция класса имела тип класса(возвращала класс), то есть типа так: class c1{ c1 f1(); } если да, то...

Классы и объекты в С++, компонента класса и экземпляр класса - C++
Вариант 8. ИЗДЕЛИЕ наименование– char* шифр– char* тип упаковки– char* количество– int 1. Определить пользовательский ...


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

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

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