2013-09-25 102 views
1

我想写一个链接列表到一个二进制文件,然后在程序启动时读回它。从C++中读取和写入相同的二进制文件

我有同样的编写下面的代码:

class Node 
{ 
    private: 
     int pos; 
     int data; 
     Node* next; 
     Node* prev; 

     friend class Linklist; 

    public: 
     Node(int d):data(d),pos(-1),next(NULL),prev(NULL) 
     {} 

}; 
#include <new> 
#include <sstream> 
#include<iostream> 
#include"linklist.h" 

bool Linklist::insert(int data, bool updateDisk) 
{ 
    if(isExist(data)) 
    { 
     std::cout<<"Tried to insert duplicate data"; 
     return false; 
    } 

    Node *temp = new (std::nothrow) Node(data); 
    if(temp == NULL) 
    { 
     return false; 
    } 

    if(tail == NULL) 
    { 
     tail = temp; 
     head = temp; 
    } 
    else 
    { 
     tail->next = temp; 
     temp->prev = tail; 
     tail = temp; 
    } 

    if(updateDisk) 
    { 
     tail->pos = nextPosition++; 
     updateAdditionOnDisk(tail); 
    } 
} 

bool Linklist::insert(int data, int location) 
{ 
    if(isExist(data)) 
    { 
     return false; 
    } 

    Node *temp = new (std::nothrow) Node(data); 
    if(temp == NULL) 
    { 
     return false; 
    } 

    Node *it = head; 
    while(it != NULL) 
    { 
     if(it->pos > location) 
     { 
      break; 
     } 
     it = it->next; 
    } 

    if(it) 
    { 
     temp->prev = it->prev; 
     temp->next = it; 
     it->prev->next = temp; 
     it->prev = temp; 
    } 

    //tail->position = updateAdditionOnDisk(data, nextAvailablePos); 
} 

bool Linklist::erase(int data) 
{ 
    if(tail == NULL) 
     return false; 

    Node *temp = head; 

    while(temp != NULL) 
    { 
     if(temp->data == data) 
     { 
      //nextAvailablePos = updateDeletionOnDisk(temp->position, nextAvailablePos); 
      if(temp == head) 
      { 
       if(head->next) 
       { 
        head = head->next; 
        head->prev = NULL; 
        delete temp; 
       } 
       else 
       { 
        delete head; 
        head = NULL; 
        tail = NULL; 
       } 
       return true; 
      } 
      else if(temp == tail) 
      { 
       if(head == tail) 
       { 
        delete head; 
        head = NULL; 
        tail = NULL; 
       } 
       else 
       { 
        tail = tail->prev; 
        tail->next = NULL; 
        delete temp; 
       } 
       return true; 
      } 
      else 
      { 
       temp->prev->next = temp->next; 
       temp->next->prev = temp->prev; 
       delete temp; 
       return true; 
      } 
     } 
     temp = temp->next; 

    } 
    return false; 
} 

bool Linklist::isExist(int data) 
{ 
    Node *temp = head; 

    while(temp != NULL) 
    { 

     if(temp->data == data) 
     { 
      return true; 
     } 
     temp = temp->next; 

    } 
    return false; 
} 

void Linklist::display() 
{ 
    Node *temp = head; 
    while(temp != NULL) 
    { 
     std::cout<<temp->data; 
     if(temp->next) 
     { 
      std::cout<<"-->"; 
     } 
     temp = temp->next; 
    } 
} 

int Linklist::updateAdditionOnDisk(Node *node) 
{ 
    oFile.seekp (0, std::ios::beg); 
    oFile.write((char*)&nextPosition, sizeof(int)); 
    oFile.flush(); 

    int count = 0,pos = 0; 
    bool inserted = false; 
    Node n(-1); 
    iFile.seekg (0, std::ios::beg); 
    iFile.read((char*)&pos, sizeof(int)); 
    while(!iFile.eof()) 
    { 
     std::cout<<"iFile is good"; 
     if(n.pos == -1) 
     { 
      oFile.seekp(sizeof(int) + (sizeof(Node) * count) , std::ios::beg); 
      oFile.write((char*)node, sizeof(Node)); 
      oFile.flush(); 
      inserted = true; 
      break; 
     } 
     count++; 
    } 

    if(!inserted) 
    { 
     oFile.seekp(sizeof(int), std::ios::beg); 
     oFile.write((char*)node, sizeof(Node)); 
     oFile.flush(); 
    } 
} 

int Linklist::updateDeletionOnDisk(int data) 
{ 
    int temp = nextPosition + 1; 
    oFile.seekp (0, std::ios::beg); 
    oFile.write((char*)&nextPosition, sizeof(int)); 
    oFile.flush(); 

    int count = 0,pos = 0; 
    bool inserted = false; 
    Node n(-1); 
    n.pos = -1; 
    iFile.seekg (0, std::ios::beg); 
    iFile.read((char*)&pos, sizeof(int)); 
    while(!iFile.eof()) 
    { 
     std::cout<<"iFile is good"; 
     iFile.read((char*)&n, sizeof(int)); 
     if(n.data == data) 
     { 
      n.pos = -1; 
      oFile.seekp(sizeof(int) + (sizeof(Node) * count) , std::ios::beg); 
      oFile.write((char*)&n, sizeof(Node)); 
      oFile.flush(); 
      break; 
     } 
     count++; 
    } 

} 

