ifstream没有读取更新的文件c ++

时间:2016-04-19 16:25:30

标签: c++ ifstream

我正在开展一个项目,我正在使用文件来构建AVL树来存储它。当我写入文件时,数据保存正确,但当我读取数据的位置时,它会返回先前存储在文件中的数据。

到目前为止我的代码

#include "stdafx.h"
#include "AVL.h"
#include <string>
#include <iostream>
#include <fstream>

// When tree is initialized open the input and output files
AVL::AVL(std::string treeFilePath)
{
    inputTreeFile.open(treeFilePath, std::ios::binary);
    if (inputTreeFile.fail())
        std::cout << "failed to open input file" << std::endl;
    outputTreeFile.open(treeFilePath, std::ios::binary | std::ios::trunc);
    if (outputTreeFile.fail())
         std::cout << "failed to open output file" << std::endl;
}

// close the tree files when destructing the tree
AVL::~AVL()
{
    inputTreeFile.close();
    outputTreeFile.close();
}

// writes the node to a given location of the output file
// based on the index of that node
void AVL::writeToDisk(Node node)
{
    outputTreeFile.seekp(node.index * sizeof(Node));
    char * buffer = (char *)&node;
    outputTreeFile.write(buffer, sizeof(Node));
    outputTreeFile.flush();
    if (outputTreeFile.fail())
        std::cout << "failed to write to output file" << std::endl;
}

