Каков «лучший» метод записи данных в файл для последующего чтения. - PullRequest
4 голосов
/ 27 октября 2008

Каков наилучший способ хранения данных в файле в сети, который впоследствии будет снова считан программно. Целевой платформой для программы является Linux (Fedora), но для этого потребуется записать файл на компьютер с Windows (XP)

Это должно быть в C ++, будет большое количество событий записи / чтения, поэтому они должны быть эффективными, а данные должны быть записаны таким образом, чтобы их можно было легко прочитать обратно.

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

Подойдет ли простой двоичный потоковый писатель? Как хранить данные - XML?

Что еще мне нужно беспокоиться?


ОБНОВЛЕНИЕ: Для пояснения, вот некоторые ответы на Петерчена очков

Пожалуйста, уточните:

* вы только добавляете блоки, или вы также нужно удалить / обновить их?

Мне нужно только добавить в конец файла, но мне нужно будет найти его и извлечь из любой точки в нем

*** are all blocks of the same size?**

Нет, данные будут различаться по размеру - некоторые будут свободными текстовыми комментариями (например, пост здесь), другие будут конкретными объектно-подобными данными (наборами параметров)

*** is it necessary to be a single file?**

нет, но желательно

*** by which criteria do you need to locate blocks?**

По типу данных и по метке времени. Например, если я периодически выписываю определенный набор параметров, среди других данных, таких как свободный текст, я хочу найти значение этих параметров в определенную дату / время - поэтому мне нужно искать время, которое я записал эти параметры ближе к этой дате и прочитал их обратно.

*** must the data be readable for other applications?**

номер

*** do you need concurrent access?**

Да, я могу продолжать писать, как я читаю. но должен делать только одну запись за раз.

*** Amount of data (per block / total) - kilo, mega, giga, tera?**

Объем данных будет низким для каждой записи ... от количества байтов до сотен байтов купе - всего должно быть не более нескольких сотен килобайт, возможно, до пяти мегабайт. (пока еще не уверен)

**> Если вам нужно все это, бросить свой вызов будет непросто, я бы определенно

рекомендуем использовать базу данных. Если вам нужно меньше, пожалуйста, укажите, чтобы мы могли рекомендуем. **

База данных слишком усложнит систему, поэтому, к сожалению, это не вариант.

Ответы [ 9 ]

5 голосов
/ 27 октября 2008

Ваш вопрос слишком общий. Сначала я определю свои потребности, затем структуру записи для файла, а затем использую текстовое представление для его сохранения. Взгляните на метаформат данных Эрика Стоуна Рэймонда , на JSON и, возможно, CSV или XML . Все пункты Петерчена кажутся актуальными.

3 голосов
/ 27 октября 2008

Вероятно, у вас должен быть другой файл, который будет считан в вектор с данными фиксированного размера.

struct structBlockInfo
    {
        int iTimeStamp;    // TimeStamp 
        char cBlockType;   // Type of Data (PArameters or Simple Text)
        long vOffset;      // Position on the real File
    };

Каждый раз, когда вы добавляете новый блок, вы также добавляете в этот вектор соответствующую информацию и сохраняете его.

Теперь, если вы хотите прочитать конкретный блок, вы можете выполнить поиск по этому вектору, поместите себя в «Реальный файл» с помощью fseek (или чего-либо другого) с соответствующим смещением и прочитайте X байтов (это смещение к начало другого или до конца файла) И выполнить приведение к чему-либо в зависимости от cBlockType, примеры:

    struct structBlockText
    {   
        char cComment[];
    };

    struct structBlockValuesExample1
    {   
        int iValue1;
        int iValue2;
    };

    struct structBlockValuesExample2
    {   
        int iValue1;
        int iValue2;
        long lValue1;
        char cLittleText[];
    };

Прочитать несколько байтов ....

fread(cBuffer, 1, iTotalBytes, p_File);

Если бы это был BLockText ...

structBlockText* p_stBlock = (structBlockText*) cBuffer;

Если это был structBlockValuesExample1 ...

structBlockValuesExample1* p_stBlock = (structBlockValuesExample1*) cBuffer;

Примечание: этот cBuffer может содержать более одного блока.

3 голосов
/ 27 октября 2008

будет большое количество событий записи / чтения, поэтому оно должно быть эффективным,

Это не будет эффективным.

Я много времени уделял этому в те дни Win2K, когда мне приходилось реализовывать программу, в которой, по сути, была копия файла. Я обнаружил, что самым большим узким местом в моей программе, похоже, были накладные расходы в каждой операции ввода-вывода. Единственная наиболее эффективная вещь, которую я нашел в сокращении общего времени выполнения, заключалась в уменьшении количества запрошенных операций ввода-вывода.

Я начал делать симпатичные потоковые операции ввода-вывода, но это было бесполезно, потому что тупой компилятор выдавал ввод-вывод для каждого отдельного символа. Его производительность по сравнению с командой «копировать» оболочки была просто жалкой. Затем я попытался выписать целую строку за раз, но это было лишь незначительно лучше.

В конце концов я написал программу, которая пытается прочитать весь файл в память, так что в большинстве случаев будет только 2 ввода-вывода: один для чтения, а другой для его записи. Именно здесь я увидел огромные сбережения. Дополнительный код, связанный с ручной буферизацией, был более чем компенсирован за меньшее время ожидания завершения операций ввода-вывода.