void Linklist::createListFromFile() 
{ 
    Node n(-1); 

    iFile.seekg(0, std::ios::beg); 
    if(!iFile.eof()) 
    { 
     iFile.read((char*)&nextPosition, sizeof(int)); 
     while(!iFile.eof()) 
     { 
      iFile.read((char*)&n, sizeof(Node)); 
     } 

    } 

} 

Linklist::~Linklist() 
{ 
    while(head) 
    { 
     Node * temp = head; 
     head = head->next; 
     delete temp; 
    } 
} 

int main() 
{ 
    char choice; 
    int data; 

    Linklist l; 

    while (1) 
    { 
     std::cout << "\n\nSelect Opration to performed on LinkList"<<std::endl; 
     std::cout << "1 Insert "<<std::endl; 
     std::cout << "2 Delete "<<std::endl; 
     std::cout << "3 IsExist "<<std::endl; 
     std::cout << "4 Display "<<std::endl; 
    } 

} 

Linklist::~Linklist() 
{ 
    while(head) 
    { 
     Node * temp = head; 
     head = head->next; 
     delete temp; 
    } 
} 

但代码是给我的垃圾输出。

有人可以指出我可能在代码中犯的错误。

感谢

+1

ifstream和ofstream成员变量 –

+0

至少发布'Node'的定义。我敢打赌,这不是POD。这意味着要么你没有保存你所需要的东西,要么你正在调用_undefined behaviour_,就好像它已经过时。 (可能两者都有) – sehe

+0

您是否使用十六进制浏览器检查了文件的内容,看它是否正确写入? –

回答

0

在功能Linklist::updateAdditionOnDisk(),什么是局部变量n的目的是什么?你初始化它,然后检查它,但从不改变它的值。也许你应该消除它,只看node? (顺便说一句,应该声明为指向const Node的指针,因此在保存时不能错误地修改Node实例)。

我看的越多Linklist::updateAdditionOnDisk()我就越困惑。 pos是一个局部变量,每次调用函数时都会从输出文件中读取;它从未被使用或修改过。你有一个循环将永远循环直到n.pos的值不是-1;它也会检查iFile.eof(),但是循环不会从iFile中读取,因此检查将始终成功或始终失败。 count是一个局部变量,始终从0开始......这实际上可能是您的问题。考虑以下行:

oFile.seekp(sizeof(int) + (sizeof(Node) * count) , std::ios::beg); 

这使用count在输出文件中寻找。但count将始终为0,所以这将继续寻找文件的开始并覆盖以前的记录。也许你想要pos而不是count在这里?或者也许node.pos

您是否尝试过在调试器中单步调试程序并观察其功能?对于这个问题,让它打印每个过程的变量值如count,并观察它在输出文件中的搜索方式。

而且,如果您只是试图解决存储值的问题,则可能需要只存储整数值(以count为前缀),或者使用已存储数据的已编写,已调试的库(以JSON格式或HDF5格式,甚至是SQLite数据库文件)。

Linklist::insert()可能会失败。如果location对于列表中的任何Node实例来说过大,则while循环将运行到最后,并将it设置为NULL,然后不会插入任何内容。此外,您没有return true任何地方发信号表示成功添加。

Linklist::createListFromFile()从来没有拨打insert()。所以它实际上并没有建立一个链表。您认为之前发布的代码是insert(),但此代码未调用它。

对不起,但我没有更多的时间。以下是一些指南类型的建议:

  • 将链表写入磁盘的函数根本不需要查找。只需写出数据记录的数量,然后记录所有记录。

  • 你的函数从磁盘读一个链表不应该需要寻求在所有。只需读取数据记录的数量,然后循环,直到您从磁盘读取了许多记录,对从磁盘读取的每个值调用insert()

  • 你叫flush()频繁,但你不应该需要做的,在所有。只需编写所有记录,然后关闭输出文件。

  • 你的函数写入到磁盘应该使用const指针。将数据写入磁盘不应更改数据,因此请使用const来声明您的意图。

  • 写都不可能正常工作,并对其进行测试,并确保它正常工作,你希望它的工作方式是最简单的代码。然后,添加更多功能。我建议你编写一个测试程序,使得包含值1,2,3,4,5和单步的值的链表能够保存该列表到磁盘中,然后读取它并从磁盘文件中建立一个新的链表。

祝你好运,玩得开心。

+0

谢谢steveha,但是指针的值并不重要。如果你看到我在node.data上做一个插入,以确保我没有使用你提到的指针值。问题是我在从磁盘读取文件时发生垃圾 –

+0

n充当从文件中读取数据的占位符,以便可以确定节点的正确位置 –

+0

我只是想了解C++中的文件I/O如何工作。我按照你的建议完成了。事实上,在我发布之前,我删除了整个程序中的日志。我在file.writ之前得到正确的值,但是当我尝试从文件中读取时,我收到垃圾值 –

0

其实,你的代码实例化的Linkedlist一个实例,但只有(隐含)调用它的构造函数和析构函数。

而你的代码不会调用其他任何东西。

您没有提供Linkedlist类的完整声明。所以我们可能只是猜测。在猜测代码的同时,我们可能会猜到很多事情。但可能没有什么可以帮助你。

0

您的代码有很多问题,所以我甚至没有试图猜测它应该做什么。但是,一掠而过,我发现theese两行:

oFile.write((char*)node, sizeof(Node)); 

iFile.read((char*)&n, sizeof(Node)); 

你正在写Node型/读取对象,但Node包含指针!在文件中存储和回顾指针没有任何意义!

相关问题