有没有一种方法可以逐行向后读取文件,而不必从头开始读取文件以开始向后读取?
6 回答
使用内存映射文件并向后走。操作系统将以相反的顺序分页文件的所需部分。
根据评论,一个可能的(非常简单的)替代方案是将这些行读入vector
. 例如:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
int main()
{
std::ifstream in("main.cpp");
if (in.is_open())
{
std::vector<std::string> lines_in_reverse;
std::string line;
while (std::getline(in, line))
{
// Store the lines in reverse order.
lines_in_reverse.insert(lines_in_reverse.begin(), line);
}
}
}
编辑:
根据jrok和Loki Astari的评论,push_back()
效率会更高,但行将按文件顺序排列,因此反向迭代 ( reverse_iterator
) 或std::reverse()
将是必要的:
std::vector<std::string> lines_in_order;
std::string line;
while (std::getline(in, line))
{
lines_in_order.push_back(line);
}
打开文件进行读取,调用
fseek()
寻找文件末尾,然后调用ftell()
获取文件的长度。stat()
或者,您可以通过调用或获取文件长度fstat()
将缓冲区指针分配给上面 #1 中获得的文件大小。
将整个文件读入该缓冲区——您可能可以
fread()
一次性读取所有文件(假设文件足够小)。使用另一个 char 指针将文件从缓冲区的末尾横向移动到缓冲区的开头。
稍微改进的版本是这样的:-
1)寻找最后一个位置
2)获取最后一个位置
3)读取一个字符并打印它;
4) 寻找 2 个 pos 回来;
5) 重复 3 &4last-1
次;
ifstream in;
in.open("file.txt");
char ch;
int pos;
in.seekg(-1,ios::end);
pos=in.tellg();
for(int i=0;i<pos;i++)
{
ch=in.get();
cout<<ch;
in.seekg(-2,ios::cur);
}
in.close();
简短的回答是否定的。但是,您可以使用 seek() 函数将指针移动到您想去的地方。然后从那个点读取()一些数据。如果你知道如何管理缓冲区,那么它应该很快,因为你可以读取和缓存数据,然后搜索前一个换行符。玩得开心 \r\n 这将被倒置......
-- 更新:对可能算法的一些阐述 --
这不是有效的代码,但它应该让您了解我在这里要说的内容
文件内容如下:
int fpos = in.size() - BUFSIZ;
char buf[BUFSIZ];
in.seek(fpos);
in.read(buf, BUFSIZ);
fpos -= BUFSIZ; // repeat until fpos < 0, although think of size % BUFSIZ != 0
// now buf has characters... reset buffer position
int bpos = BUFSIZ - 1;
获取字符串:
// first time you need to call the read
if(bpos == -1) do_a_read();
// getting string
std::string s;
while(bpos >= 0 && buf[bpos] != '\n') {
s.insert(0, 1, buf[bpos]);
--bpos;
}
// if bpos == -1 and buf[0] != '\n' then you need to read another BUFSIZ chars
// and repeat the previous loop...
// before leaving, skip all '\n'
while(bpos >= 0 && buf[bpos] == '\n') {
--bpos;
}
return s;
为了简化 '\r',您可以先将所有 '\r' 转换为 '\n'。否则,'\n' 的所有测试也需要测试'\r'。
我的答案类似于使用 avector
来存储文件行的答案,但我会改为使用list
.
假设您在名为 的文件中有以下文本input.txt
:
hello
there
friend
我会逐行阅读文件,不是将每一行推到我的后面,list
而是推到它的前面。使用它而不是push_back
与将文件的内容逐行读取到 avector
然后反转它或向后迭代它具有相同的效果。
#include <iostream>
#include <fstream>
#include <list>
#include <string>
#include <iterator>
#include <algorithm>
int main(void) {
std::ifstream file;
file.open("input.txt");
// Make sure the file opened properly
std::list<std::string> list;
std::string buffer;
while (std::getline(file, buffer)) {
list.push_front(buffer);
}
file.close();
std::copy(
list.begin(),
list.end(),
std::ostream_iterator<std::string>(std::cout, "\n")
);
return 0;
}
(请注意,底部的位std::copy
只是打印列表的内容,并使用换行符作为元素之间的分隔符。)
然后打印:
friend
there
hello