【问题标题】:fstream gives me wrong file sizefstream 给了我错误的文件大小
【发布时间】:2020-11-29 22:48:37
【问题描述】:

我编写了将整个文件读入缓冲区的简单函数。

#include <iostream>
#include <fstream>
int main()
{
    std::ios_base::sync_with_stdio(0);
    std::ifstream t;
    t.open("C:\\Users\\sufal\\Desktop\\test.txt");
    t.seekg(0, std::ios::end);    
    long length = t.tellg();           
    t.seekg(0, std::ios::beg);  
    std::cout << "file size: " << length << std::endl;
    char* buffer = new char[length+1];    
    t.read(buffer, length);       
    t.close();
    buffer[length] = 0;
    std::cout << buffer << std::endl;

    
    return 0; 
}

这是 test.txt:

1
2
3

程序产生的输出如下所示:

文件大小应为 5 个字节。为什么我的程序显示错误的文件大小? Windows 资源管理器似乎也显示错误的文件大小为 7 个字节。

【问题讨论】:

  • 这并没有解决问题 l 而是养成使用有意义的值初始化对象的习惯,而不是默认初始化它们并立即覆盖默认值。在这种情况下,这意味着将std::ifstream t; t.open("C:\\Users\\sufal\\Desktop\\test.txt”); 更改为std::ifstream t("C:\\Users\\sufal\\Desktop\\test.txt");。此外,您不必致电t.close();。析构函数会这样做。

标签: c++ windows fstream


【解决方案1】:

在 Windows 上,换行符是 "\r\n",它由两个字节组成。因此,如果您的文件不以换行符结尾,7 确实是它的大小:

1     <-- 1 byte for '1', 2 bytes for CRLF
2     <-- 1 byte for '2', 2 bytes for CRLF
3     <-- 1 byte for '3'

要在字节级别上正确读取文件,您需要以二进制模式打开它:

t.open("C:\\Users\\sufal\\Desktop\\test.txt", ios_base::binary);

(您可以在the documentation 中阅读有关此行为的详细信息)。

您还可以在 C++ 中查看将整个文件读入字符串的其他选项:

【讨论】:

  • 那么二进制模式也适用于读取文本文件?
  • @olaf 不,但是您的代码是以假定读取二进制文件的方式编写的 - 逐字节。如果没有这个标志,ifstream 会解释换行符并修改它们,因此你的人工制品。请参阅链接的问题及其答案,了解利用文本文件读取文件的方法。
【解决方案2】:

您的文件大小为 7 个字节,因为它使用 CRLF 换行符。

1[cr][lf]
2[cr][lf]
3

但是,您正在以 text 模式打开文件,在 Windows 上该模式会将 CRLF 换行符标准化为 LF。您正在为缓冲区分配 7 个 chars,但 read() 仅输出 5 个 chars:

1[lf]
2[lf]
3

这就是为什么您会在打印输出的末尾看到额外的 2 =,因为您没有将未使用的缓冲区空间清零,因此您会看到来自未初始化内存的随机垃圾。

要执行您正在尝试的操作,请改为以 二进制 模式打开文件。

t.open("C:\\Users\\sufal\\Desktop\\test.txt", std::ios_base::binary);

有关详细信息,请参阅 cppreference.com 上的 Binary and text modes

【讨论】:

    【解决方案3】:

    在 Windows 上,这个文件确实是 7 个字节:1\r\n2\r\n3

    Windows 将新行编码为两个字节 - CR + LF(或 \r + \n 其他表示法)。

    一切都正确。

    【讨论】:

    • 所以如果我只想读取整个文件,我应该如何处理这两个 EOL 字符
    • 您会很好地阅读该文件。您可以轻松地假设所有\r 字符结束行并跳过下一个字节。在 Windows 上总是 \r\n\r 不会在其他任何地方使用(基本上)。
    • \r = 十进制的 13,\n = 十进制的 10
    • 那么这就是输出末尾两个等号的原因吗?
    • @loa_in_ + 1 是在缓冲区末尾存储0 所必需的,以获得正确的以空字符结尾的字符串,以便cout 正确打印。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 2010-10-29
    • 1970-01-01
    • 2021-08-04
    • 2016-08-26
    • 1970-01-01
    相关资源
    最近更新 更多