why does removing blank space while writing into file fails reading files? - c++

I'm learning C++, I find problems reading a file if I didn't add blank space while writing into it.
Plus, the file I wrote into doesn't contain blank space as intended.(I opened it with notepad++)
Btw, I'm using code::blocks17.12.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ofstream out("file1");
int i;
ifstream in;
if(!out){cerr << "create file error!\n"; return 1;}
for(i = 1; i<=10; ++i) out << i <<' ';
/*if I remove (<<' ') here, nothing was pirnted on screen. */
out.close();
in.open("file1");
if(!in){cerr << "open file error!\n"; return 1;}
while(in >> i) cout<< i << ' ';
in.close();
return 0;
}

If you write 1, 3 and 8 to a file without spaces then you get 138 how do you now want to figure out that it was not 138 that was written?
The input stream needs some kind of indication of how the numbers are separated.
If you want to know why they decided that writing a number does not automatically add a space, that is because it is not always the desired behavior.
And as Martin Heralecký correctly mentions. in >> i does not read in anything because without spaces 12345678910 is written to the file, which is most certainly out of the range of an int only your setup.
The actual size of an int is platform-dependent but you should not expect that it can store numbers larger than 2147483647.
More details about the Fundamental types: Properties

Related

read a .dat file in c++

I am unable to read '.dat' file. I have tired all the possible ways and tired googling it but I could not find the solution. All it gives me is a null value for integer and a junk value for a string variable or char. This what I have written
ifstream file;
file.open("data1.dat"); // I have also tried this way too like file.open("data1.dat", ios::binary, ios::in);
int data=0;
file >> data;
cout << data << endl;
system("pause");
return 0;
I am using visual studio to compile this code. I am pretty sure that the pointer is entering into the data file but I don't know for what reason the data is not being read.
The .dat file consists of integer number per line ranging from 0, so I just need to read the file and get number from each line and should find the sum of all numbers in the file. The file contains number like
5,
468,
3200,
32, etc.,. Each number is in a new line. The file can contain any number of records. this how .dat file looks when opened using a notepad editor
Your code "works" on my system.
The following compiles (without "using namespace std;")
I changed the file name for my convenience.
I created the 't391.dat' file in the same working directory of the code, and put in 10 lines, with 1 value per line, 1..9,0.
#include <fstream>
#include <iostream>
int t391a(void)
{
std::ifstream file;
file.open("t391.dat");
int data=0;
file >> data;
std::cout << data << std::endl; // echo of input / proof it works
//system("pause");
file.close();
return 0;
}
This code outputs the first value (which is all it attempts to do), so it is working!
The echo of input is good idea.
As an experiment, I temporarily renamed the 't391.dat' file to something else. The code ran to completion and printed a single 0, which is not the first value in the file. Perhaps this suggests your file is not being found, I won't guess. To confirm, I restored the file, and the above 'works' again.
Missing items in your code:
error check - file.open()
a loop to read to end of file
error check - formatted extract (i.e. read from stream) of data item
file.close - possibly not needed
If you are still working this issue, I have a minimally extended version of your code that addresses these issues. Let me know.
class ValueGet {
public:
int data;
ValueGet() {
data = 0;
}
};
int main()
{
ValueGet vg;
ifstream file;
file.open("data1.dat", fstream::binary | fstream::out); // Opens a file in binary mode for input operations i.e., getting data from file.
if (!file)
cout << "File Not Found." << endl;
else {
file.seekg(0); // To make sure that the data is read from the starting position of the file.
while (file.read((char *)&vg, sizeof(vg))) // Iterates through the file till the pointer reads the last line of the file.
cout<<vg.data<<endl;
}
//system("pause");
return 0;
}
output of the data in the file
Here is one way which I just found
#include <bits/stdc++.h>
using namespace std;
int main(){
unsigned int a;
unsigned char c;
ifstream file;
file.open("ou.bin", ios::binary);
if(!file.is_open()){
cout<<"error";
return 0;
}
for(int i=0; i<8; i++){
file>>c;
a = c;
a = a<<8;
file>>c;
a = a+ c;
cout<<a<<endl;
}
file.close();
return 0;
}
This for storing two bytes in a number you can store as many bytes in a number or even one.
Hope this helps.
You will not be able to read .dat files and understand them in your context-- they are general formats used for storing data. Unless you know the contents of it or how they are specified, you will always get junk.

How to update data at a particular line in a file?