// reads a node from the file given an index of the file in order to generate an offset
AVL::Node AVL::readFromDisk(int index)
{
    Node node;
    if (index == -1)
        return node;
    inputTreeFile.seekg(index * sizeof(Node));
    inputTreeFile.read((char *)&node, sizeof(Node));
    if (inputTreeFile.fail())
        std::cout << "failed to read from input file" << std::endl;
    return node;
 }

 // inserts a node into the tree and then checks balance factors to decide if a rotation is needed
 // to maintain the balance of the tree

 void AVL::insert(char input[30])
 {
        // If the root is null we only need to do a dumb insert and nothing else
    if (root == -1)
    {
        root = 0;
        node1.balanceFactor = 0;
        node1.count = 1;
        node1.index = 0;
        node1.leftChild = -1;
        node1.rightChild = -1;
        strcpy_s(node1.value, input);
        uniqueInserts++;
        writeToDisk(node1);
        return;
    }

    int p; // our current location on the tree
    int q; // lags behind current node
    int a; // the last parent of current node that had a balance factor of +- 1
    int f; // lags behind recent nonzero

    p = a = root;
    q = f = -1;

    node1 = readFromDisk(root);
    // while the current node is not at the child of a leaf or a duplicate value keep traversing through the tree
    // keeping track of the most recent nonzero balance factor node
    while (p != -1)
    {
        if (strcmp(input, node1.value) == 0)
        {
            node1.count++;
            writeToDisk(node1);
            return;
        }

        if (node1.balanceFactor != 0)
        {
            a = p;
            f = q;
        }

        q = p;
        p = (strcmp(input, node1.value) < 0) ? node1.leftChild : node1.rightChild;
        node1 = readFromDisk(p);
    }

    // Now the previous node is a leaf and the current node is the child of that leaf so we need
    // to create a new node to insert

    // node to insert is y
    node1.balanceFactor = 0;
    node1.count = 1;
    int y = node1.index = uniqueInserts;
    node1.leftChild = -1;
    node1.rightChild = -1;
    strcpy_s(node1.value, input);
    uniqueInserts++;
    writeToDisk(node1);

    int b; // this is the child of the most recent nonzero balance factor in the direction of the potential rotation
    int displacement; // this is used to correct balance factors later

    // we need to know if the new node we are inserting is the left or the right child of the previous node so we
    // can have the correct child pointer point to the new node
    node2 = readFromDisk(q);

    if (strcmp(input, node2.value) < 0)
        node2.leftChild = y;
    else
        node2.rightChild = y;

    writeToDisk(node2);

    // if the value of the node we just inserted is less than that of the most recent nonzero balance factor node
    // then we went left so the pivot needs to be the left child else its the right child
    // the displacement is set based on the direction taken

    node1 = readFromDisk(a);

    if (strcmp(input, node1.value) > 0)
    {
        p = node1.rightChild;
        b = p;
        displacement = -1;
    }
    else
    {
        p = node1.leftChild;
        b = p;
        displacement = 1;
    }

    // then we traverse down from the most recent nonzero balance factor node to the node we inserted setting balance factors
    // on the way down
    while (p != y)
    {
        node1 = readFromDisk(p);

        if (strcmp(input, node1.value) > 0)
        {
            node1.balanceFactor = -1;
            p = node1.rightChild;
        }
        else
        {
            node1.balanceFactor = 1;
            p = node1.leftChild;
        }

        writeToDisk(node1);
    }


    node1 = readFromDisk(a);
    // if the tree was completely balanced recentNonZero will be at the root of the tree and our insert will
    // have pushed the tree slightly out of balance
    if (0 == node1.balanceFactor)
    {
        node1.balanceFactor = displacement;
        writeToDisk(node1);
        return;
    }

    // if the most reent nonzero balance factor is opposite the displacement then we put the tree back in balance 
    if (node1.balanceFactor == -displacement)
    {
        node1.balanceFactor = 0;
        writeToDisk(node1);
        return;
    }

    node2 = readFromDisk(b);
    // At this point we have thrown the tree out of balance by inserting
    // The displacement tells us the first direction of the rotation and the most recent non-zero balance factor node (b) 
    // tells us the second direction
    if (displacement == 1)
    {
        if (node2.balanceFactor == 1) //LL
        {
            // set a's left child to b's right and b's right to a
            // then fix balance factors
            node1.leftChild = node2.rightChild;
            node2.rightChild = a;
            node1.balanceFactor = node2.balanceFactor = 0;
        }
        else //LR
        {
            // create a new node c that is b's right child
            node3 = readFromDisk(node2.rightChild);

            // for this rotation the order of a, b, and c are b < c < a
            // so c gets pulled up to the middle and sets its children to b (left) and a (right)
            // this cuts off c's children though so prior to this c's left needs to be attached as b's right
            // and c's right is attached as a's left

            // then attach c's children to a and b
            node1.leftChild = node3.rightChild;
            node2.rightChild = node3.leftChild;

            // then set c's children to b and a
            node3.leftChild = b;
            node3.rightChild = a;

            // then we set a and b's balance factors to 0 and correct one of them depending on what
            // c's balance factor
            node1.balanceFactor = node2.balanceFactor = 0;

            if (node3.balanceFactor == 1)
                node1.balanceFactor = -1;
            else if (node3.balanceFactor == -1)
                node2.balanceFactor = 1;

            // then c's balance factor is fixed and set to 0
            node3.balanceFactor = 0;
            writeToDisk(node3);
            b = node3.index; // this is for reattaching the subtree to the proper parent
        }
    }
    else // again the next parts are symmetric so almost all the operations are just flipped
    {
        if (node2.balanceFactor == -1) //RR
        {
            node1.rightChild = node2.leftChild;
            node2.leftChild = a;

            node1.balanceFactor = node2.balanceFactor = 0;
        }
        else //RL
        {
            node3 = readFromDisk(node2.leftChild);
            node1.rightChild = node3.leftChild;
            node2.leftChild = node3.rightChild;
            node3.rightChild = b;
            node3.leftChild = a;

            node1.balanceFactor = node2.balanceFactor = 0;

            if (node3.balanceFactor == 1)
                node2.balanceFactor = -1;
            else if (node3.balanceFactor == -1)
                node1.balanceFactor = 1;

            node3.balanceFactor = 0;
            writeToDisk(node3);

            b = node3.index;
        }
    }

    writeToDisk(node1);
    writeToDisk(node2);

    // if the parent of the recent non zero balance factor node was null then there were no nodes with a nonzero balance
    // or the only one was the root. in either case the recent non zero was the root so whatever is in position b needs to 
    // be set as the root
    if (f == -1)
    {
        root = b;
        return;
    }

    node3 = readFromDisk(f);

    // if the left child of the recent nonzero BF parent node is the recent nonzero node we need to attach the new
    // root of the subtree (b) in a's place
    if (node3.leftChild == a)
        node3.leftChild = b;
    else // otherwise its the right child that needs reattached
        node3.rightChild = b;

    writeToDisk(node3);
}

继承人我的主要

#include "stdafx.h"
#include "AVL.h"
#include <fstream>
#include <iostream>
#include <chrono>

using namespace std;

