C++ 到达文件末尾后从文件中读取

C++ 到达文件末尾后从文件中读取,c++,visual-studio-2012,eof,seekg,C++,Visual Studio 2012,Eof,Seekg,我有一个名为readNextString(ifstream&file,char*&pBuffer)的函数,它从文件中提取下一个字符串,直到到达,“或”\n',删除字符串开头和结尾的空格,将其余字符串保存在pBuffer中,如果一切正常,则返回true,否则返回false。在到达文件末尾之前,一切都正常工作。设置eof标志时,我无法移动get指针。 我试过这个: if(file.eof()) { file.clear(); file.seekg(0 , ios::end) } …然后

我有一个名为
readNextString(ifstream&file,char*&pBuffer)
的函数,它从文件中提取下一个字符串,直到到达
,“
”\n'
,删除字符串开头和结尾的空格,将其余字符串保存在pBuffer中,如果一切正常,则返回true,否则返回false。在到达文件末尾之前,一切都正常工作。设置
eof
标志时,我无法移动get指针。 我试过这个:

if(file.eof())
{
   file.clear();
   file.seekg(0 , ios::end)
}
…然后删除字符串末尾的空白。这几乎起到了作用。函数提取不带空格的字符串,但得到一个无限循环

我的实际问题是:如何检查下一个字符是否为
EOF
,如果不能,是否有其他方法可以这样做

以下是我的实际功能:

