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

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

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

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

24.10.2012, 07:18. Просмотров 1566. Ответов 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
Toshkarik
1147 / 864 / 51
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
29.10.2012, 18:30 #16
Покажите, как Вы вызываете fseek.
1
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:50 #17
Объекты в файле как записаны? Непрерывная последовательность? Без разделителей?

Добавлено через 2 минуты
Цитата Сообщение от nexen Посмотреть сообщение
Считываю запись с текущего места (то есть должна быть 2ка,
Если строго по примеру, то будет не 2-ка, а пробел.
1
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].
0
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 18:59 #19
Зачем цикл, если нужно переписать один объект?
0
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
29.10.2012, 19:20  [ТС] #20
alsav22, планирую добавить удаление не только по id, так что оставил так.
0
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 23:04 #21
В предыдущих постах ты пишешь: это помогает, то помогает... То есть, решение проблемы у тебя есть? Просто хочешь знать, почему возникает ошибка? Или нет решения?


Цитата Сообщение от nexen Посмотреть сообщение
Записываю 4. (EOF не ставится, ибо не конец файла)
*В файле сейчас : 4 4 2 3 4*
Уменьшаю count на 1.
Считываю запись с текущего места (то есть должна быть 2ка, но тут происходит не пойми что и считывается как будто пара байт из 4ки и пара байт из 2ки и выходит 00 00 02 00 (если уже к примеру говорить).
Эту причину нешёл. После записи сделай fflush(FILE *f) . Запись в буфер идёт и нужно, чтобы изменения (перед чтением) попали в файл.
И насчёт конца файла. Проверь, правильно ли читаешь последний объект в файле. Как у тебя чтение сделано не видно, но если читать с начала объекта, и читать количество байтов, равное размеру объекта, то признак конца файла не установится. Установится, если чтение сделано именно до конца файла, или начато не с той (большей) позиции.
1
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 06:50  [ТС] #22
alsav22, Т_Т.. А ведь я же проверял fflush.. Видать я его перед считыванием ставил и почему-то так не срабатывало. Поставил после PrintFile и теперь всё в порядке.
Можете пояснить, почему это помогло? Ведь, если запись идет в буфер, то нам все равно не важно это, так как fread так же читает из буфера, а не из файла, разве нет?
0
kertio
26 / 26 / 1
Регистрация: 20.09.2011
Сообщений: 68
30.10.2012, 07:56 #23
Цитата Сообщение от nexen Посмотреть сообщение
alsav22, Т_Т.. А ведь я же проверял fflush.. Видать я его перед считыванием ставил и почему-то так не срабатывало. Поставил после PrintFile и теперь всё в порядке.
Можете пояснить, почему это помогло? Ведь, если запись идет в буфер, то нам все равно не важно это, так как fread так же читает из буфера, а не из файла, разве нет?
Ты немного не про тот буфер думаешь. буфер записи на винчестер. система кэширует данные в буфере для ускорения операций чтения записи данных. после того как ты записал данные в файл(точнее даже в дескриптор) они пишутся в буфер записи на винчестер. через какое-то время они запишутся физически на диск, не ранее. можно самому эту синхронизацию вызвать через fflush, а можно просто подождать, например через паузу. а буфер чтения это уже другое. поэтому ты и не можешь читать напрямую из буфера, в который ты записал данные. примерно так. это касательно Linux\Unix. хотя и в виндовс скорее всего тоже самое.
1
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 16:49 #24
Цитата Сообщение от nexen Посмотреть сообщение
Можете пояснить, почему это помогло?
Нет, сам не понимаю. Думаю, тут дело в том, что файл открыт одновременно для записи и чтения. Как в таком случае буфер организован, без понятия. Самое интересное в том, что тут не просто чтение неправильно происходит, но и запись в файл, в результате, получится неправильная. Чтение сдвигает курсор для записи? Ещё помогает, если после записи просто указать (через fseek()) откуда читать.
1
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 17:05  [ТС] #25
alsav22, я делал так, как будто fread и fwrite имеют общую позицию в файле, то есть, если мы прочитали первую запись fread, то, испоьзовав после неё fwrite, писать начнет со второй записи. Так оно и происходило, разве что fread колбасило. fwrite отрабатывало корректно. Проверял ручками дв. файл, байты нормальные.
Поставил везде fflush и всё заработало так, как нужно. Ну как везде.. Если есть чтение - не ставлю. Если есть запись - ставлю ТОЛЬКО после последнего блока. Если есть пара блоков чтения и записи, и они между собой перекликаются, ставлю перед каждым чтением. Пример :

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
//1
fread();
fread();
fread();
//END
 
//2
fwrite();
fwrite();
fwrite();
fflush();//
//END
 
//3
fwrite();
fwrite();
fflush();//
fread();
fwrite();
fflush();//
fread();
fwrite();
fflush();//
//END
Параметры функций опущены.


kertio, если честно, ничего не понял : ) Постараюсь разобраться чуть позже.
Есть ли у тебя ссылка, где можно почитать о таком? Я раньше никогда fflush не использовал и все работа корректно. Подобных ошибок, как у меня, у кого-то ещё в google не нашел..
0
kertio
26 / 26 / 1
Регистрация: 20.09.2011
Сообщений: 68
30.10.2012, 17:19 #26
kertio, если честно, ничего не понял : ) Постараюсь разобраться чуть позже.
Есть ли у тебя ссылка, где можно почитать о таком? Я раньше никогда fflush не использовал и все работа корректно. Подобных ошибок, как у меня, у кого-то ещё в google не нашел..[/QUOTE]

