2012-04-26 4 views
0

Правильно, пожалуйста, несите меня, поскольку у меня есть две отдельные попытки, которые я расскажу ниже.C++ iostream двоичные проблемы с чтением и записью

Сначала я начал читать руководство (http://www.cplusplus.com/doc/tutorial/files/). Однако, хотя он содержит то, что кажется хорошим примером использования read(), в нем нет примера использования функции write().

Сначала я попытался сохранить простой массив символов в двоичном формате, используя write(). Моя оригинальная идея (и надежда) заключалась в том, что я мог бы добавить в этот файл новые записи, используя ios :: app. Первоначально это работало, но я тоже получал нежелательные результаты. Сообщение на другом форуме для справки предложило, что мне не хватало нулевого терминатора в конце моего массива char. Я применил это (или, по крайней мере, попытался на основе того, как я был показан), как видно из приведенного ниже примера. К сожалению, это означало, что read() больше не функционирует должным образом, потому что он не будет считывать нулевой терминатор.

Мне также сказали, что выполнение char *memoryBlock является «злоупотреблением» стандартом C++ или чем-то, и является небезопасным, и что я должен определить массив точного размера, то есть char memoryBlock[5], однако что делать, если я хочу написать данные char к файлу, который может быть любого размера? Как мне продолжить? В приведенном ниже коде содержатся различные пронумерованные строки кода, указывающие различные попытки, которые я сделал, и различные варианты, в том числе некоторые из предложений, упомянутых выше. Я хочу попробовать использовать код хорошей практики, поэтому, если char *memoryBlock небезопасно или какие-либо другие строки кода, я хочу исправить это.

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

Первый код:

#include <cstdlib> 
#include <iostream> 
#include <fstream> 
//#include <string> 


int main() 
{ 
    //char memoryBlock[5]; 
    char *memoryBlock; 
    char *memoryBlockTwo; 
    std::ifstream::pos_type size;// The number of characters to be read or written from/to the memory block. 

    std::ofstream myFile; 
    myFile.open("Example", std::ios::out | /*std::ios::app |*/ std::ios::binary); 

    if(myFile.is_open() && myFile.good()) 
    { 
     //myFile.seekp(0,std::ios::end); 
     std::cout<<"File opening successfully completed."<<std::endl; 
     memoryBlock = "THEN"; 
     //myFile.write(memoryBlock, (sizeof(char)*4)); 
     //memoryBlock = "NOW THIS"; 

     //strcpy_s(memoryBlock, (sizeof(char)*5),"THIS"); 
     //memoryBlock = "THEN"; 
     //strcpy(memoryBlock, "THIS"); 
     //memoryBlock[5] = NULL; 
     myFile.write(memoryBlock, (sizeof(char)*5)); 
    } 
    else 
    { 
     std::cout<<"File opening NOT successfully completed."<<std::endl; 
    } 
    myFile.close(); 

    std::ifstream myFileInput; 
    myFileInput.open("Example", std::ios::in | std::ios::binary | std::ios::ate); 

    if(myFileInput.is_open() && myFileInput.good()) 
    { 
     std::cout<<"File opening successfully completed. Again."<<std::endl; 

     std::cout<<"READ:"<<std::endl; 
     size = myFileInput.tellg(); 

     memoryBlockTwo = new char[size]; 
     myFileInput.seekg(0, std::ios::beg);// Get a pointer to the beginning of the file. 
     myFileInput.read(memoryBlockTwo, size); 

     std::cout<<memoryBlockTwo<<std::endl; 

     delete[] memoryBlockTwo; 
     std::cout<<std::endl<<"END."<<std::endl; 
    } 
    else 
    { 
     std::cout<<"Something has gone disasterously wrong."<<std::endl; 
    } 
    myFileInput.close(); 
    return 0; 
} 

Следующая попытка горных работ на том основании, что попытка использовать ИОС :: приложение с прошивкой :: двоичном просто не будет работать, и что ammend файл я должен прочитайте все это, внесите мои изменения, затем напишите назад и замените все содержимое файла, хотя это выглядит несколько неэффективным.

Однако я не читаю и не помещаю содержимое в свой код ниже. То, что я на самом деле пытаюсь сделать, это написать объект пользовательского класса в файл, а затем снова прочитать его обратно.

Это похоже на работу (хотя, если я делаю что-то плохое мудрёный код здесь, пожалуйста, укажите это), ОДНАКО, я, казалось бы, не в состоянии хранить переменный типа std::string и std::vector, потому что я получаю нарушение прав доступа, когда я достигаю myFileInput.close(). Поскольку эти переменные-члены закомментированы, нарушение прав доступа не происходит. Мое лучшее предположение о том, почему это происходит, заключается в том, что они используют указатели на другие части памяти для хранения своих файлов, и я сам не записываю данные в свой файл, а указатели на него, которые по-прежнему остаются действительными, когда я читаю мои данные.

Возможно ли вообще сохранить содержимое этих более сложных типов данных в файле? Или я должен разбить все на более основные переменные, такие как символы, ints и floats?

Второй код:

#include <cstdlib> 
#include <iostream> 
#include <fstream> 
#include <string> 
#include <vector> 

class testClass 
{ 
public: 
    testClass() 
    { 
     testInt = 5; 
     testChar = 't'; 
     //testString = "Test string."; 
     //testVector.push_back(3.142f); 
     //testVector.push_back(0.001f); 
    } 
    testClass(int intInput, char charInput, std::string stringInput, float floatInput01, float floatInput02) 
    { 
     testInt = intInput; 
     testChar = charInput; 
     testArray[0] = 't'; 
     testArray[1] = 'e'; 
     testArray[2] = 's'; 
     testArray[3] = 't'; 
     testArray[4] = '\0'; 
     //testString = stringInput; 
     //testVector = vectorInput; 
     //testVector.push_back(floatInput01); 
     //testVector.push_back(floatInput02); 
    } 
    ~testClass() 
    {} 

private: 
    int testInt; 
    char testChar; 
    char testArray[5]; 
    //std::string testString; 
    //std::vector<float> testVector; 
}; 

int main() 
{ 
    testClass testObject(3, 'x', "Hello there!", 9.14f, 6.662f); 
    testClass testReceivedObject; 
    //char memoryBlock[5]; 
    //char *memoryBlock; 
    //char *memoryBlockTwo; 
    std::ifstream::pos_type size;// The number of characters to be read or written from/to the memory block. 

    std::ofstream myFile; 
    myFile.open("Example", std::ios::out | /*std::ios::app |*/ std::ios::binary); 

    if(myFile.is_open() && myFile.good()) 
    { 
     //myFile.seekp(0,std::ios::end); 
     std::cout<<"File opening successfully completed."<<std::endl; 
     //memoryBlock = "THEN"; 
     //myFile.write(memoryBlock, (sizeof(char)*4)); 
     //memoryBlock = "NOW THIS"; 

     //strcpy_s(memoryBlock, (sizeof(char)*5),"THIS"); 
     //memoryBlock = "THEN AND NOW"; 
     //strcpy(memoryBlock, "THIS"); 
     //memoryBlock[5] = NULL; 
     myFile.write(reinterpret_cast<char*>(&testObject), (sizeof(testClass)));//(sizeof(char)*5)); 
    } 
    else 
    { 
     std::cout<<"File opening NOT successfully completed."<<std::endl; 
    } 
    myFile.close(); 

    std::ifstream myFileInput; 
    myFileInput.open("Example", std::ios::in | std::ios::binary | std::ios::ate); 

    if(myFileInput.is_open() && myFileInput.good()) 
    { 
     std::cout<<"File opening successfully completed. Again."<<std::endl; 

     std::cout<<"READ:"<<std::endl; 
     size = myFileInput.tellg(); 
     //memoryBlockTwo = new char[size]; 
     myFileInput.seekg(0, std::ios::beg);// Get a pointer to the beginning of the file. 
     myFileInput.read(reinterpret_cast<char *>(&testReceivedObject), size); 

     //std::cout<<memoryBlockTwo<<std::endl; 

     //delete[] memoryBlockTwo; 
     std::cout<<std::endl<<"END."<<std::endl; 
    } 
    else 
    { 
     std::cout<<"Something has gone disasterously wrong."<<std::endl; 
    } 
    myFileInput.close(); 
    return 0; 
} 

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

+0

бит трудно следовать. Боюсь, я не могу разобраться с проблемой, потому что вы прокомментировали код, попробуйте указать минимальный код, который воспроизводит ошибку. Как стартер, вы похожи на то, что у вас есть проблемы с распределением памяти. И какая ошибка, вы получаете дамп ядра, или вы получаете дерьмо в файле? – ColWhi

+0

Код, который в настоящее время предоставляется, дает проблемы, которые я описал. Исключая второй пример с векторами и строками, но я объяснил проблему, связанную с запросами на ответы. Все, что вам нужно сделать, это раскомментировать код, относящийся к векторам и строкам в классе. – Interminable

+0

В первом примере это не будет скомпилировано, поскольку memoryBlock не определен. если вы раскомментировали одно из определений, у вас проблемы, потому что вы не выделяете сколько-нибудь или достаточно места. – ColWhi

ответ

0

В первом примере я не уверен, что вы пишете, поскольку memoryBlock закомментирован и никогда не инициализирован ни к чему. Когда вы его читаете, поскольку вы используете std::cout для отображения данных на консоли, он ДОЛЖЕН быть завершен NULL или вы будете печатать за пределами буфера памяти, выделенного для memoryBlockTwo.

Либо написать завершающего нуль к файлу:

memoryBlock = "THEN"; // 4 chars + implicit null terminator 
    myFile.write(memoryBlock, (sizeof(char)*5)); 

и/или обеспечить буфер прекращается после того, как он читается:

myFileInput.read(memoryBlockTwo, size); 
    memoryBlockTwo[size - 1] = '\0'; 

В вашем втором примере не делают что с объектами C++. Вы обходите необходимые вызовы конструктора, и если вы попытаетесь использовать эти векторы, как вы прокомментировали, это, безусловно, не будет работать так, как вы ожидаете. Если класс - это простые старые данные (не виртуальные функции, не указатели на другие данные), вы, вероятно, будете в порядке, но это по-прежнему очень плохая практика. При сохранении объектов C++ рассмотрите возможность перегрузки операторов и >>.

+0

Причина, по которой исходный запрос не существует, заключается в том, что ios :: ate устанавливает начальную позицию в конце файла? По крайней мере, именно так связан сайт, который я связал, и я действительно получаю данные. Если он удален, я действительно получаю мусор. – Interminable

+0

Да, вы правы, я пропустил эту часть. Должен признаться, я использую этот флаг никогда. –

+0

С моим вторым примером, где вы говорите «не делайте этого с объектами C++», вы ссылаетесь на «testVector = vectorInput;»? – Interminable

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