Consider i have following file ("testt.txt")
abc
123
def
456
ghi
789
jkl
114
Now if i wanted to update the figure next to name ghi (i.e. 789),
how would i do it?
The following code helps me reach there quickly no doubt, but how to update it quickly?
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
int counter = 0;
string my_string;
int change = 000;
ifstream file ( "testt.txt" );
while(!file.eof())
{
counter = counter + 1;
getline(file, my_string, '\n');
if (my_string == "ghi")
{
ofstream ofile ( "testt.txt" );
for (int i = 0; i < counter + 1; i++)
{
//reached line required i.e. 789
//how to process here?
}
ofile.close();
break;
}
}
cout << counter << endl;
file.close();
return 0;
}
Clearly the counter here is 5 corresponding to "ghi",
so counter + 1 would point to value 789. How to change it to 000?
------------SOLVED-----------FINAL CODE------
#include<iostream>
#include<fstream>
#include<string>
#include <cstdio>
using namespace std;
int main()
{
string x;
ifstream file ( "testt.txt" );
ofstream ofile ( "test2.txt" );
while (!file.eof())
{
getline(file,x);
if (x == "789")
{
ofile << "000" << endl;
}
else
ofile << x << endl;
}
file.close();
ofile.close();
remove("testt.txt");
return 0;
}
Output ("test2.txt")
abc
123
def
456
ghi
000
jkl
114
If you open a file with ifstream for reading, and then with ofstream for writing, the ofstream will either not work or overwrite the file - I am not sure which option is right, but neither is what you want.
So use std::fstream to open a file for reading and writing:
fstream file ( "testt.txt" );
After arriving to the proper place, use the seekp method to enable writing to the stream after reading from it (it often works without seekp, but when it fails, the bug is very difficult to find), as required by the Standard:
if (my_string == "ghi")
{
file.seekp(file.tellg());
...
break;
}
When modifying files, you have to replace the existing bytes with the new ones. It's important to write exactly 3 bytes, so the value 789 is overwritten properly. So you may want to check the range:
if (change < 0 || change > 999)
abort(); // or recover from the error gracefully
And set the width of the output field before writing it:
file << setw(3) << change;
If your code switches from writing back to reading, use file.seekg(file.tellp()) to ensure it works properly.
Doing that is not generally easy, because file systems don't store files line-wise, but instead as sequence of bytes. So if you replace a line with let's say 4 characters in it by a line with 5 characters, you will overwrite something in your next line. You'd have to read the file into memory, and then re-write everything from your changed line on.
That's a horrible approach, because it is incredibly slow, and if you can avoid it by not using a text file to store this kind of information, you should do that. I generally recommend using something like sqlite, for which libraries for all relevant languages exist, if you need to store data in things that feel like tables; for other kind of data, there's other approaches than relational databases, but that depends on what you want to actually store.

How to read a txt file with characters (without spacing) and store into a 2D character array with 15x15 in visual c++?

I'm kind of a newbie in C++ programming.. My command prompt output is a big bulk (repeated) of the characters I have in my txt file. I create a 2d array map[15][15] and try to read the txt file. the reading part is ok but now I dunno how to put them in a 2D character array..
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
char map[15][15];
int alp = 0;
int i = 0;
int main()
{
ifstream in;
//string s;
in.open("city.txt");
if(!in.is_open())
{
cout << "File open error! " << endl;
}
else
{
while(!in.eof())
{
//getline(in, s);
in >> map[i];
i++;
alp++;
//if(in.eof()) break;
cout << map[i] << endl;
}
}
for(i = 0; i <= alp; i++)
{
cout << map[i];
}
in.close();
return 0;
}
eof() will only return true only after the first failed read operation. That operation will not be caught by your code. You could have a test for eof directly after the read and then break if eof(), but that's not elegant:
IO operations on streams return a ref to the given stream. Streams have a meaningful conversion to bool. True indicates that the read was successful, e.g. eof wasn't reached yet, and the read target contains a new correct input value. The idiomatic way of using this feature is "while(in >> map[i])".
As to the algorithm: You say that there are no spaces and I assume it's all ascii chars, so it boils down to double looping over the array's lines and columns with two for loops. Inside those loops would be a line reading each character explicitly with get() like
if(!cin.get(map[i][j])) {/* unexpected eof/io error, abort or whatever */ }
As the data is textual, and separated into lines, I suggest you read directly into the sub-array using e.g. std:istream::getline:
for (size_t i = 0; in.getline(map[i], 15); ++i)
;

Accessing specific lines of text file c++