На самом деле ничего сложно тут нет.
ну вроде бы тут описано.
http://itc.ua/forum/showthread.php?t=40057
Будут вопросы, постараюсь объяснить как смогу.
1
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 18:08 #27
Цитата Сообщение от alsav22 Посмотреть сообщение
Самое интересное в том, что тут не просто чтение неправильно происходит, но и запись в файл, в результате, получится неправильная.
Я вот об этом (2 вариант):
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// 1 вариант (после записи нет чтения)
 
#include <fstream>
#include<iostream>
#include <cstdlib>
using namespace std;
 
int main()
{
    FILE *f = fopen("f.txt", "r+b"); // в файле: 012345678
     
    unsigned char x = 'x', y = 'y', z = 'z';
    
                fseek(f, 6, SEEK_SET); // читаем, начиная с 6
    fread(&x, 1, 1, f);
    fread(&y, 1, 1, f);
    fread(&z, 1, 1, f);
    
    fseek(f, 0, SEEK_SET); // записываем, начиная с 0
    fwrite(&x, 1, 1, f);
    fwrite(&y, 1, 1, f);
    fwrite(&z, 1, 1, f);
    
    // в результате в файле:  678345678
    system("pause");
    return 0;
}
 
// 2 вариант (после записи нет fflush(f)  и сразу чтение; запись в файл неправильная)
 
#include <fstream>
#include<iostream>
#include <cstdlib>
using namespace std;
 
int main()
{
    FILE *f = fopen("f.txt", "r+b"); // в файле: 012345678
     
    unsigned char x = 'x', y = 'y', z = 'z';
    
                fseek(f, 6, SEEK_SET); // читаем, начиная с 6 
    fread(&x, 1, 1, f);
    fread(&y, 1, 1, f);
    fread(&z, 1, 1, f);
    
    fseek(f, 0, SEEK_SET); // записываем, начиная с 0
    fwrite(&x, 1, 1, f);
    fwrite(&y, 1, 1, f);
    fwrite(&z, 1, 1, f);
    
    x = 'x', y = 'y', z = 'z';
    
    fread(&x, 1, 1, f);   // продолжаем читать (откуда непоятно. С буфера записи?)
    cout << x << endl; // выводит мусор (код 205)
    fread(&y, 1, 1, f);
    cout << y << endl; // выводит мусор
    fread(&z, 1, 1, f);
    cout << z << endl;  // выводит мусор
    
    // в результате в файле:  678ННН678 // неправильная запись
    system("pause");
    return 0;
}
 
// 3 вариант (с fflush(f) после записи).
 
#include <fstream>
#include<iostream>
#include <cstdlib>
using namespace std;
 
int main()
{
    FILE *f = fopen("f.txt", "r+b"); // в файле: 012345678
     
    unsigned char x = 'x', y = 'y', z = 'z';
    
                fseek(f, 6, SEEK_SET); // читаем, начиная с 6 
    fread(&x, 1, 1, f);
    fread(&y, 1, 1, f);
    fread(&z, 1, 1, f);
    
    fseek(f, 0, SEEK_SET); // записываем, начиная с 0
    fwrite(&x, 1, 1, f);
    fwrite(&y, 1, 1, f);
    fwrite(&z, 1, 1, f);
    
    fflush(f);
 
    x = 'x', y = 'y', z = 'z';
    
    fread(&x, 1, 1, f); // продолжаем читать c 3
    cout << x << endl;          // выводит 3
    fread(&y, 1, 1, f);
    cout << y << endl;          // выводит 4
    fread(&z, 1, 1, f);
    cout << z << endl;          // выводит 5
    
     // в результате в файле:  678345678 
     system("pause");
     return 0;
}
1
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 18:28  [ТС] #28
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
0
Toshkarik
1147 / 864 / 51
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
30.10.2012, 18:44 #29
kertio, причем здесь ОС и кеширование HDD? Программа знать не знает, как происходят операции записи/чтения, она всего лишь делает запросы. ОС сама решает записывать данные сразу на диск сейчас или потом, для программы эти данные уже записаны.

nexen, про fflush:
In files open for update (i.e., open for both reading and writting), the stream shall be flushed after an output operation before performing an input operation.
1
alsav22
5429 / 4824 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 19:54 #30
Цитата Сообщение от nexen Посмотреть сообщение
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
На моём коде проверял? Среда какая?

Добавлено через 16 минут
Я в Студии проверял и в Code Blocks. Разница только в том, что во втором варианте, в Code Blocks, не мусор, а пустота выводится, и в файле получается: 678пробелы678"
1
30.10.2012, 19:54
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.10.2012, 19:54
Привет! Вот еще темы с ответами:

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

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

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

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


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

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

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