Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Вставка записей в бинарный файл


Автор: shaukote 24.4.2013, 00:18
Всем доброго времени суток.

Встала у меня задача заполнить бинарный файл структурами по возрастанию (некоторого поля).
Соответственно понадобилось как-то вставлять записи в файл.
Я написал довольно очевидный, вроде бы код:
Код

#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <io.h>

using std::cout;
using std::endl;

// структура, которыми будет заполняться файл
struct fileEntry {
    char str[8];
    long number;
};

const size_t size = sizeof(fileEntry);

bool insert(fileEntry, long, FILE*); // вставка записи
bool shift(long, long, FILE*); // сдвиг имеющихся записей для освобождения места
void output(FILE*); // вывод файла

int main()
{
    FILE *file;
    fopen_s(&file, "..\\test", "w+b");

    fileEntry empty;
    strcpy_s(empty.str, sizeof(empty.str), "empty");
    for (int i = 0; i < 5; ++i) {
        empty.number = i;
        fwrite(&empty, size, 1, file);
    }
    output(file);

    fileEntry entry;
    entry.number = 42;
    strcpy_s(entry.str, sizeof(entry.str), "test");

    insert(entry, 2, file);

    output(file);

    fclose(file);
    system("PAUSE");

    return 0;
}

bool insert(fileEntry entry, long pos, FILE* file)
{
    shift(pos, _filelength(fileno(file)) / size - 1, file);
    output(file);

    fseek(file, pos * size, SEEK_SET);
    size_t code = fwrite(&entry, size, 1, file);
    fflush(file);

    return (1 == code);
}

bool shift(long first, long last, FILE* file)
{
    size_t correct = 0;
    fileEntry buffer;

    for (long i = last; i >= first; --i) {
        fseek(file, i * size, SEEK_SET);
        correct += fread(&buffer, size, 1, file);
        correct -= fwrite(&buffer, size, 1, file);
    }
    fflush(file);

    return (0 == correct);
}

void output(FILE* file)
{
    rewind(file);
    fileEntry entry;

    while (fread(&entry, size, 1, file))
        cout << entry.number << " : " << entry.str << endl;
    cout << endl;
}

 
Однако пресловутая функция shift() не работает, увы. То есть она не то, чтобы не сдвигает записи в файле, она вообще его не меняет.  
Буду рад, если кто-нибудь ткнёт меня носом в проблему, поскольку я её найти не могу.  smile

UPD
Слегка модифицировал функцию shift(), добавил, так сказать, отладочный вывод, чтобы понять, что вообще происходит:
Код

bool shift(long first, long last, FILE* file)
{
    size_t correct = 0;
    fileEntry buffer;

    for (long i = last; i >= first; --i) {
        fseek(file, i * size, SEEK_SET);
        cout << "\t" << ftell(file) / size;

        correct += fread(&buffer, size, 1, file);
        cout << "->" << ftell(file) /size;

        correct -= fwrite(&buffer, size, 1, file);
        cout << "->" << ftell(file) / size;
        cout << endl;
    }
    fflush(file);

    return (0 == correct);
}
 
Получил, что указатель в файле движется так:
4->5->5
3->4->5
2->3->4

То, есть он вроде передвигается как надо (но на последнем - пятом - элементе почему-то не сдвигается в третий раз), но никакие изменения в файл не вносятся.  smile 

Автор: feodorv 24.4.2013, 11:22
Потоки плохо переваривают непосредственный переход от чтения к записи:
Цитата(shaukote @  24.4.2013,  01:18 Найти цитируемый пост)
    for (long i = last; i >= first; --i) {
        fseek(file, i * size, SEEK_SET);
        cout << "\t" << ftell(file) / size;
        correct += fread(&buffer, size, 1, file);
        fseek(file, (i+1) * size, SEEK_SET);
        cout << "->" << ftell(file) /size;
        correct -= fwrite(&buffer, size, 1, file);
        cout << "->" << ftell(file) / size;
        cout << endl;
    }

Цитата

For files open for appending (those which include a "+" sign), on which both input and output operations are allowed, the stream should be flushed (fflush) or repositioned (fseek, fsetpos, rewind) between either a writing operation followed by a reading operation or a reading operation which did not reach the end-of-file followed by a writing operation.

Автор: shaukote 24.4.2013, 21:00
feodorv, спасибо, помогло.
Скажите, а есть какое-то объяснение у такого, кхм, "явления"?..

Автор: feodorv 25.4.2013, 08:53
Насколько я помню, какие-то проблемы с буферизацией (буфер на чтение и на запись один и тот же).

Автор: shaukote 25.4.2013, 10:24
feodorv, ясно, спасибо.  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)