I am new to programming and I have this question. I have this file that I am opening
ifstream fin;
FILE * pFile;
pFile = fopen (fname,"r");
The file has 3 data each line. The first is an integer, the second is an alphabet and the third is an address(like computer memory address). How do I extract these line by line into 3 variables that I can process, and then repeat it with next line and so.
You should know that there are preferred C++ methods for manipulation of files over C stdio methods:
Using standard predefined streams: std::ofstream for output and std::ifstream for input.
Formatted/Unformatted I/O such as operator<<(), operator>>(), read() and write().
In-memory I/O for manipulation of extracted data.
What you need for this particular case is input stream functionality along with formatted input. The formatted input will be done through operator>>().
But before you get to that, you have to instantiate a file stream. Since you're using input, std::ifstream will be used:
std::ifstream in("your/path.txt");
The next thing to do is to create the three variables whose values you will extract into the stream. Since you know the types beforehand, the types you will need is an integer, character, and string respectively:
int num;
char letter;
std::string address;
The next thing to do is to use operator>>() to obtain the first valid value from the stream. The way it works is that the function analyses the type of the righthand operand and determines if the characters extracted from the file stream will create a valid value after parsing. When the stream hits whitespace, the new line character or the EOF (end-of-file) character (or a character that doesn't match that of the operand's type), extraction will stop.
What makes IOStreams powerful is that it allows chaining of expressions. So you are able to do this:
in >> num >> letter >> address;
which is equivalent to:
in >> num;
in >> letter;
in >> address;
This is all that is needed for this simple case. In more complex situations, loops and in-memory I/O might be needed for successful extractions.
Related
So, I'm having some issues with my c++ code. I have the following code, but so far I can't get most of the data stored into the structured data type.
//structured data declaration
struct item
{
int itemCode;
char description[20];
float price;
};
And then the get code looks like this.
cout << setprecision(2) << fixed << showpoint;
ofstream salesFile ("Sales.txt");
ifstream stockFile ("Stock.txt");
for (counter = 0; counter < 9; counter++)
{
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
}
The output should have looked like:
1234 "description here" 999.99
Quantity X
And this was the output:
1234 0.00
Quantity 5
If you have a file format that is of the form (for one entry)
1234
description here
999.99
(across multiple lines) then the explanation is simple
Th reading code in your loop, which does
stockFile >> instock[counter].itemCode;
stockFile.getline (instock[counter].description, 20);
stockFile >> instock[counter].price;
will work in this sequence
The value of instock[counter].itemCode will receive the value 1234. However (and this is important to understand) the newline after the 1234 will still be waiting in the stream to be read.
The call of getline() will encounter the newline, and return immediately. instock[counter].description will contain the string "".
The expression stockFile >> instock[counter].price will encounter the d in description. This cannot be interpreted as an integral value, so instock[counter].price will be unchanged.
Assuming some preceding code (which you haven't shown) sets instock[counter].price to 999.99 the above sequence of events will explain your output.
The real problem is that you are mixing styles of input on the one stream. In this case, mixing usage of streaming operators >> with use of line-oriented input (getline()). As per my description of the sequence above, different styles of input interact in different ways, because (as in this case) they behave differently when encountering a newline.
Some people will just tell you to skip over the newline after reading instock[counter].itemCode. That advice is flawed, since it doesn't cope well with changes (e.g. what happens if the file format changes to include an additional field on another line?, what happens if the file isn't "quite" in the expected format for some reason?).
The more general solution is to avoid mixing styles of input on the one stream. A common way would be to use getline() to read all data from the stream (i.e. not use >> to interact directly with stockFile). Then interpret/parse each string to find the information needed.
Incidentally, rather than using arrays of char to hold a string, try using the standard std::string (from standard header <string>). This has the advantage that std::string can adjust its length as needed. std::getline() also has an overload that can happily read to an std::string. Once data is read from your stream as an std::string, it can be interpreted as needed.
There are many ways of interpreting a string (e.g. to extract integral values from it). I'll leave finding an approach for that as an exercise - you will learn more by doing it yourself.
I am trying to read text from a file into an array and then output the contents of each array index to the output file. I need the data to be read/stored until it reaches the end of line, at which point it should re-start reading/storing and re-using the array for temporary storage only to be output to the output file.
I cannot use the getline function because the idea is that later I will incorporate the use of some model classes to store the individual words as member variables of the classes. I will need to have the words separated to know which words get saved as which variables. For this reason I need to be able to just identify the corresponding index position and get it's contents.
I know my syntax is incorrect so I was hoping someone knew a correct syntax for recognizing the end of line.
this is what I've tried so far:
ifstream fin;
//open file...
char next[20]; //creating an word array to hold the characters of a word.
fin >> next;
while (!fin == '\n') //<------ THIS IS WHAT I THINK THE PROBLEM IS.
//I KNOW ITS INCORRECT BUT DO NOT KNOW THE CORRECT WAY.
{
//input words, store to array, and output to file
fin >> next;
}
You should use a std::string instead of a char array to handle words of any size. Streams also have an implicit conversion to void* (bool in C++11 or later) to test if the stream is still valid.
std::ifstream fin(filename);
std::string word;
while(fin >> word) {
//do something with word
}
i'm trying to ready a binary-file into a set of variables using the c++ std::ifstream class.
The following example works:
std::ifstream inFile;
inFile.open("example.bin");
uint8_t temp8;
uint16_t temp16;
inFile >> temp8;
inFile >> temp8;
But if i replace the last two lines with one line
inFile >> temp16;
nothing is read and inFile.fail() returns true.
Can anyone explain, why I can't read into a 16 bit variable?
The operator>> overload for reading uint16_t from istreams is a formatted input function, meaning does not read binary data, it reads a string and if necessary converts it to a number (e.g. using strtoul or similar).
As explained at http://en.cppreference.com/w/cpp/io/basic_istream
The class template basic_istream provides support for high level input operations on character streams. The supported operations include formatted input (e.g. integer values or whitespace-separated characters and characters strings) and unformatted input (e.g. raw characters and character arrays).
inFile >> temp16 tries to read a sequence of (usually) ASCII digits, up to the first non-digit character, then converts that sequence of digits to a number, and if it fits in uint16_t stores it in temp16. If you are reading from a binary file then the istream is probably not going to find a sequence of ASCII digits, so reading fails.
You need to use an unformatted input function to read 16 bits directly from the file without trying to interpret a string as a number, like:
inFile.read(reinterpret_cast<char*>(&temp16), 2);
The extraction of an integer from a stream with >> expects to find ascii numeric digits. If it doesn't find them, it sets the fail status.
If your uint16_t data is not by pure coincidence composed by two bytes, which the first appear to be between 0x30 and 0x39, it's doomed to fail. ANd if it would succed, it wouldn't be the values that you expect.
For binary data use:
inFile.read (&temp16, sizeof(temp16));
and of course, open the file with ios::binary mode.
I'm having a problem reading from a binary file (*.dat) using the .read(reinterpret_cast (&x),sizeof(x)) command but there is always an error about the existence of the file even when the file exist or has been created successfully. Here is the code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct x{
char name[10],pass[10];
};
int main()
{
x x1,x2;
fstream inout;
inout.open("test.dat" ,ios::binary);
if(!inout)
{
cout<<"Error";
exit(1);
}
cout<<"Enter your name:";
cin>>x1.name;
inout.write(reinterpret_cast <const char*> (&x1.name), sizeof(x1));
cout<<"Enter your name:";
cin>>x1.pass;
inout.write(reinterpret_cast <const char*> (&x1.pass), sizeof(x1));
while(inout.read(reinterpret_cast <char*> (&x2.name), sizeof(x1)))
{
cout<<x2.name;//here is my problem cannot read!!
}
inout.close();
}
Use std:flush after your write operations.
// ... Write x1.name and x1.pass
inout << std::flush;
// ... Read x2.name in while loop.
inout.close();
There is a problem with your output to the file.
First you are writing the struct x1 to the file where only the name field is filled
inout.write(reinterpret_cast <const char*> (&x1.name), sizeof(x1));
and afterwards:
inout.write(reinterpret_cast <const char*> (&x1.pass), sizeof(x1));
You start writing from the address of x1.pass but you are writing sizeof(x1) bytes.
sizeof(x1) is 20 here but its only 10 bytes from the start of x1.pass to the end of the struct, so you are writing 10 bytes of unknown data from the stack into your file.
So this is the first thing that your file may not contain what you expect it to contain.
The next thing is that after writing your data the stream is sitting at the end of the file and you try to read from there. You have to move the position back to the beginning of the stream to read the stuff you just wrote. For example use:
inout.seekg(std::ios::beg);
If you mess with read and write to the same stream, you'd rather use flush or file positioning functions.
MSDN says:
When a basic_fstream object is used to perform file I/O, although the underlying buffer contains separately designated positions for reading and writing, the current input and current output positions are tied together, and therefore, reading some data moves the output position.
GNU Stdlib:
As you can see, ‘+’ requests a stream that can do both input and output. When using such a stream, you must call fflush (see Stream Buffering) or a file positioning function such as fseek (see File Positioning) when switching from reading to writing or vice versa. Otherwise, internal buffers might not be emptied properly.
Reading into raw C-style arrays from an input stream is not as idiomatic as a simple call to operator>>(). You also have to prevent buffer overruns by keeping track of the both the bytes allocated for the buffer, and the bytes being read into the buffer.
Reading into the buffer can be done by using the input stream method getline(). The following example shows the extraction into x1.name; the same would be done for x1.path:
if (std::cin.getline(x1.name, sizeof(x1.name))) {
}
The second argument is the maximum number of bytes to be read. It is useful in that the stream won't write pass the allocated bounds of the array. The next thing to do is just write it to the file as you have done:
if (std::cin.getline(x1.name, sizeof(x1.name))) {
inout.write(reinterpret_cast<char*>(&x1.name), std::cin.gcount());
}
std::cin.gcount() is the number of characters that were read from the input stream. It is a much more reliable alternative to sizeof(x1.name) in that it returns the number of characters written, not the characters allotted.
Now, bidirectional file streams are a bit tricky. They have be coordinated in the right way. As explained in the other answers, bidirectional file streams (or std::fstreams) share a joint buffer for both input and output. The position indicators that mark positions in the input and output sequence are both affected by any input and output operations that may occur. As such, the file stream position has to be "moved" back before performing input. This can be done by either a call to seekg() or seekp(). Either will suffice since, as I said, the position indicators are bound to each other:
if (std::cin.getline(x1.pass, sizeof(x1.pass))) {
inout.write(reinterpret_cast<char*>(&x1.pass), std::cin.gcount());
inout.seekg(0, std::ios_base::beg);
}
Notice how this was done after the extraction into x1.pass. We can't do it after x1.name because we would be overwriting the stream on the second call to write().
As you can see, extracting into raw C-style arrays isn't pretty, you have to manage more things than you should. Fortunately, C++ comes to the rescue with their standard string class std::string. Use this for more efficient I/O:
Make both name and pass standard C++ strings (std::string) instead of raw C-arrays. This allows you pass in the size as the second argument to your read() and write() calls:
#include <string>
struct x {
std::string name;
std::string pass;
};
// ...
if (std::cin >> x1.name) {
inout.write(x1.name.data(), x1.name.size());
}
if (std::cin >> x1.pass) {
inout.write(x1.name.data(), x1.name.size());
inout.seekg(0, std::ios_base::beg);
}
std::string allows us to leverage its dynamic nature and its capacity for maintaining the size of the buffer. We no longer have to use getline() but now a simple call to operator>>() and an if() check.
This was not possible before, but now that we're using std::string we can also combine both extractions to achieve the following:
if (std::cout << "Enter your name: " && std::cin >> x1.name &&
std::cout << "Enter your pass: " && std::cin >> x1.pass) {
inout.write(x1.name.data(), x1.name.size());
inout.write(x1.pass.data(), x1.pass.size());
inout.seekg(0, std::ios_base::beg);
}
And finally, the last extraction would simply be this:
while (inout >> x2.name)
{
std::cout << x2.name;
}
I have an input stream with the following lines:
# <int> <int>
<some_data_type> <some_data_type> <some_data_type> ..... <some_data_type>
<some_data_type_1> <some_data_type_2> <some_data_type_3> <some_data_type_1> <some_data_type_2> <some_data_type_3> .... <some_data_type_1> <some_data_type_2> <some_data_type_3>
In the above stream all three lines are different and have to be parsed differently. Currently,I am using a reading method as follows:
void reader( std::istream & is, DataStructure & d ){
std::string line;
getline(is,line);
std::stringstream s(line);
//parse line 1
getline(is,line);
std::stringstream line2(line);
//parse line 2
getline(is,line);
std::stringstream line3(line);
//parse line 3
}
Now the idea is not to make use of std::stringstream at all, as a line can arbitarily large and we donot want to load everything into memory twice. So, it would be better if it was possible to read from the input stream directly into the user given datastructure d.
An idea is to make use of std::istream_iterator but unfortunately the different lines have different parsing needs. For example, in the last line, three elements from the stream together constitute a single data element.
The only idea that seems plausible to me at this moment is to handle the stream buffer directly. It would be great if anyone could recommend a better way of doing this.
NOTE: Cannot make use of a tertiary data structure like std::stringstream. It is essential to read from the stream directly into the user provided data structure.
EDIT: Please note we are only allowed a single pass over the file.
Now the idea is not to make use of std::stringstream at all, as a line
can arbitarily large and we donot want to load everything into memory
twice. So, it would be better if it was possible to read from the
input stream directly into the user given datastructure d.
Olaf explained the extraction operator above but then we have a new requirement:
This will only work for the first line, where it is known there is a
fixed number of elements.
and
(2) Unfortunately, I have no discriminator beyond my knowledge that each instance of the data
structure needs to be instantiated with information stored in three
different lines. All three lines have different lengths and different
data elements. Also, I cannot change the format.
plus
(3) All information is treated as unsigned integer.
Now the next issue is that we don't know what the data structure actually is, so given what has come before it appears to be dynamic in some fashion. Because we can treat the data as unsigned int then we can use the extraction operator possibly, but read into a dynamic member:
vector<unsigned int> myUInts;
...
inFile >> currentUInt;
myUInts.push_back(currentUInt);
But then the issue of where to stop comes into play. Is it at the end of the first line, the third? If you need to read an arbitrary number of unsigned ints, whilst still checking for a new line then you will need to process white space as well:
inFile.unsetf(ios_base::skipws);
How you actually handle that is beyond what I can say at the moment without some clearer requirements. But I would guess it will be in the form:
inFile >> myMember;
char next = infile.peek()
//skip whitespace and check for new line
//Repeat until data structure filled, and repeat for each data structure.
Then do not use std::getline() at all. Define an istream operator for your types and use these directly
std::istream &operator >>(std::istream &f, DataStructure &d)
{
f >> d.member1 >> d.member2 >> ...;
return f;
}
void reader(std::istream & is, DataStructure &d)
{
is >> d;
}
There's no need fiddling with an std::istream_iterator or directly manipulating the stream buffer.