Конечно, это было около 7 лет назад, поэтому я полагаю, что сейчас все может быть по-другому. Если хотите быть в этом уверенным, оцените сами.

1 голос
/ 27 октября 2008

Я хотел бы проверить Boost Serialization Library

Один из их примеров:

#include <fstream>

// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

/////////////////////////////////////////////////////////////
// gps coordinate
//
// illustrates serialization for a simple type
//
class gps_position
{
private:
    friend class boost::serialization::access;
    // When the class Archive corresponds to an output archive, the
    // & operator is defined similar to <<.  Likewise, when the class Archive
    // is a type of input archive the & operator is defined similar to >>.
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    int degrees;
    int minutes;
    float seconds;
public:
    gps_position(){};
    gps_position(int d, int m, float s) :
        degrees(d), minutes(m), seconds(s)
    {}
};

int main() {
    // create and open a character archive for output
    std::ofstream ofs("filename");

    // create class instance
    const gps_position g(35, 59, 24.567f);

    // save data to archive
    {
        boost::archive::text_oarchive oa(ofs);
        // write class instance to archive
        oa << g;
        // archive and stream closed when destructors are called
    }

    // ... some time later restore the class instance to its orginal state
    gps_position newg;
    {
        // create and open an archive for input
        std::ifstream ifs("filename");
        boost::archive::text_iarchive ia(ifs);
        // read class state from archive
        ia >> newg;
        // archive and stream closed when destructors are called
    }
    return 0;
}
1 голос
/ 27 октября 2008

Вот что у меня есть для чтения / записи данных:

template<class T>
    int write_pod( std::ofstream& out, T& t )
{
    out.write( reinterpret_cast<const char*>( &t ), sizeof( T ) );
    return sizeof( T );
}

template<class T>
    void read_pod( std::ifstream& in, T& t )
{
    in.read( reinterpret_cast<char*>( &t ), sizeof( T ) );
}

Это не работает для векторов, дек и т. Д., Но это легко сделать, просто записав количество элементов, за которыми следуют данные:

struct object {
    std::vector<small_objects> values;

    template <class archive>
    void deserialize( archive& ar ) {
        size_t size;
        read_pod( ar, size );
        values.resize( size );
        for ( int i=0; i<size; ++i ) {
            values[i].deserialize( ar );
        }
    }
}

Конечно, вам нужно будет реализовать функции сериализации и десериализации, но они просты в реализации ...

1 голос
/ 27 октября 2008

Если вы говорите только о нескольких мегабайтах, я бы вообще не хранил их на диске. Иметь процесс в сети, который принимает данные и сохраняет их внутри, а также принимает запросы к этим данным. Если вам нужна запись данных, этот процесс также может записать ее на диск. Обратите внимание, что это звучит очень похоже на базу данных, и это действительно может быть лучшим способом сделать это. Я не вижу, как это усложняет систему. На самом деле, это делает это намного проще. Просто напишите класс, который абстрагирует базу данных, и пусть остальной код использует это.

В прошлом я сам проходил этот же процесс, включая отклонение базы данных как слишком сложной. Все началось довольно просто, но через пару лет мы написали собственную, плохо реализованную, с ошибками, сложную в использовании базу данных. В этот момент мы испортили наш код и перешли на postgres. Мы никогда не сожалели об изменении.

1 голос
/ 27 октября 2008

Ваше приложение звучит так, как будто оно нуждается в базе данных. Если вы можете себе позволить, используйте один. Но не используйте встроенный механизм базы данных, такой как sqlite, для файла через сетевое хранилище, поскольку он может быть слишком нестабильным для ваших целей. Если вы все еще хотите использовать что-то подобное, вы должны использовать это в своем собственном процессе чтения / записи с вашим собственным протоколом доступа, проблемы со стабильностью сохраняются, если вы используете вместо этого текстовый формат файла, такой как XML, так что вам придется делать это то же самое для них.

Я не могу быть уверен, не зная твоей рабочей нагрузки.

1 голос
/ 27 октября 2008

Вам нужно будет посмотреть, какие данные вы записываете. Как только вы работаете с объектами вместо POD, простое выписывание двоичного представления объекта не обязательно приведет к чему-либо, что вы можете успешно десериализовать.

Если вы «только» пишете текст, считывание данных должно быть сравнительно простым, если вы пишете в том же текстовом представлении. Если вы пытаетесь записать более сложные типы данных, вам, вероятно, нужно взглянуть на что-то вроде boost :: serialization.

0 голосов
/ 27 октября 2008

Сохраните его как двоичный файл, если вы не занимаетесь хранением текста. Текст ужасно неэффективен; XML еще хуже. Недостаточная эффективность формата хранения приводит к увеличению передачи файлов, что означает больше времени. Если вам нужно сохранить текст, отфильтруйте его через zip-библиотеку.

Ваша главная проблема - блокировка файлов и параллелизм. Все начинает угасать, когда вам приходится писать / читать / писать одновременно. На этом этапе установите установленную БД какого-либо типа и BLOB-файл, или что-то в этом роде, потому что на этом этапе вы будете писать свою собственную БД .... и никто не хочет изобретать это колесо ( Вы знаете, если они не создают свою собственную компанию БД, или являются аспирантами, или имеют странное хобби ...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...