187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335

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

24.10.2012, 07:18. Показов 3224. Ответов 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
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
24.10.2012, 07:18
Ответы с готовыми решениями:

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

Создать экземпляр одного класса в Main, и передать его в экземпляр другого класса
Добрый день. Подскажите пожалуйста. есть несколько классов-файлов в одном пакете. class one class two class main... Нужно...

Удалить экземпляр класса в массиве
в клсассе Group нужен метод удаления студента из группы по номеру зачетной книжки, как правильно его организовать?уже всю голову сломал,...

34
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
29.10.2012, 23:04
Студворк — интернет-сервис помощи студентам
В предыдущих постах ты пишешь: это помогает, то помогает... То есть, решение проблемы у тебя есть? Просто хочешь знать, почему возникает ошибка? Или нет решения?


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

На самом деле ничего сложно тут нет.
ну вроде бы тут описано.
http://itc.ua/forum/showthread.php?t=40057
Будут вопросы, постараюсь объяснить как смогу.
1
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 18:08
Цитата Сообщение от 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
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 18:28  [ТС]
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
30.10.2012, 18:44
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
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 19:54
Цитата Сообщение от nexen Посмотреть сообщение
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
На моём коде проверял? Среда какая?

Добавлено через 16 минут
Я в Студии проверял и в Code Blocks. Разница только в том, что во втором варианте, в Code Blocks, не мусор, а пустота выводится, и в файле получается: 678пробелы678"
1
187 / 180 / 25
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 19:55  [ТС]
alsav22, ага.
VS 2008.
0
26 / 26 / 3
Регистрация: 20.09.2011
Сообщений: 68
30.10.2012, 20:32
Цитата Сообщение от Toshkarik Посмотреть сообщение
kertio, причем здесь ОС и кеширование HDD? Программа знать не знает, как происходят операции записи/чтения, она всего лишь делает запросы. ОС сама решает записывать данные сразу на диск сейчас или потом, для программы эти данные уже записаны.

nexen, про fflush:
чуть чуть конечно не в тему, но все же,как тогда объяснить что на кешируемых фс если вырубить питание, то данные которые не были сброшены sync-ом, читай fflush-ем, теряются? тем более приводишь информацию по функции, и даже не потрудился перевести. после операции out поток должен быть сброшел, перед чтением. или я затупил где-то?
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
30.10.2012, 21:22
kertio, буфер потока и кеширование фс/диска разные вещи.
При вызове fflush, или при закрытии файла, данные должны записаться в файл на диске. ОС на свое усмотрение, или записывает сразу данные на диск, или оставляет их в кеше для последующей записи, если диск занят в данный момент другой операцией, все зависит как от самой ОС так и от драйвера устройства. Для программы эти данные уже записаны на носитель. И, естественно, если в тот момент, пока ОС держит данные в кеше, вырубить питание, то данные потеряются. Но повторюсь - для программы файл уже записан.
Цитата Сообщение от kertio Посмотреть сообщение
тем более приводишь информацию по функции, и даже не потрудился перевести.
Ну как бы тут люди не глупые, я думаю, английский технический язык знают, если занимаются программированием.

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

Как я понял, это синхронизирует потоки ввода и вывода.

В C++, например, есть функция std::ios::tie для привязки потоков. Так, например, объект std::cin, по умолчанию, "привязан" к объекту std::cout, что гарантирует сброс буфера объекта std::cout перед попыткой ввода с помощью std::cin.
2
26 / 26 / 3
Регистрация: 20.09.2011
Сообщений: 68
31.10.2012, 07:16
так вроде бы об этом и шла речь... поэтому и не читаются данные правильно после операций: запись запись запись запись чтение... после записи нужно сделать, грубо говоря commit изменений, а потом читать. и перед тем как писать я прочитал об этой функции. полный справочник шилдта. там есть описание ф-ии.
PS, все равно спасибо. буду больше учить\читать.
1
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
31.10.2012, 20:25
Сейчас посмотрел, как это в линукс работает. Там и без fflush() всё корректно отрабатывает. Только после fflush() изменения (записанные) сразу в файле появляются, а если без, то после первой операции чтения (если в отладке смотреть, а скорее всего, перед первой операцией чтения). Наверное, в линукс синхронизация записи/чтения из файла сделана так же, как для cin/cout (как Toshkarik описывал в 33 посте).
Цитата Сообщение от Toshkarik Посмотреть сообщение
... Так, например, объект std::cin, по умолчанию, "привязан" к объекту std::cout, что гарантирует сброс буфера объекта std::cout перед попыткой ввода с помощью std::cin.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
31.10.2012, 20:25

Сборщик мусора (как удалить экземпляр класса)
В классе Main при клике на спрайт создаётся экземпляр класса Window: var window:Window; ... ...

Создать экземпляр метода класса или доступ к методу из экземпляра класса
Всем доброго времени суток!) Уже месяца как 2 не сишарпил и подзабыл...собственно задача такая: Создать отдельный экземпляр класса для...

Как получить ссылку на текущий экземпляр класса внутри этого класса?
Как? Чтобы отрабатывал деструктор! и в нем можно было поиметь этот this ... Идея в том, что пишу оболочку под некоторую существующую...

Экземпляр класса как входные данные метода другого класса
Можно ли в качестве входных данных метода передать экземпляр метода другого класса? Если да, то как?

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


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

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

Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru