Reading the last line of a file

I have a large file and I need to get only the last line ( \n only line separator).
I need this to be done on an iOS device, so it cannot take up a lot of memory or processor time (e.g. reading the entire file).
How to do it in Objective-C, C ++ or C ++ 11?

+4
source share
4 answers

I have a function in my production code. The idea is that you are trying to read the last line, trying to find and read. Look here please.

 bool readLastLine(std::string const& filename, std::string& lastLine) { std::ifstream in(filename.c_str(),std::ifstream::binary); if(!in) return false; in.seekg(0, std::ifstream::end); const std::streamoff len = in.tellg(); //empty file if(len == 0) { lastLine = ""; return true; } int buf_size = 128; std::vector<char> buf; while(in) { if(buf_size > len) { buf_size = len; } buf.resize(buf_size); in.seekg(0 - buf_size, std::ifstream::end); in.read(&buf[0],buf_size); //all content is in the buffer or we already have the complete last line if(len == buf_size || std::count(buf.begin(), buf.end(), '\n') > 1) { break; } //try enlarge the buffer buf_size *= 2; } //find the second line seperator from the end if any auto i = std::find(++buf.rbegin(),buf.rend(), '\n'); lastLine.assign(i == buf.rend() ? buf.begin() : buf.begin() + std::distance(i, buf.rend()), buf.begin() + buf_size); return true; } 
+3
source

Itโ€™s clear that you want to open the file and search all the way to the end minus N bytes (maybe 80 or something else). Then read this and find \ n. If you do not find it, then first find N bytes and try it in this set of N bytes, and so on, until you find \ n.

As for specific calls, it is just a matter of how to open a file, search in it and read data. It should be pretty simple. But I think this is what you would like to do and choose a size for N that is not too large.

+5
source

@ Nerdtron's answer seems most appropriate to me if you have no control over your file format, but ...

If you have control over the file format, you can do this with O (1) complexity. Just write the offset of the beginning of the last line to the (constant) offset at the beginning of the file when writing data to it. When you want to read it, read this offset and go to the offset indicated in it.

+2
source

I came up with this, trying to improve the situation with Bruce, at the top - itโ€™s not necessary to change the size of the buffer, just continue to read fragments of characters from the same size from EOF:

 std::string lastLine(std::ifstream &file) { if (!file.good()) throw exception("Bad stream on input"); const size_t bufSize = 80; // because why not? tweak if need to char buf[bufSize]; string line; int seek, nloff; // iterate over multiples of bufSize while file ok for (size_t n = 1; file; ++n) { // next seek position will be a multiple of bufSize seek = -static_cast<int>(n * bufSize); file.seekg(seek, file.end); // read "bufSize" bytes into buffer file.read(buf, bufSize); // in case no newline found, seek past eof nloff = -seek; // find offset of last newline in buffer for (size_t i = 0; i < bufSize; ++i) { if (buf[i] == '\n') nloff = i; } seek += nloff + 1; // new seek position is one character after found newline if (seek >= 0) continue; // just kidding about the "past eof" part ;) // seek to after found newline and get line file.seekg(seek, file.end); getline(file, line); if (!line.empty()) break; // have result, break and return } if (file.good()) return line; else return string(); } 
0
source

Source: https://habr.com/ru/post/1383264/


All Articles