如何在不读取整个文件的情况下查找文件中字符串的长度

How to find the length of a string in a file without reading the entire file

本文关键字:文件 查找 字符串 情况下 读取      更新时间:2023-10-16

我有一个文件包含一个标题和一个很长的字符串,如:

>Ecoli100k
AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGCTTCTGAACTG
GTTACCTGCCGTGAGTAAATTAAAATTTTATTGACTTAGGTCACTAAATACTTTAACCAATATAGGCATAGCGCACAGAC
....

我试图检索文件大小和头大小使用:

ifstream file(fileName.c_str(), ifstream::in | ifstream::binary);
string line1;
getline(file,line1);
int line1Size = line1.size();
file.seekg(0, ios::end);
long long fileSize = file.tellg();
file.close();

例如,对于包含头为>Ecoli100k的长度为100k的字符串的文件,fileSize为101261,line1Size为10。现在来计算字符串的长度,而不需要再读取:

101261 -(10+1) = 101250这意味着没有头文件,该文件包含101250个字符

101250/81 = 1250,这意味着有1250完整的行(但最后一行没有n),所以我们必须从101250减去1249来得到字符串的长度,但这是错误的。我们得到100k+1,而不是100k。

在代码:

int remainedLineCount = 
        (fileSize - line1Size - 1 - 1 /*the last line has no n*/)/81 ;
cout<<(fileSize - line1Size - 1 - remainedLineCount )<<"n";

在另一个例子中,我只添加了一个字符,由于文件中有换行符,所以大小更改为101263,并且通过此计算,我们将得到100k+2而不是100k+1。

有人知道这个[[extra 1]]是怎么来的吗?文件的末尾有什么吗?

编辑:

根据请求,以下是文件开头和结尾的二进制值(十六进制):

offset 0: 3e 45 63 6f 6c 69 31 30 30 6b

offset 0000018b83: 54 47 47 43 41 47 41 41 43 0a

谢谢。

有几个候选:

  • 如果你在windows下,并且如果文件是以文本模式写入的,那么第一行+换行符将被存储为10+2个字符,因为'n'被翻译成'r'+'n';
  • 再次,如果文件是在文本模式下写入的,可能会添加一个文件结束字符(在文本模式下不可见),在二进制模式下可读。
  • 它也取决于是否在文件的最后一行添加'n'(参见我的第二次编辑下的解释)

附加阅读:

  • 二进制模式和文本模式的区别

编辑:

如果对编码有疑问,可以在文件的开头和结尾显示字节的二进制值(十六进制):

void show (istream &ifs, int count) {  // utility function
    cout <<"offset "<<setw(10)<<ifs.tellg()<<": ";
    for (int i=0; i<10; i++) 
        cout << setw(2) << setfill('0') <<hex<<ifs.get()<<" ";
    cout <<endl; 
}
// with your newly opened filestream: 
show(ifs, 12);  
ifs.seekg(-10,ios::end);
show(ifs, 10);  

编辑2:

所以看起来在最后一行的末尾有一个换行符(在输出中以ASCII码0a结尾)。

理解文本模式和二进制模式可能存在差异是很重要的。c++标准没有详细说明这些,但在其第27.1.9.4节中依赖于C11标准中描述的C studio:

7.21.2/2:文本流是由行组成的有序字符序列,每行由零个或多个字符组成加上一个结束的换行字符。最后一行是否需要终止换行字符是由实现定义的。字符可能需要对输入和输出进行添加、修改或删除遵循不同的约定来表示主机中的文本环境。因此,不需要一对一的对应在流中的字符和外部的字符之间表示。从文本流中读取的数据是必需的与先前写入该流的数据进行比较仅当:数据仅由打印字符和控件组成字符水平制表符和新行;没有换行符紧接空格字符前面;最后一个字符是a新行字符。是否写出空格字符在读入时,紧接在新行字符出现之前实现定义。