在C++中读取非文本文件

3
我误打开了mp3文件,使用Notepad++(在打开方式中)打开并将整个文件以文本形式显示在Notepad中,非常酷。 由于我正在重新学习c ++,我告诉自己让编写一个程序,可以在控制台内打开任何文件并在控制台上显示它们的内容,所以我像这样开始编写代码:
int readAndWrite() {

    string filename(R"(path\to\a\file)");

    ifstream file(filename);



    string line;

    if (!file.is_open()) {
        cerr << "Could not open the file - '"
             << filename << "'" << endl;
        return EXIT_FAILURE;
    }

    while (getline(file, line)){
        cout << line;
    }

    return EXIT_SUCCESS;
}

但它只显示了文件的3或4行,然后退出程序,我再次检查我的notepad++,发现其中有大约700,000行。我告诉自己也许文件中有一个字符,所以我开始写上面的代码并进行以下更改。不要显示文件,而是将其写入文本文件中。

int readAndWrite() {

    string filename(R"(path\to\a\file)");
    string filename2(R"(path\to\a\file\copy)");

    ifstream file(filename);
    ofstream copy(filename2);


    string line;

    if (!file.is_open()) {
        cerr << "Could not open the file - '"
             << filename << "'" << endl;
        return EXIT_FAILURE;
    }

    while (getline(file, line)){
        copy << line;
    }

    return EXIT_SUCCESS;
}

再试一次,还是得到了同样的结果。接下来,我放弃逐行读取文件,而是使用这个函数进行复制。

void copyStringNewFile(ifstream& file, ofstream& copy)
{
    copy << file.rdbuf();
}

他们的结果没有改变一点。

此时,我告诉自己问题可能来自于文件,而实际上也是这样,因为当我使用简单的文本文件时,以上所有代码都可以正常工作。


2
有一个猜想,如果你将 ifstream file(filename); 改为 ifstream file(filename, std::ios::binary);,会有什么不同吗? - JaMiT
无论如何,path\to\a\file\copy 都不会起作用,因为 file 不是一个目录。 - Ted Lyngmo
可能是 MP3 文件内部某处有 EOF 字符,您尝试在不同的文件上运行它了吗?也许一些包含几行普通文本的简单文本文件? - Lumorti
@jamit /@/ted-lyngmo,没有区别,即使我删除它,复制文件也会被创建。 - Milad
1个回答

2

和其他非文本文件一样,mp3 文件不包含 ,因此不应使用 std::getline。应该使用 istream::readostream::write。您可以使用 istream::gcount 检查实际读取的字符数。

由于您正在处理非文本文件,还要以 binary 模式打开文件。

您还应测试是否可以打开两个文件 - 即输入文件和输出文件。

示例:

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>

int readAndWrite() {
    std::string filename(R"(path\to\a\file)");
    std::string filename2(R"(path\to\a\file_copy)");

    std::ifstream file(filename, std::ios::binary);
    if(!file) {
        std::cerr << '\'' << filename << "': " << std::strerror(errno) << '\n';
        return EXIT_FAILURE;
    }

    std::ofstream copy(filename2, std::ios::binary);
    if(!copy) {
        std::cerr << '\'' << filename2 << "': " << std::strerror(errno) << '\n';
        return EXIT_FAILURE;
    }

    char buf[1024];
    while(file) {
        file.read(buf, sizeof(buf));
        // write as many characters as was read above
        if(!copy.write(buf, file.gcount())) {
            // write failed, perhaps filesystem is full?
            std::cerr << '\'' << filename2 << "': " << std::strerror(errno) << '\n';
            return EXIT_FAILURE;
        }
    }

    return EXIT_SUCCESS;
}

int main() {
    return readAndWrite();
}

谢谢,但我再次测试你的代码时只有几行被复制了。原始文件大小为1MB,而复制文件大小约为1KB。 - Milad
@Milad,这里没有“行”。这段代码“应该”生成与您读取的文件完全相同的副本。您确定您没有查看输出文件的旧副本吗? - Ted Lyngmo
我将你的代码复制粘贴到我的主程序中,结果如我所说,原始文件超过1Mb,但复制文件只有约322字节。 - Milad
@Milad 请先删除复制文件,然后重新运行程序。顺便问一下,你的文件系统是否已满?我在循环中添加了一个新的测试。 - Ted Lyngmo
谢谢,需要进行清洁重建并且已经工作了。你从哪里得到的buf[1024]?我读了一个教程,他使用了buf[4096]。 - Milad
@Milad 很好,不用谢!1024 是凭空想象出来的。4096 同样可以正常工作。 - Ted Lyngmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接