文件读取返回损坏的文件结尾

时间:2016-07-15 01:54:25

标签: c++ arrays string

最近,我构建了一个看似简单的text-to-char字符串阅读器,但它似乎在文件末尾返回奇怪的文本。

所以这是我正在尝试阅读的文件之一:

#version 330 core
in vec3 inputColour;

out vec4 outputColour;

void main()
{
    outputColour = vec4(inputColour, 1.0f);
}

这是一个用GLSL编写的OpenGL着色器,fyi。但是,当我尝试“阅读”它时,它会返回:

Console Output

请注意命令窗口末尾的四个2个字符。当我尝试在运行时编译此着色器时,它会返回错误,其中包含一些不在原始文本中的字符。我创建了一个断点并进一步研究了它。我运行了该函数并打开了Text-Visualiser,它返回了这个:

Text Visualiser Image

同样,文本末尾还有另外4个字符ýýýý

这是文本阅读器的代码:

std::ifstream inputFile("foo.txt", std::ios::in|std::ios::binary|std::ios::ate);
int inputFileSize;
char* buffer = "";

if (inputFile.is_open())
{
    inputFile.seekg(0, std::ios::end); //Set the cursor to the end.
    inputFileSize = (int)inputFile.tellg(); //Set inputFileSize to the position of the cursor.
    buffer = new char[inputFileSize]; //Create the buffer and set its size to the inputFileSize.
    inputFile.seekg(0, std::ios::beg); //Move the cursor to the beginning.
    inputFile.read(buffer, inputFileSize); //Read the file from the beginning.
    inputFile.close(); //Close the file
}

我的猜测是它可能与行结尾被不正确地读取有关。但是,我已经使用Notepad ++和内部Visual Studio编辑器编写的文件进行了测试,两者都给了我相同的结果。

我确实找到了“解决方法”。也就是说,这是一个非常糟糕的hacky解决方法,这是非常糟糕的做法。基本上,您可以将[FILEEND]和您阅读的任何文本文件的末尾放在一起。虽然代码允许[FILEEND]或根本不允许,但代码需要[FILEEND]才能正确读取文件。

char* fileend = std::strstr(buffer, "[FILEEND]"); //Find [FILEEND].
int actualfilelen = fileend != NULL ? std::strlen(buffer) - std::strlen(fileend) : std::strlen(buffer); //Get the length of the main content of txt file. 
//If there is no [FILEEND] then return the size of the buffer without any adjustments.
char* output = new char[actualfilelen + 1]; //Create new string with the length of the main content of txt file.
std::strncpy(output, buffer, actualfilelen); //Copy main content of buffer to output.
output[actualfilelen] = '\0'; //Add escape sequence to end of file.
delete(buffer); //Deletes the original buffer to free up memory;

然后我们只返回output变量。 我不想在文件末尾使用[FILEEND]关键字(?),因为它们会立即变得不那么便携。使用[FILEEND]的一个或两个文件可能没问题,但如果我想在其他项目中使用数百个文件,那么它们都会有[FILEEND]

2 个答案:

答案 0 :(得分:1)

您没有确保缓冲区\0已终止。将其设为inputFileSize+1并在阅读后终止它。

std::strlen(buffer)这样的函数期待它。如果你试图在任何地方使用它而不提供长度,它将继续读取超过缓冲区的末尾。

此外,您需要delete[] buffer,因为它已分配new[]

答案 1 :(得分:1)

我提出了一个解决方案,但它涉及使用std::string,然后使用string.c_str()进行转换。

std::string LoadFile(const char* FileLocation)
{
    std::ifstream fileStream;
    std::string fileOutput, currentLine;
    fileStream.open(FileLocation);
    if (fileStream.is_open())
    {
        while (!fileStream.eof())
        {
            std::getline(fileStream, currentLine);
            fileOutput.append(currentLine + "\n");
            std::cout << "> " << currentLine << "\n";
        }
    }

    fileStream.close();

    return fileOutput;
}

然后通过执行LoadFile(“C:\ example.txt”) .c_str(); const char*的等效std::string >或将LoadFile(location)保存到新的std::string并使用.c_str()

注意,.c_str()不能轻易“返回”,因为它是指向局部变量的指针。当函数结束时,该变量将被删除,.c_str()变为空指针。我选择这样做的方法是在函数或API调用需要时使用.c_str()。在C ++中,当您使用std::string而不是char*时,似乎可以省去很多麻烦,尤其是在使用基于文本的文件和 C ++标准库时。