int main()
{
    string inputFilePath = "C:\\Users\\DMCar\\Desktop\\a1s1.txt";

    // set of delimiters for reading in the file
    char delimiters[11] = { 9 , 10 , 13 , 32 , '.' , ',' , '!' , ';' , ':' , '(' , ')' };

    AVL avl("C:\\Users\\DMCar\\Desktop\\test.txt");

    std::ifstream inputStream;
    inputStream.open(inputFilePath, std::ios::binary); // binary flag is set to read the file one byte at a time

                                              // if we couldn't open the file, let the user know and return
    if (inputStream.fail())
    {
        std::cout << "Could not open file" << std::endl;
        return 0;
    }

    bool isDelimiter = false;
    char nextChar;
    inputStream.get(nextChar);

    char input[30]{ 0 };
    int index = 0;

    // keep getting bytes until we have reached the end of the file
    while (!inputStream.eof())
    {
        // loop through the delimiters to check if the character read is one of them
        for each (char delimiter in delimiters)
        {
            // if the character is a delimiter we check to see if the word is empty
            // if the word is not empty it is sent to the trees insert function
            if (nextChar == delimiter)
            {
                if (input[0])
                {
                    cout << input << endl;
                    avl.insert(input);
                }


                memset(input, 0, sizeof(input));
                index = -1;
                isDelimiter = true;
            }
        }

        // if the character was not a delimiter we need to append it to next word
        if (!isDelimiter)
            input[index] = nextChar;

        index++;

        isDelimiter = false; // reset is delimiter

        if (inputStream.eof())
        {
            int i = 1;
            i++;
        }

        inputStream.get(nextChar); // try to read the next character
    }

    if (input[0] != 0)
    {
        avl.insert(input);
    }

    return 0;
}

我从莎士比亚集体作品的第1幕第1场插入,但是在插入第一部&#39; I&#39;在本节

writeToDisk(node2);

// if the value of the node we just inserted is less than that of the most recent nonzero balance factor node
// then we went left so the pivot needs to be the left child else its the right child
// the displacement is set based on the direction taken

node1 = readFromDisk(a);

此时node2包含&#39; ACT&#39;它的右子是1.这被写入位置0.因为a = 0这里node1将从位置0读取。因此回读的内容应与node2相同,但node1没有正确的右子。当它应该是1时,它返回的正确子项是-1。我已经逐步完成了代码,发现所有正确的数据都被写入文件,但是当调用read时,它的行为就像上一次写入从未发生过一样。

这是Node的结构

struct Node {
    int leftChild = -1;
    int rightChild = -1;
    char value[30];
    unsigned int count = 0;
    int balanceFactor = 0;
    int index = -1;
};

有谁知道可能会发生什么?所有的猜测都欢迎我现在已经看了好几个小时,但是无法弄明白。另外,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

那是因为ifstream仅在第一次读取文件并将内容保留在缓冲区中供以后读取。

由于您将以读写模式操作文件,因此您可能只有一个文件处理程序。

第1步: 我们将读写流处理程序组合为一个,在AVL.h:

//std::ifstream inputTreeFile;
//std::ofstream outputTreeFile;
std::fstream treeFile;

第2步: 更改AVL构造函数:

AVL::AVL(std::string treeFilePath)
{
    //inputTreeFile.open(treeFilePath, std::ios::binary | std::ios::);
    //if (inputTreeFile.fail())
    //  std::cout << "failed to open input file" << std::endl;
    //outputTreeFile.open(treeFilePath, std::ios::binary | std::ios::trunc);
    //if (outputTreeFile.fail())
    //  std::cout << "failed to open output file" << std::endl;
    treeFile.open(treeFilePath, std::ios::binary | std::ios::trunc |     std::ios::in | std::ios::out);
    if (treeFile.fail())
        std::cout << "failed to open file" << std::endl;
}

第3步: 在read和write方法中将inputTreeFile和outputTreeFile替换为此treeFile:

// writes the node to a given location of the output file
// based on the index of that node
void AVL::writeToDisk(Node node)
{
treeFile.seekp(node.index * sizeof(Node));
char * buffer = (char *)&node;
treeFile.write(buffer, sizeof(Node));
treeFile.flush();
if (treeFile.fail())
    std::cout << "failed to write to output file" << std::endl;
}

// reads a node from the file given an index of the file in order to generate an offset
AVL::Node AVL::readFromDisk(int index)
{
    Node node;
    if (index == -1)
        return node;
    treeFile.seekg(index * sizeof(Node));
    treeFile.read((char *)&node, sizeof(Node));
    char * p = (char *)&node;
    if (treeFile.fail())
        std::cout << "failed to read from input file" << std::endl;
    return node;
}

现在你将看到预期的结果。