Форум программистов, компьютерный форум 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
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) . Запись в буфер идёт и нужно, чтобы изменения (перед чтением) попали в файл.
И насчёт конца файла. Проверь, правильно ли читаешь последний объект в файле. Как у тебя чтение сделано не видно, но если читать с начала объекта, и читать количество байтов, равное размеру объекта, то признак конца файла не установится. Установится, если чтение сделано именно до конца файла, или начато не с той (большей) позиции.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 06:50  [ТС]     Удалить записанный экземпляр класса из двоичного файла #22
alsav22, Т_Т.. А ведь я же проверял fflush.. Видать я его перед считыванием ставил и почему-то так не срабатывало. Поставил после PrintFile и теперь всё в порядке.
Можете пояснить, почему это помогло? Ведь, если запись идет в буфер, то нам все равно не важно это, так как fread так же читает из буфера, а не из файла, разве нет?
kertio
26 / 26 / 1
Регистрация: 20.09.2011
Сообщений: 68
30.10.2012, 07:56     Удалить записанный экземпляр класса из двоичного файла #23
Цитата Сообщение от nexen Посмотреть сообщение
alsav22, Т_Т.. А ведь я же проверял fflush.. Видать я его перед считыванием ставил и почему-то так не срабатывало. Поставил после PrintFile и теперь всё в порядке.
Можете пояснить, почему это помогло? Ведь, если запись идет в буфер, то нам все равно не важно это, так как fread так же читает из буфера, а не из файла, разве нет?
Ты немного не про тот буфер думаешь. буфер записи на винчестер. система кэширует данные в буфере для ускорения операций чтения записи данных. после того как ты записал данные в файл(точнее даже в дескриптор) они пишутся в буфер записи на винчестер. через какое-то время они запишутся физически на диск, не ранее. можно самому эту синхронизацию вызвать через fflush, а можно просто подождать, например через паузу. а буфер чтения это уже другое. поэтому ты и не можешь читать напрямую из буфера, в который ты записал данные. примерно так. это касательно Linux\Unix. хотя и в виндовс скорее всего тоже самое.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 16:49     Удалить записанный экземпляр класса из двоичного файла #24
Цитата Сообщение от nexen Посмотреть сообщение
Можете пояснить, почему это помогло?
Нет, сам не понимаю. Думаю, тут дело в том, что файл открыт одновременно для записи и чтения. Как в таком случае буфер организован, без понятия. Самое интересное в том, что тут не просто чтение неправильно происходит, но и запись в файл, в результате, получится неправильная. Чтение сдвигает курсор для записи? Ещё помогает, если после записи просто указать (через fseek()) откуда читать.
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 не нашел..
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
Будут вопросы, постараюсь объяснить как смогу.
alsav22
5282 / 4801 / 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;
}
nexen
187 / 180 / 3
Регистрация: 27.01.2012
Сообщений: 1,335
30.10.2012, 18:28  [ТС]     Удалить записанный экземпляр класса из двоичного файла #28
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
Toshkarik
 Аватар для Toshkarik
1139 / 856 / 50
Регистрация: 03.08.2011
Сообщений: 2,381
Завершенные тесты: 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.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2012, 19:54     Удалить записанный экземпляр класса из двоичного файла #30
Цитата Сообщение от nexen Посмотреть сообщение
alsav22, у меня подобная конструкция не приводит к порче записи.. Лишь к порче чтения :<
На моём коде проверял? Среда какая?

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

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

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

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

В C++, например, есть функция std::ios::tie для привязки потоков. Так, например, объект std::cin, по умолчанию, "привязан" к объекту std::cout, что гарантирует сброс буфера объекта std::cout перед попыткой ввода с помощью std::cin.
kertio
26 / 26 / 1
Регистрация: 20.09.2011
Сообщений: 68
31.10.2012, 07:16     Удалить записанный экземпляр класса из двоичного файла #34
так вроде бы об этом и шла речь... поэтому и не читаются данные правильно после операций: запись запись запись запись чтение... после записи нужно сделать, грубо говоря commit изменений, а потом читать. и перед тем как писать я прочитал об этой функции. полный справочник шилдта. там есть описание ф-ии.
PS, все равно спасибо. буду больше учить\читать.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.10.2012, 20:25     Удалить записанный экземпляр класса из двоичного файла
Еще ссылки по теме:

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

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

Или воспользуйтесь поиском по форуму:
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
31.10.2012, 20:25     Удалить записанный экземпляр класса из двоичного файла #35
Сейчас посмотрел, как это в линукс работает. Там и без fflush() всё корректно отрабатывает. Только после fflush() изменения (записанные) сразу в файле появляются, а если без, то после первой операции чтения (если в отладке смотреть, а скорее всего, перед первой операцией чтения). Наверное, в линукс синхронизация записи/чтения из файла сделана так же, как для cin/cout (как Toshkarik описывал в 33 посте).
Цитата Сообщение от Toshkarik Посмотреть сообщение
... Так, например, объект std::cin, по умолчанию, "привязан" к объекту std::cout, что гарантирует сброс буфера объекта std::cout перед попыткой ввода с помощью std::cin.
Yandex
Объявления
31.10.2012, 20:25     Удалить записанный экземпляр класса из двоичного файла
Ответ Создать тему
Опции темы

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