bool readNextString(ifstream &file , char* &pBuffer)
{
    if(file.eof()){
        return false;
    }
    for(; file.good() && isWhitespace(file.peek()) && !file.eof() ; file.seekg(1 , ios::cur))
        ;
    if(file.eof()){
        cout << "The file is empty.\n";
        return false;
    }else{
        streamoff startPos = file.tellg();
        cout << "startPos : " << startPos << endl;
        for(;file.good() && file.peek()!='\n' && file.peek()!=',' && file.peek()!= EOF; file.seekg(1 , ios::cur))
            ;
        streamoff A = file.tellg();
        cout << "A : " << A << endl;
        file.seekg(-1 , ios::cur);
        for(;file.good() && isWhitespace(file.peek()) ; file.seekg(-1 , ios::cur))
            ;
        file.seekg(2 , ios::cur);
        streamoff endPos = file.tellg();
        cout << "endPos : " << endPos << endl;
        pBuffer = new char[endPos-startPos];
        if(pBuffer)
        {
            file.seekg(startPos , ios::beg);
            file.get(pBuffer , endPos-startPos , ',' || '\n');
            for(;file.good() && file.peek()!='\n' && file.peek()!=',' && file.peek()!= EOF; file.seekg(1 , ios::cur))
                ;
            file.seekg(2 , ios::cur);
            streamoff temp = file.tellg();
            cout << "temp : " << temp << endl;
            return true;
        }else{
            cout << "Error! Not enough memory to complete the task.\nPlease close some applications and try again.\n";
            return false;
        }
    }
}
bool readNextString(ifstream&file,char*&pBuffer)
{
if(file.eof()){
返回false;
}
对于(;file.good()&&isWhitespace(file.peek())&&&!file.eof();file.seekg(1,ios::cur))
;
if(file.eof()){
库特
如何检查下一个字符是否为EOF

像这样

if (file.peek() == EOF)
{
    // next char is EOF
    ...
}
首先,不要使用seek跳过空白。只需获取 性格和性格是不可能的

第二,你似乎误解了
istream::good()
istream::eof()
。从来没有 无论何时,
istream::good()
合适,并且
istream::eof()
通常仅在输入完成后才适用 失败。对于跳过空白的循环,通常 解决办法是:

while ( isspace( file.peek() ) && file.peek() != EOF ) {
    file.get();     //  ignore read character...
}
其他循环也有类似的注释,除了 您不希望忽略读取的字符。要收集 字符,直到下一个
,”
,例如:

std::string field;
while ( file.peek() != ',' && file.peek() != EOF ) {
    field.push_back( file.get() );
}
(和您的
文件.get(pBuffer,endPos-startPos,','| |'\n')
当然并没有达到您期望的效果;表达式
,'
||“\n”
将始终计算为
true
,在转换时 到
字符
,是
'\01

最后,尽管上述策略会起作用,但它更可取 将较大的文本单位输入到
std::stream
,并解析 也就是说,如果文本是面向行的,请使用以下内容:

std::string line;
while ( std::getline( file, line ) ) {
    //  Parse line, using std::istringstream if appropriate,
    //  although this doesn't seem to be the case for your code.
}

这比你正在做的事情要简单几个数量级。

好的。我做的不是这样!getline()为了胜利!:D 这是我的代码(这次可读性更强):

bool readNextString(ifstream&file,char-pBuffer[])
{
while(isWhitespace(file.peek())&&&!file.eof())
忽略(1);
如果(!file.eof())
{
streamoff start=file.tellg();
stringstream to comma;
if(file.getline(pBuffer,200,,'))
{

仅供参考,你真的不想从这样的文件中解析字符串。要么将整个文件读入缓冲区,要么一次将大块文件读入缓冲区并在内存中解析。不要进行一百万次的读取。这很慢。而对于这一点,实际上更为复杂。@Dave逐字读取并不一定慢;
istream
进行缓冲。但是,使用seek速度很慢;在许多实现中,seek会导致缓冲区丢失,每个字符会有两个系统调用。(不必这样做,但在缓冲区内进行seek应该非常罕见,库不会对其进行优化。)是的,这在我的代码中,但我不能正常工作。当我试图找出下一个“,”,“\n”或在本例中是EOF时,问题出现在第二个for循环中。当我检查get pointer(tellg)的位置时,在我的代码中,我将其保存为“A”,它告诉我位置是-1…:(我不确定,但我认为tellg会失败,因为您试图读取文件的结尾。尝试在调用peek之前调用tellg,而不是之后调用。或者尝试简化。我还没有理解您的问题,或者阅读其他答案,但您的代码看起来确实非常复杂。@john,这是一个很好的观点。Once
file.peek()
返回文件结尾,
tellg
无效,将失败。在输入文件上使用多次传递以进行解析的整个策略已被打破。感谢您提供的详细答案,但我认为这对我没有多大帮助…1.您给我的第一个代码几乎与我的相同,并且无法正常工作。该文件。peek()!=EOF失败。2.第二个代码实际上可能会有帮助…3.关于我的代码-我不太理解您,但我认为它工作得很好,因为问题只出现在文件的末尾…4.对于getline()-这是我的第二个选择,但我想了解如何使用seekg实现这一点…使用此方法一定有办法实现这一点…再次-非常感谢您的帮助:)@dragonator
file.peek()
永不失败。If
file.peek()
返回
EOF
,这可能是因为您在文件末尾,或者您已经遇到了某种错误。单独的代码段用于解释不同的错误:一旦您到达文件末尾,
文件
失败,并且没有其他操作(包括查找)对于3,我引用的行的结束条件是字符
0x01
。或者您读取准确的计数:您可能想要的是
file.read(pBuffer,endPos-startPos)
(但这仍然不是一个好的解决方案)。@dragonator如果目标只是获得
gseek()的经验
:您可能必须在每次搜索之前立即调用
file.clear()
,或者使用C++11(它指定在
seekg
中清除
eofbit
,然后再执行其他操作)。
std::string line;
while ( std::getline( file, line ) ) {
    //  Parse line, using std::istringstream if appropriate,
    //  although this doesn't seem to be the case for your code.
}
bool readNextString(ifstream &file , char pBuffer[] )
{
    while(isWhitespace(file.peek()) && !file.eof())
        file.ignore(1);
    if(!file.eof())
    {
        streamoff start = file.tellg();
        stringstream toComma;
        if(file.getline(pBuffer , 200 , ','))
        {
            toComma << pBuffer;
            toComma.getline(pBuffer ,200, '\n');
            int i=strlen(pBuffer)-1;
            for(; isWhitespace(pBuffer[i]) ;i--)
                ;
            pBuffer[i+1] = '\0';
            file.clear();
            file.seekg(start + strlen(pBuffer) , file.beg);
            return true;
        }else return false;
    }
    return false;
}
void printCities()
{
    ifstream city ;
    city.open("cities.txt", fstream::in);
    if(city.is_open())
    {
        if(!isEmpty(city))
        {
            char currCity[200];
            int counter = 1;
            while(readNextString(city , currCity) && counter < 10)
                cout << counter++ << ". " << currCity << endl;
        }else
            cout << "There are no cities added.\n";
        city.close();
    }else
        cout << "Error by opening 'cities.txt'.Make sure that the file exist and try again.\n";
}