std::ifs.seekg problem

Hi, I was trying to create class through which I could read specific characters in a file using operator[] and it kind of worked.
It was working if there was only a single long line but if there were multiple lines in my file I got an extra new line for every new line, for example :
File:
Line 1
Line 2
Line 3
Line 4

Output:
Line 1

Line 2

Line 3

Line 4

Why are those extra new lines happening?

This is my class
1
2
3
4
5
6
7
8
9
class file_handle
{
	std::ifstream ifs;
	std::size_t lenght;
public:
	file_handle(const std::string& filename);
	char operator[](std::size_t pos);
	std::size_t size() { return lenght; }
};

definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
file_handle::file_handle(const std::string& filename) : ifs{filename, std::ios::in},
lenght{(ifs.seekg(0, std::ios_base::end), ifs.tellg())} {
	if (!ifs) throw std::runtime_error{ "Couldn't open file " + filename + " for reading" };
}

char file_handle::operator[](std::size_t pos)
{
	if (pos < 0 || pos > lenght)  throw std::ios_base::failure{"file_handle::operator[] : pos out of range"};

	ifs.seekg(pos, std::ios_base::beg);
	char ch;
	ifs.get(ch);
	return ch;
}


And actual file reading just to see if it works
1
2
3
4
5
6
7
8
	std::string filename{ "text.txt" };
	file_handle handle{ filename };

	for (int i = 0; i < handle.size(); ++i)
	{
		std::cout << handle[i];
	}
	std::cout << '\n';


All code together if anybody wants to check himself/herself.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

class file_handle
{
	std::ifstream ifs;
	std::size_t lenght;
public:
	file_handle(const std::string& filename);
	char operator[](std::size_t pos);
	inline std::size_t size() { return lenght; }
};

file_handle::file_handle(const std::string& filename) : ifs{filename, std::ios::in},
lenght{(ifs.seekg(0, std::ios_base::end), ifs.tellg())} {
	if (!ifs) throw std::runtime_error{ "Couldn't open file " + filename + " for reading" };
}

char file_handle::operator[](std::size_t pos)
{
	if (pos < 0 || pos > lenght)  throw std::ios_base::failure{"file_handle::operator[] pos out of range"};

	ifs.seekg(pos, std::ios_base::beg);
	char ch;
	ifs.get(ch);
	return ch;
}



int main()try
{
	std::string filename{ "text.txt" };

	file_handle handle{ filename };

	for (int i = 0; i < handle.size(); ++i)
	{
		std::cout << handle[i];
	}
	std::cout << '\n';

	return 0;
}
catch (const std::ios_base::failure& exc)
{
	std::cerr << exc.what() << '\n';
	return -1;
}
catch (const std::runtime_error& exc)
{
	std::cerr << exc.what() << '\n';
	return -1;
}
can't reproduce, so my guess is that your input file was created on windows https://en.wikipedia.org/wiki/Newline#Representations
> Why are those extra new lines happening?

For streams opened in text mode, seeks to arbitrary positions are not supported (both C and C++).

a. Open the file in binary mode (read byte by byte, without escape sequence translations).
b. Streams opened in binary mode are not required to support seek to the end; so check for seek failure.
c. EDIT: Use std::streamsize std::streamoff instead of std::size_t

1
2
3
4
5
file_handle::file_handle(const std::string& filename) : ifs{ filename, std::ios::binary } //,
// lenght{(ifs.seekg(0, std::ios_base::end), ifs.tellg())} {
{
	if (!ifs) throw std::runtime_error{ "Couldn't open file " + filename + " for reading" };
}


1
2
3
4
5
6
7
8
9
10
11
char file_handle::operator[]( std::streamoff pos )
{
    if( ifs.seekg(pos, std::ios_base::beg) )
    {
        char ch;
        ifs.get(ch);
        return ch;
    }

    else throw std::ios_base::failure{"file_handle::operator[] pos out of range"};
}
Last edited on
Thank you guys, much appreciated :) This opening in binary mode really fixed this. Link was cool as well!

PS. Does "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference" talks about "problems" such as this? I'm considering buying it and just wanted to know how detailed it is. Not that there are any better book about the topic anyway so this questions is probably pointless :D Just curiosity!
Last edited on
C++ defines low-level file stream operations in terms of C99.

std::ifstream::seekg => std::filebuf::pubseekoff/pubseekpos => std::filebuf::seekoff/seekpos => std::fseek

std::fseek
If the stream is open in text mode, the only supported values for offset are zero (which works with any origin) and a value returned by an earlier call to std::ftell on a stream associated with the same file (which only works with origin of SEEK_SET.
http://en.cppreference.com/w/cpp/io/c/fseek


> Does "Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference" talks about "problems" such as this?
> I'm considering buying it and just wanted to know how detailed it is.

TOC: http://www.angelikalanger.com/IOStreams/contents.htm
As always thank you man! Looks like the book is not that super in depth but definitely worth reading!
Topic archived. No new replies allowed.