C++ 通过fscanf()获取文本文件中的所有字符将返回无效的字符计数

C++ 通过fscanf()获取文本文件中的所有字符将返回无效的字符计数,c++,c,file,text,C++,C,File,Text,我正在通过c文件从文本文件中获取字符串。我打算使用文本大小获取行。我创建了一个简单的文本文件 a s da 它是7字节。我认为文件大小应该是6字节,因为它有5个字符和一个新行。我已经做过了,估计有2个 '\n' 字符值。我的第一个问题是为什么文本每行放两行新行 然后我使用fscanf函数来获取字符串,但这次它给我的字符数组大小是6而不是7。它忽略了第二个新行字节。但是当我调用fscanf()得到一个字节时,我可以得到所有字节为什么数组有6个字符,甚至我调用fscanf()函

我正在通过c文件从文本文件中获取字符串。我打算使用文本大小获取行。我创建了一个简单的文本文件

   a s
   da
它是7字节。我认为文件大小应该是6字节,因为它有5个字符和一个新行。我已经做过了,估计有2个

  '\n' 
字符值。我的第一个问题是为什么文本每行放两行新行

然后我使用fscanf函数来获取字符串,但这次它给我的字符数组大小是6而不是7。它忽略了第二个新行字节。但是当我调用fscanf()得到一个字节时,我可以得到所有字节为什么数组有6个字符,甚至我调用fscanf()函数得到7个字节

这是我的密码:

#include <iostream>
#include <windows.h>
#include <stdio.h>

using namespace std;

