【问题标题】:How to find the length of a string in a file without reading the entire file如何在不读取整个文件的情况下查找文件中字符串的长度
【发布时间】:2016-10-06 18:21:02
【问题描述】:

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

>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();

例如,对于包含长度为 100k 且标题为 >Ecoli100k 的字符串的文件,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 ]] 是从哪里来的吗?文件末尾有什么东西吗?

编辑:

根据要求,这里是文件开头和结尾字节的二进制值(十六进制):

偏移量 0:3e 45 63 6f 6c 69 31 30 30 6b

偏移量 0000018b83:54 47 47 43 41 47 41 41 43 0a

谢谢大家。

【问题讨论】:

  • 用什么字符来标记字符串的结尾?
  • 如果你开始在一个好的十六进制编辑器(不是纯文本编辑器)中查看你正在处理的文件,你会更好,它会显示你每个数据的字节偏移量'重新寻找。然后根据您通过查看文件收集的信息,定制您的程序以适应。 Christophe 给出的答案显示了不同的场景,但如果您最初检查文件,您很容易发现这一点。
  • @ThomasMatthews 我猜什么都没有...我自己从 Rstudio 编写文件并在最后不添加任何内容,但是从 R 中的 Bioconductor Packages 的 DNAString 或 DNAStringset 写入该字符串。你能解释更多如何查看?请查看我帖子中的编辑...

标签: c++ file io


【解决方案1】:

有几个候选人:

  • 如果您在 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 节中对 C 标准输出的依赖,这些内容在 C11 标准中进行了描述:

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

【讨论】:

  • 我在 linux 中,我自己从 RStudio 将文件编写为来自 DNAString 或 DNAStringset 的 .fasta 文件。
  • 刚刚从文件中读取并输出为十六进制的前 12 个字节和 4 个 lasr 字节,并编辑问题以提供此数据
  • 好的,我会的,但是如何提供这些信息?你提到的十六进制...
  • @ameerosein 我已经解释了如何在编辑中做到这一点
  • @ameerosein 好的,所以它更简单:在最后一行添加了换行符。有关原因的解释,请参阅我的编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-13
  • 2019-07-09
  • 1970-01-01
  • 2016-08-14
  • 2017-01-19
  • 2016-07-25
  • 1970-01-01
相关资源
最近更新 更多