0

对,请耐心等待,因为我将在下面介绍两次单独的尝试。

我首先开始阅读这里的指南 (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::string并且std::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;
}

对于这个问题的冗长,我深表歉意,但我希望我在提供尽可能多的关于我的问题的信息方面的彻底性将加速答案的出现,即使是这样(这甚至可能是一个简单的问题,尽管我已经搜索了几个小时试图找到解决方案),因为时间是这里的一个因素。我将全天监控这个问题,以便在答案的帮助下提供澄清。

4

1 回答 1

0

在第一个示例中,我不确定您要写出的内容已memoryBlock被注释掉并且从未初始化为任何内容。当您读入它时,由于您std::cout用于将数据显示到控制台,因此必须NULL终止它,否则您将在分配给memoryBlockTwo.

将终止的 null 写入文件:

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

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

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

在您的第二个示例中,不要对 C++ 对象执行此操作。您正在规避必要的构造函数调用,如果您尝试使用已注释掉的向量,它肯定不会像您期望的那样工作。如果该类是普通的旧数据(非虚拟函数,没有指向其他数据的指针),您可能会没事,但这仍然是非常糟糕的做法。持久化 C++ 对象时,请考虑考虑重载<<and>>运算符。

于 2012-04-26T15:13:26.407 回答