int main() 
{ 
    //Declaring char arrays for every bits//
    char a[1], b[1] , c[1] , d[1] , e[1] , f[1] , g[1] , h[7];

    //Streaming the text file//
    FILE *file;
    file=fopen("conversations.txt","r");


    fseek (file, 0, SEEK_END);   
    int size=ftell (file);
    printf ("Size of myfile.txt: %ld bytes.%c",size , 10);

    //Appending char value of first pointed bit//                           
    fseek ( file , 0 , SEEK_SET );
    fscanf(file, "%1c",a);  
    cout << a[0] << "<-a||";

    fseek ( file , 1 , SEEK_SET );
    fscanf(file, "%1c",b);
    cout << b[0]<< "<-b||";

    fseek ( file , 2 , SEEK_SET );
    fscanf(file, "%1c",c);
    cout << c[0]<< "<-c||";

    fseek ( file , 3 , SEEK_SET );
    fscanf(file, "%1c",d);
    cout << d[0]<< "<-d||";

    fseek ( file , 4, SEEK_SET );
    fscanf(file, "%1c",e);
    cout << e[0]<< "<-e||";

    fseek ( file , 5 , SEEK_SET );
    fscanf(file, "%1c",f);
    cout <<f[0]<< "<-f||";

    fseek ( file , 6 , SEEK_SET );
    fscanf(file, "%1c",g);
    cout << g[0]<< "<-g||";

    //Getting bits of chars
    cout << endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = a[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }
    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = b[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = c[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = d[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = e[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = f[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout<<endl<<endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = g[0] & (1 << i);
    cout << "Bit " << i << ": " << is_set << '\n';
    }


    //Appending  all bytes to one char array//
    fseek ( file , 0 , SEEK_SET );
    fscanf( file, "%7c",h);
    for(int i = 0 ; i < 7 ; i++ )
    {
        cout << h[i];
    }

    cout << endl << endl;

    //Getting bits of chars

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[0] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[1] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[2] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[3] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[4] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[5] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    cout << endl << endl;

    for (int i = 0; i < 8; ++i) {
    bool is_set = h[6] & (1 << i);
    std::cout << "Bit " << i << ": " << is_set << '\n';
    }

    return 0;
}
#包括
#包括
#包括
使用名称空间std;
int main()
{ 
//为每个位声明字符数组//
字符a[1],b[1],c[1],d[1],e[1],f[1],g[1],h[7];
//流式传输文本文件//
文件*文件;
file=fopen(“conversations.txt”、“r”);
fseek(文件,0,SEEK_END);
int size=ftell(文件);
printf(“myfile.txt的大小:%ld字节。%c”,大小为10);
//追加第一个定点位的字符值//
fseek(文件,0,搜索集);
fscanf(文件“%1c”,a);
cout您不能使用
ftell()
来确定文本文件的大小

根据,7.21.9.4
ftell
功能:

ftell
函数获取文件位置的当前值 二进制文件的
指向的流的指示符 流,该值是来自 文件的开头。对于文本流,它的文件位置 指示器包含未指定的信息,可由
fseek使用
用于将流的文件位置指示器返回到
它在调用
ftell
时的位置;差异 两个这样的返回值之间不一定有意义 测量写入或读取的字符数。

Windows(和MS-DOS)使用两个字节序列0x0D 0x0a来表示文本文件中的一个新行。因此,文本中的每一行都在文本文件中产生两个字节。<代码> fSCANF和其他C和C++文本输入函数(以及输出函数)了解它们设计用于的系统的行约定:在输出时,字符

'\n'
生成适当的序列以开始新行,在Windows上为0x0D 0x0A,在典型Unix系统上为0x0A,在旧Mac上为0x0D。在输入时,函数只需反转该过程。因此,在Windows上,代表发送到行尾的数据将作为表示新行的单个字符“
”\n“
”读取


Windows文件中的两个字节有时被惰性地称为
\r\n
,但由于
'\n'
表示换行符,因此写入
“\r\n”
文件将产生0x0D 0x0D 0x0A。最好将文件中的字节视为:CR和LF的ASCII码。正是这两者的组合将输出位置移动到行的开头(CR表示回车),然后将其向下移动到下一行(LF表示换行).

OP试图逐字节查看文件,但仍以“文本”模式打开文件

在文本模式下,可能会发生与行和文件结尾有关的各种翻译。要逐字节读取文件并打印其真值,请以二进制模式打开文件

file=fopen("conversations.txt","rb");
使用二进制模式和
fscanf()
是不可靠的,最好使用
fread()


在Windows中,以文本模式处理文件时,
“\r\n”
序列通常会更改为
”\n'
。单独的
“\n”
序列仍然是
'\n'
。这就是为什么OP会看到2
'\n'
,并且code会尝试以文本模式在选择的偏移量处读取文件。

如果第一个示例应该是一行,那么答案是您使用的是Microsoft Windows,这是现存的少数仍然使用过时的
\r\n
换行符序列。请尝试以“rb”模式而不是“r”模式打开文件。这将以二进制模式打开文件,以便您可以读取文件中的实际字节。此外,在使用
fseek
查找文件结尾后,
ftell
将告诉您文件包含7个字节。@IanAbbott这是不可移植的,实际上是未定义的行为:二进制流不需要有意义地支持
fseekSEEK\u END
whence
值进行调用,并将文件位置指示器设置为文件结尾,就像
fseek(file,0,SEEK\u END)
一样,对于二进制流有未定义的行为……它只起作用,因为它依赖于实现。@AndrewHenle可能是
fseek(file,0,SEEK\u END)
将用于常规文件的二进制流。
SEEK\u END
还有什么其他可能的用途?毕竟,根据标准,它根本不应该用于文本流。@IanAbbott为什么总是必须使用
SEEK\u END
?二进制“文件”没有固定“END”的系统存在或不是一组有序字节。C标准没有说明
fseek()
SEEK\u END
在文本流中无效。它声明
ftell()
无法在文本流上使用以确定其中有多少字节。我了解不同的新行类型。但在检查字节时,我得到的是
0x0A 0x0A
而不是
0x0D 0x0A
。我不确定我的代码是否正确。请看一下好吗?
file=fopen("conversations.txt","rb");