文件I / O中的不一致

时间:2016-01-01 06:34:05

标签: c++ file-io

我有一个获取ID和记录位置的数据类型。 该文件包含大约1000个项目,每个项目包含id,名字,姓氏,GPA(每个项目共25个字符) 我的程序为每个循环寻找25个字符,只需要ID,将ID和记录号放在表中等等。

然后,用户输入id,我根据给定的id从表中检索项目,之后我得到记录号,在文件中查找项目,然后阅读详细信息。

提供了recordlocation和arrayhashtable类的标题,删除了一些东西以缩短它们

class  RecordLocation{
public:    
    RecordLocation(int idd = -1, int rno = -1);     
    void setId(int);
    int  getId();
    void setRNo(int);
    int getRNo();
    int Hash();    
    int LinearRehash(int initial_hash_value);           
private:
    int id;
    int r_no;
};

/

    typedef RecordLocation ItemType;
    class  ArrayHashTable{  //declares a class data type

    public:
        ArrayHashTable();//Fill info with null studnets
        Error_Code RetrieveItem(ItemType&  item, bool&  found);
        Error_Code InsertItem(ItemType  item);
        Error_Code DeleteItem(ItemType  item);
        void PrintAllItems();
    private:
        ItemType info[MAX_ITEMS];
        int items;
    };

/ data.txt中 短版

4609:hhhhh    hhhhh   :2:4737:ggggg    ggggg   :4:5530:rrrrr    rrrr   :4:4849:ttttttt tttttttttt:2:5563:ddddd    dddd    :2:4959:aaaa    aaaaaaa  :4:

/

void main(){    
    char buffer[26] = { '0' };
    char id_buff[5];
    int id;
    ArrayHashTable object;
    RecordLocation temp;
    ifstream input("data.txt");
    if (!input){
        cout << "Unable to open file " << endl;
        exit(1);
    }

    int i = 0;
    int c;

//location 1    
    do{
        input.seekg(25 * i);
        input.read(id_buff, 4);
        id = convert(id_buff);

        temp.setId(id);
        temp.setRNo(i);
        object.InsertItem(temp);

        i++;

    }while (input);

//location 2        

    input.close();      
}

现在令人困惑的是以下声明:

input.seekg(25 * 3);//3 is arbitrary
    input.read(buffer, 25);
    cout << buffer << endl;

如果要将其放置在位置1,那么它是正常输出。如果它在位置2,则输出为0.如果它在位置1和2中,则两个输出都是正常的。

解决此问题的一种方法是完成do while语句,然后关闭文件并再次打开它,执行语句就可以了。但这不是一个明智的解决方案。

我基本上说的是我已经读完了文件,之后我似乎无法从中获取更多信息。我也没有添加该部分来询问用户ID(使其更简单)

2 个答案:

答案 0 :(得分:1)

根据cplusplus.com,对于C ++ 98:

  

如果在呼叫之前设置了eofbit标志,则该功能失败(设置   failbit and returns)。

因此,一旦你到达文件的末尾,EOF(文件结束)位就会被设置,需要在使用此功能之前重置。

请注意,对于C ++ 11:

  

如果在通话前设置,该功能会清除eofbit标志。

因此,您可以尝试更新的编译器,或使用clear清除eof标志,例如:

input.clear();

答案 1 :(得分:1)

如果对input.read的任何调用失败,您的程序将永远不会注意到,因为您从不检查read方法的返回代码。因此,我们必须弄清楚发生了什么,而不是看到它。幸运的是,在这种情况下这并不太难,但一般来说,如果你养成检查错误返回的习惯,你会觉得生活会更容易。

我们知道,当达到位置2时,会设置input的failbit。这必须是真的,因为在input为假之前,while循环不会退出。

由于设置了failbit,seekgread都没有做任何有用的事情。不修改流位置,不读取数据且未修改缓冲区。

因此,当程序将buffer发送给std::cout时,它发送的内容就是之前buffer中的内容。如果显示的代码位于位置1,则第四条记录仍将位于buffer。否则,buffer将包含单个'0',后跟NUL,因为它已初始化为NUL。 (0和'0'不一样。)

这完美地解释了观察到的行为。在进行搜索之前,您需要清除input的failbit。

实际上,while循环也是错误的。读完最后一个条目后,input仍为good,循环将重复。 read将失败,id保持不变,但由于您没有检查,程序将继续使用虚假ID。现在'input'为false并且解析失败。

如果readseekg失败,您需要做的是退出循环。 input的布尔转换的显式测试是完全没有必要的,因为它来得太晚了没用。