2015-12-17 2 views
0

Я попытаюсь сохранить его коротким и конкретным. Я работаю над проектом, который копирует файл, а затем создает точную копию. Я хотел бы улучшить этот проект, чтобы он копировал файл на сервере и отправил эти данные клиенту, который затем воссоздает файл на локальном компьютере. У меня есть клиент/сервер, настроенный с помощью Winsock, и я могу отправить char * между ними с помощью TCP-сокета. Моя проблема заключается в ... подгонке всех данных этого класса в char *. Я предполагаю, что сериализация - лучший способ сделать это, однако я хочу, чтобы код был как можно более простым и, если возможно, очень хотел бы исключить использование библиотек для этого конкретного проекта.Есть ли способ сериализации класса C++ без использования библиотеки?

Вот мой код на самом деле сохранения файла: ч:

#pragma once 

#include <fstream> 
#include <string> 
using namespace std; 

class SaveFile{ 
private: 
    streampos fileSize;//streampos data type holds current position of the buffer pointer or file pointer 
    char* memBlock; 
    string fileName; 
public: 
    SaveFile(); 
    ~SaveFile(); 

    streampos getSize(); 
    char* getMemBlock(); 

}; 

каст:

#include <iostream> 
#include "SaveFile.h" 

SaveFile::SaveFile(){//default constructor 
    cout << "Please enter file directory: "; 
    cin >> fileName; 

    //ios::ate means that the get pointer will be positioned at end of the file 
    ifstream file(fileName, ios::in|ios::binary|ios::ate); 

    if (file.is_open()){ 
     fileSize = file.tellg();//because get pointer is at end of file, tellg will return size of file in question 
     memBlock = new char[fileSize];//allocating memory for the file 

     file.seekg(0, ios::beg);//return get position to beginning of file 
     file.read(memBlock, fileSize);//read file into memBlock variable 
     file.close();//close file 

     //default destructor will take care of cleanup 
    } 

} 

SaveFile::~SaveFile(){}//default destructor 

streampos SaveFile::getSize(){ 
    return fileSize; 
} 

char* SaveFile::getMemBlock(){ 
    return memBlock; 
} 

Вот код для восстановления файла: ч:

#pragma once 

#include <fstream> 
#include <string> 
using namespace std; 

class SaveFile{ 
private: 
    streampos fileSize;//streampos data type holds current position of the buffer pointer or file pointer 
    char* memBlock; 
    string fileName; 
public: 
    SaveFile(); 
    ~SaveFile(); 

    streampos getSize(); 
    char* getMemBlock(); 

}; 

cpp:

#include <iostream> 
#include "WriteFile.h" 

WriteFile::WriteFile(SaveFile sf){ 
    cout << "Please enter new file name: "; 
    cin >> fileName; 
    ofstream file(fileName, ios::out|ios::binary); 
    file.write(sf.getMemBlock(), sf.getSize()); 
    file.close(); 
} 

WriteFile::~WriteFile(){} 

Пример этого кода в действии будет:

#include "SaveFile.h" 
#include "WriteFile.h" 

int main(){ 
    SaveFile s; 
    WriteFile w(s); 
} 

Так что моя цель здесь каким-то образом сохраняя содержимое класса SAVEFILE к полукокса *, а затем передать, что через сокет TCP для другая машина, которая затем преобразует этот символ * обратно в объект SaveFile и передает его в WriteFile, чтобы он мог воссоздать данный файл.

Любая помощь очень ценится!

+0

Что представляют собой данные 'SaveFile'? – NathanOliver

+1

'SaveFile' и' WriteFile' больше похожи на имена функций, в отличие от имен классов! Пахнет как плохой дизайн классов! – Nawaz

+0

Ах, извините, я включу файл SaveFile.h в одно мгновение. – frank34443

ответ

1

Да, вы можете создать свой собственный процесс сериализации.

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

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

Не-POD-типы не могут быть непосредственно записаны или прочитаны. Например, класс std::string. Класс string имеет некоторые данные-члены, но обычно содержимое строки находится в другом месте (например, в динамической памяти).

Я рекомендую реализовать следующие методы для каждого объекта:

  • Размера байт в буфере - возвращает количество байт в буфере , что этот объект занимает.
  • Загрузить из буфера - загружает его содержимое из указателя в буфер, а увеличивает указатель на размер.
  • Запись в буфер - содержимое хранится в буфер с помощью указателя, а обновляет указатель.

Процесс:

  1. определить размер байтов в буфере для объекта
  2. выделения буфера
  3. Записать буфер с помощью «Записать в буфер» метод
  4. блок запишите буфер в файл или устройство.
+0

Просто задумываясь здесь: В этом случае было бы целесообразно просто изолировать каждую переменную данных, которая мне нужна, чтобы воссоздать файл, преобразовать его в char *, отправить его и затем преобразовать обратно в его исходный тип данных на стороне клиента? Или такой подход связан с созданием ошибок? – frank34443

+0

В большинстве передач данных при записи важные данные копируются в буфер (пакет), затем применяется контрольная сумма и отправляется пакет. На принимающей стороне контрольная сумма проверяется, затем данные копируются из буфера в элементы структуры. Вышеприведенная схема соответствует идее «член данных лучше знает, как записать его содержимое в буфер». Аналогично чтению. Это позволяет объектам изменять с минимальным нарушением процесса связи. –

+0

Благодарим за помощь, я попытаюсь принять ваш подход! – frank34443

Смежные вопросы