C ++ iostream二进制读写问题

时间:2012-04-26 14:39:30

标签: c++ binary iostream

是的,请耐心等待,因为我将在下面进行两次单独的尝试。

我首先开始阅读这里的指南(http://www.cplusplus.com/doc/tutorial/files/)。然而,尽管它包含了一个如何使用read()的好例子,但它不包含如何使用write()的示例。

我首先尝试使用write()以二进制形式存储一个简单的char数组。我最初的想法(和希望)是我可以使用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;
}

我的下一次尝试是基于尝试将ios :: app与ios :: binary一起使用根本不起作用,并且要修改文件我必须阅读整个内容,进行我的修改,然后回写并替换文件的全部内容,尽管这似乎效率低下。

但是我没有在下面的代码中读入并修改内容。我实际上要做的是将一个自定义类的对象写入一个文件,然后再将其完整地读回来。

这似乎有用(虽然如果我在这里做任何不好的代码,请指出它),但是,我似乎无法存储std::stringstd::vector类型的变量,因为当我到达myFileInput.close()时,我遇到访问冲突。将这些成员变量注释掉后,不会发生访问冲突。我最好的猜测是为什么会发生这种情况是他们使用指向其他内存块的指针来存储他们的文件,我不是将数据本身写入我的文件,而是指向它的指针,当我读到我的文件时它仍然有效数据输出。

是否可以将这些更复杂的数据类型的内容存储在文件中?或者我是否必须将所有内容分解为更多基本变量,如字符,整数和浮点数?

第二段代码:

#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;
}

我为这个问题的长篇大论道歉,但我希望我尽可能多地提供有关我的问题的信息将加快答案的出现,即使是这样(甚至可能是一个简单的问题)修复虽然我已经搜索了几个小时试图找到解决方案),因为时间是一个因素。我将全天监控这个问题,以便在答案的帮助下作出澄清。

1 个答案:

答案 0 :(得分:0)

在第一个例子中,我不确定你写的是什么memoryBlock被注释掉了,从未初始化为任何东西。当您正在阅读它时,因为您使用std::cout向控制台显示数据,它必须被NULL终止,否则您将打印超出为{{1}分配的内存缓冲区的末尾}。

将终止空值写入文件:

memoryBlockTwo

和/或,确保缓冲区在读取后终止:

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

在第二个示例中,不要对C ++对象执行此操作。你正在绕过必要的构造函数调用,如果你尝试使用像你已经注释掉的向量那么它肯定不会像你期望的那样工作。如果类是普通的旧数据(非虚函数,没有指向其他数据的指针),你可能会没问题,但它仍然是非常糟糕的做法。在持久化C ++对象时,请考虑调查 myFileInput.read(memoryBlockTwo, size); memoryBlockTwo[size - 1] = '\0'; <<运算符的重载。