I want to access specific lines in of text file to display or modify that one. My text file contains lines of different lengths and i heard cannot use seekg or seekp for such files. I got a code but it doesn't works. Can someone please tell me its fault of some other helpful idea?
#include <fstream>
#include <limits>
#include <string>
#include <iostream>
std::fstream& GotoLine(std::fstream& file, unsigned int num)
{
file.seekg(std::ios::beg);
for(unsigned int i=0; i < num - 1; ++i)
{
file.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
}
return file;
}
int main()
{
using namespace std;
std::fstream& GotoLine(std::fstream& file, unsigned int num);
cout << "Starting..." << endl;
fstream file("bla.txt");
GotoLine(file, 8);
string line8;
file >> line8;
cout << "[" << line8 << "]" << endl;
// cin.get();
cout << "Finished..." << endl;
return 0;
}
string line8;
file >> line8;
will only extract until the first whitespace character is hit.
you could use something like:
string line8;
getline(file, line8);
This at least worked for me with the rest of your code on Windows 7 with VS2012
Standard C++11 (and earlier versions of the standard) dont have notion of lines contained inside files. Also POSIX (and even Windows or MacOSX) don't have it. Textual files usually contain lines of variable length (and only the line terminator is relevant, either \n or \r\n or \n\r, depending upon the operating system and perhaps the file read mode -binary or textual-).
In the 1960s or 1970s IBM mainframe OS/360 operating systems had "file" systems which did have files made of fixed-length lines, mimicking punched cards.
So, you have to read your file line by line and remember where are the line limits (or use std::istream::ignore to skip till \n).
Alternatively, read every line of your file into a std::vector<std::string> using std::getline on std::ifstream-s.
For /etc/fstab (or /proc/mounts) reading all the lines in a vector is a good idea, since it is always a tiny file. It usually have less than an few dozens of lines, often less than about a hundred char each. The pathological case could be a file with many thousand lines of comments, but that don't really happen in practice.

Visual C++ - Writing doubles and integers to binary files

I'm reading info from one text file, then outputting it to a bin file. I got the name to write properly, but the integer and doubles do not work properly. Disregard the system("pause"), they are so I can check my outputs.
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
struct SaleSlip{
char name[20];
int prodID;
double value;
};
void main(){
fstream slips, binslip;
SaleSlip sales[17];
binslip.open("SaleSlips.bin", ios::out | ios::binary | ios::trunc);
slips.open("SaleSlips.txt", ios::in);
if(slips.eof()){
cout << "Cannot open file - SaleSlips.txt"<< endl;
system("pause");
exit(2);
}
int i = 0;
while(!slips.eof()){
slips >> sales[i].name;
slips.ignore(80, ' ');
slips >> sales[i].prodID;
slips.ignore(80, ' ');
slips >> sales[i].value;
slips.ignore(80, '\n');
cout << sales[i].name;
cout << sales[i].prodID;
cout << sales[i].value << endl;
binslip.write((const char *)&sales[i].name, sizeof(sales[i].name));
binslip.write((const char *)&sales[i].prodID, sizeof(sales[i].prodID));
binslip.write((const char *)&sales[i].value, sizeof(sales[i].value));
i++;
}
slips.close();
binslip.close();
system("pause");
}
SaleSlips.txt has one line per item of the array so "Ryan 2 1400.52" is one line. Ryan is interpreted correctly, but when I read back in from the binary it isn't right, nor is it when I check it in textpad.
binslip.write is an UnformattedOutputFunction. There is formatted and unformatted input/output. When you use unformatted output, you are writing raw bytes to the file. There is no interpretation as to what the bytes actually represent.
When you wrote to SalesSlips.bin, you wrote characters followed by numbers (rather, what you thought would be numbers). When you tried to examine SalesSlips.bin, the computer read text characters, and was expecting the rest of the file to be text, but it wasn't. Numbers are represented differently then characters. Even if you were to just deal with numbers alone, integral and floating point values are represented differently in binary. It may be a bit much for you to absorb right now, but the gist of it is you need to use a FormattedOutputFunction. This will perform the internal conversions necessary for you to output your data properly.
Imagine you have a number, lets say, 50. That number is meaningless without units that describe what 50 represents. 50 seconds? 50 feet? 50 states? You can think of binslip.write as just writing 50, and when you try to read the file later, all you see is 50, and you don't understand what it was supposed to represent, which is why it looks like gibberish to you.
To fix your code you need to replace the binslip.write lines with this:
binslip << sales[i].name << sales[i].prodID << sales[i].value;
In this case, operator<< behaves as a FormattedOutputFunction, so when you write SaleSlips.bin, you can open it in a text editor and view Ryan 2 1400.52 like you expected.
While reading and writing in BINARY mode, you are not expected to read the data in any text editor. It simply serves no purpose. If you want to read it in a text editor, recommendation is to use NORMAL mode.
Anyways, if you don't bother about viewing your BINARY data in a text editor, you could use the following lines to Read and write binary file:
while(!slips.eof())
{
slips >> sales[i].name;
slips.ignore(80, ' ');
slips >> sales[i].prodID;
slips.ignore(80, ' ');
slips >> sales[i].value;
slips.ignore(80, '\n');
cout << sales[i].name;
cout << sales[i].prodID;
cout << sales[i].value << endl;
//// WRITE THE STRUCTURE AT ONCE
binslip.write((const char *)&sales[i], sizeof(sales[i]));
i++;
}
binslip.flush();
binslip.close();
//// OPEN UP THE FILE IN READ MODE
binslip.open("SaleSlips.bin", ios::in | ios::binary );
SaleSlip sale;
//// READ UP THE COMPLETE STRUCTURE
binslip.read((char *)&sale, sizeof(sale));
//// PRINT IT.
cout<<sale.name;
cout<<sale.prodID;
cout<<sale.value;