C++ 向后读取文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10813930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Read a file backwards?
提问by mezamorphic
Is there a way to read a file backwards, line by line, without having to go through the file from the beginning to start reading backwards?
有没有办法逐行向后读取文件,而不必从头开始读取文件?
采纳答案by hmjd
As per comment, a possible (quite simple) alternative would be read the lines into a vector
. For example:
根据评论,一个可能的(非常简单的)替代方法是将这些行读入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);
}
}
}
EDIT:
编辑:
As per jrok's and Loki Astari's comments, push_back()
would be more efficient but the lines would be in file order, so reverse iteration (reverse_iterator
) or std::reverse()
would be necessary:
根据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);
}
回答by Roger Lipscombe
Use a memory-mapped fileand walk backwards. The OS will page in the needed parts of the file in reverse order.
使用内存映射文件并倒退。操作系统将以相反的顺序在文件的所需部分中分页。
回答by Tejendra
Open the file for read, call
fseek()
to seek to the end of the file, then callftell()
to get the length of the file. Alternatively you can get the file length by callingstat()
orfstat()
Allocate a buffer pointer to the file size obtained in #1, above.
Read the entire file into that buffer -- you can probably use
fread()
to read the file all in one shot (assuming the file is small enough).Use another char pointer to transverse the file from end to beginning of the buffer.
打开文件进行读取,调用
fseek()
seek到文件末尾,然后调用ftell()
获取文件长度。或者,您可以通过调用stat()
或fstat()
为上面#1 中获得的文件大小分配一个缓冲区指针。
将整个文件读入该缓冲区 - 您可能可以使用
fread()
一次性读取所有文件(假设文件足够小)。使用另一个字符指针从缓冲区的末尾到开头遍历文件。
回答by Alexis Wilke
The short answer would be no. However, you can use the seek() function to move your pointer to where you want to go. Then read() some data from that point. If you know well how to manage buffers, then it should be pretty quick because you can read and cache the data and then search for the previous newline character(s). Have fun with \r\n which will be inverted...
简短的回答是否定的。但是,您可以使用 seek() 函数将指针移动到您想去的地方。然后从那个点 read() 一些数据。如果您非常了解如何管理缓冲区,那么它应该很快,因为您可以读取和缓存数据,然后搜索前一个换行符。玩得开心 \r\n 它将被反转......
-- Update: some elaboration on the possible algorithm --
-- 更新:对可能算法的一些详细说明 --
This is not valid code, but it should give you an idea of what I'm trying to say here
这不是有效的代码,但它应该让您了解我在这里想说什么
File reads:
文件写道:
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;
Getting string:
获取字符串:
// 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;
To ease with '\r', you could have a first pass that transforms all '\r' to '\n'. Otherwise, all the tests of '\n' need to also test for '\r'.
为了简化 '\r',您可以进行第一遍将所有 '\r' 转换为 '\n'。否则,'\n' 的所有测试也需要测试 '\r'。
回答by Aadhil RF
Slightly improved version will be this:-
1)Seek to the last-1 position
2)Get the last-1 position
3)Read a char and print it;
4)seek 2 pos back;
5)repeat 3 &4 for last-1
times;
稍微改进的版本将是这样的:-
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();
回答by Personage
My answer is similar to ones that use a vector
to store the lines of the file, but I would instead use a list
.
我的答案类似于使用 avector
存储文件行的答案,但我会使用list
.
Imagine you have the following text in a file called input.txt
:
假设您在名为 的文件中有以下文本input.txt
:
hello
there
friend
I would read the file line-by-line, pushing each line not to the back of my list
but to its front. Using this rather than push_back
has the same effect as reading the contents of the file line-by-line into a vector
and then reversing it or iterating through it backwards.
我会逐行阅读文件,将每一行都推到我的后面而不是list
它的前面。使用 this 而不是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;
}
(Note that the bit at the bottom with std::copy
is just to print the contents of the list with a newline character as a delimiter between elements.)
(请注意,底部的位std::copy
只是使用换行符作为元素之间的分隔符打印列表的内容。)
This then prints:
然后打印:
friend
there
hello