文本文件二进制搜索

Text File Binary Search

本文关键字:搜索 二进制 文件 文本      更新时间:2023-10-16

我有一个测试文件,如下所示:

Ampersand           Gregorina           5465874526370945
Anderson            Bob                 4235838387422002
Anderson            Petunia             4235473838457294
Aphid               Bumbellina          8392489357392473
Armstrong-Jones     Mike                8238742438632892

代码如下:

#include <iostream>
#include <string>
#include <fstream>
class CardSearch
{
protected:
    std::ifstream cardNumbers;
public:
    CardSearch(std::string fileName)
    {
        cardNumbers.open(fileName, std::ios::in);
        if (!cardNumbers.is_open())
        {
            std::cout << "Unable to open: " << fileName;
        }
        return;
    }
    std::string Find(std::string lastName, std::string firstName)
    {
        // Creating string variables to hold first and last name
        // as well as card number. Also creating bools to decide whether
        // or not the person has been found or if the last name is the only
        // identifier for a found person
        std::string lN;
        std::string fN;
        std::string creditNumber;
        bool foundPerson = false;
        // By using the seekg and tellg functions, we can find our place
        // in the file and also calculate the amount of lines within the file
        cardNumbers.seekg(0, std::ios::beg);
        cardNumbers.clear();
        std::streamsize first = cardNumbers.tellg();
        cardNumbers.ignore(std::numeric_limits<std::streamsize>::max());
        cardNumbers.clear();
        std::streamsize last = cardNumbers.tellg();
        cardNumbers.seekg(0, std::ios::beg);
        std::streamsize lineNumbers = (last / 57);
        std::streamsize middle;
        while (first <= lineNumbers)
        {
            middle = (first + lineNumbers) / 2;
            // middle * 57 takes us to the beginning of the correct line
            cardNumbers.seekg(middle * 57, std::ios::beg);
            cardNumbers.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
            cardNumbers >> lN >> fN;
            if (lN < lastName)
            {
                first = middle + 1;
            }
            else if (lN > lastName)
            {
                lineNumbers = middle - 1;
            }
            else
            {
                if (fN < firstName)
                {
                    first = middle + 1;
                }
                else if (fN > firstName)
                {
                    lineNumbers = middle - 1;
                }
                else if (fN == firstName)
                {
                    foundPerson = true;
                    break;
                }
            }
        }
        if (foundPerson)
        {
            // When a person is found, we seek to the correct line position and 
            // offset by another 40 characters to receive the card number
            cardNumbers.seekg((middle * 57) + 40, std::ios::beg);
            std::cout << lN << ", " << fN << " ";
            cardNumbers >> creditNumber;
            return creditNumber;
        }
        return "Unable to find person.n";
    }
};
int main()
{
    CardSearch CS("C:/Users/Rafael/Desktop/StolenNumbers.txt");
    std::string S = CS.Find("Ampersand", "Gregorina");
    std::cout << S;
    std::cin.ignore();
    std::cin.get();
    return 0;
}

除了列表中的第一条记录外,我可以检索到所有记录。看起来好像seekg在寻找正确的位置,但cardNumbers没有读取正确的信息。当"middle"设置为0时,seekg应查找第0行(middle*57),读取Ampersand Gregorina并进行比较。相反,它仍然在读安德森·鲍勃。

关于为什么会发生这种情况,有什么想法吗?

感谢

LineNumbers正在被循环修改,从4到1再到-1。-1使您的循环过早终止,因此您无法正确拾取第一个条目。

这似乎是一个家庭作业问题,所以我希望你能用它来引导自己找到答案。

使用seekg等函数时,最好以binary mode打开文件,而不是像您的代码现在所做的那样以文本模式打开文件。换句话说,你应该这样做:

cardNumbers.open(fileName, std::ios::in | std::ios::binary);

原因是以文本模式打开文件将允许完成行末翻译。这使得seekgtellg等函数在最好的情况下不稳定(或幸运地工作),在最坏的情况下对文本处理毫无用处。

当文件以二进制模式打开时,seekg和其他函数族会按预期工作,因为没有行末转换。实际上,您将在指定的文件中查找字节偏移量,而不会被行末转换所丢弃。

此外,一旦这样做,行中数据的长度不仅包括可见文本,还包括组成行序列末尾的不可见字符。因此,在二进制模式下,你手工计算的57是不正确的——它应该是58或59,这取决于你使用的是Linux/Unix还是Windows。