I've been trying to grasp how reading and writing with the fstream class works, and I've become stuck. The program reads the magic number of the file correctly, and then suddenly fails to read an integer. I'm guessing I am missing something very obvious, but after several Internet searches, I've come up with nothing. If someone could point out what I'm missing, it would be extremely appreciated. Thanks!
#include <fstream>
#include <iostream>
#include "File.h"
using namespace std;
const char magicnumber[8] = {'C','H','S','R','L','I','N','E'};
const int magiclength = 8;
void saveLines(char* filename, int linenum, Line* lines){
//Create the file and write the magic number to it
ofstream file(filename, std::ios::trunc);
for(int kkk = 0; kkk < magiclength; kkk++)
file << magicnumber[kkk];
//Write the number of lines we expect
file << linenum;
//Write the lines' data
for(int iii = 0; iii < linenum; iii++){
file << lines[iii].start.x << lines[iii].start.y;
file << lines[iii].finish.x << lines[iii].finish.y;
file << lines[iii].thickness;
}
cout << linenum << endl;
file.close();
}
Line* openLines(char* filename){
ifstream file(filename);
if(!file.is_open())
return NULL;
//Read the magic number of the file
char testnumber[12];
for(int jjj = 0; jjj < magiclength; jjj++)
file >> testnumber[jjj];
//Make sure the file contains the right magic number
for(int iii = 0; iii < magiclength; iii++){
if(testnumber[iii] != magicnumber[iii])
return NULL;
}
//Get the number of lines
int linenum = -1;
file >> linenum;
cout << linenum << endl;
if(linenum <= 0 || file.fail())
return NULL;
Line* product = new Line[linenum];
for(int kkk = 0; kkk < linenum; kkk++){
file >> product[kkk].start.x >> product[kkk].start.y;
file >> product[kkk].finish.x >> product[kkk].finish.y;
file >> product[kkk].thickness;
}
file.close();
return product;
}
In the openLines() function, the file opens correctly, and the magic number is read and matched correctly, but when the variable "linenum" is read, the file reads as gibberish, the fail() flag turns true, and the function returns NULL. If it matters, here's the Line struct:
typedef struct{
int x, y;
} Point;
typedef struct{
float slope;
float thickness;
Point start;
Point finish;
bool defined;
} Line;
I am using SDL in this project. I do not know if this matters, but I'm including it for completeness' sake. In cout.txt I get 2 (For the linenum when I'm writing the file) and then 2147483647 when I read it back. Thanks for looking!
Related
I'm looking to store a txt file with 52 characters that have no spaces into a char array. What I have below only outputs garbage. I would appreciate on some insight on how to solve this.
`
int main()
{
fstream fin, fout;
int maxSize = 9999; // Max length for text file.
int sizeArray = 0; //Stores length of message.txt file.
char storeCharacter[maxSize]; //Array that stores each individual character.
fin.open("message.txt");
if(fin.fail())
{
cout << "Input file failed to open (wrong file name/other error)" << endl;
exit(0);
}
sizeArray = fileLength(fin, storeCharacter, maxSize); //Assigns size using fileLength function.
cout << sizeArray << endl;
char txtCharacters[sizeArray];
storeInArray(fin, txtCharacters, sizeArray);
for(int i=0; i<=sizeArray; i++)
{
cout << txtCharacters[i];
}
fin.close();
fout.close();
return 0;
}
int fileLength(fstream& fin, char storeCharacter[], int length)
{
char nextIn;
int i = 0;
fin >> nextIn;
while(!fin.eof())
{
storeCharacter[i] = nextIn;
i++;
fin >> nextIn;
}
return i; //returns the file size.
}
void storeInArray(fstream& fin, char arr[], int length)
{
int i = 0;
char nextIn;
while(!fin.eof() && i!=length )
{
fin >> nextIn;
arr[i] = nextIn;
i++;
}
}
`
I tried to use a while and for loop to store the txt file characters into a char array. I was expecting it to work since I have done a similar thing with a txt file full of integers. Instead garbage gets outputted instead of the contents of the text file.
first error here is that VLA is not a standard c++ feature. Do not use it
char txtCharacters[sizeArray];
also do not do
while(!fin.eof()
read Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
next
fileLength reads to the end of the file but you do not rewind the file after that. This function loads the file into an array anyway so why the read it (or try to) into a second array.
also
for(int i=0; i<=sizeArray; i++)
you mean
for(int i=0; i<sizeArray; i++)
way simpler is to read into std::vector, no need to calculate initial size. Just push_back each char
From the world of old-school, we use fopen, fread and fclose:
#include <stdio.h>
int read_file(const char* path, char* data, int max_length)
{
FILE *fp = fopen(path, "rb");
if (!fp) return 0;
int n = fread(data, 1, max_length, fp);
fclose(fp);
return n;
}
int main()
{
char data[1024] = { };
int l = read_file("message.txt", data, 1024);
printf("length = %d\n", l);
printf("text = %s\n", data);
return 0;
}
For the following message.txt (the alphabet twice with a trailing new line character, i.e. 26 + 26 + 1 = 53 bytes)
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
I get the following output:
length = 53
text = ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Somethings you'll note:
The read_file is implemented as a refactor of fopen, fread and fclose
We open the file in read-only binary mode
If the file didn't exist or there was a reason why we couldn't open, we early exit with 0 bytes read
We read up to a maximum of max_length and return the actual bytes read
We make sure we close the file before exiting
In the main I declare data as 1024 bytes, i.e. 1K which is more than enough
I ensure that the data has been zero-initialized, so, if nothing populates it, it will contain NUL characters
I use printf statements to display what has been read
To do the same thing using std::ifstream, I would simply make use of std::string and std::getline as follows:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream fin("message.txt", ios::in | ios::binary);
string data, line;
if (fin.is_open()) {
while (getline(fin, line)) {
data += line + "\n";
}
fin.close();
}
cout << "length = " << data.length() << "\n";
cout << "text = " << data << "\n";
return 0;
}
I am attempting to read numbers from a text file into a program, but for some reason, the program isn't reading the file. Here is my code:
#include <iostream>
#include <stream>
using namespace std;
int main()
{
ifstream infile;
infile.open ("adventDay1.txt");
if (!infile) { //Check if file is opening
cerr << "Error!"<< endl;
return 0;
}
int dataSize = 0;
infile >> dataSize;
int* arr;
arr = new int[dataSize]; //dynamically allocated array
int measureCount = 0; //Keep track of input from file
for (int i = 0; i < dataSize; i++) {
// infile >> dataSize;
arr[i] = dataSize;
measureCount += 1;
}
cout << measureCount << endl;
delete[] arr; //Delete dynamically allocated memory
return 0;
}
Each time I run it, it just displays the "Error!" message I added. There are 2,000 numbers in the text file, so that should be the expected output based on what I have here. I can't pinpoint the mistake.
Include fstream and ensure that you are opening the file in read mode. Perhaps also define it as ifstream infile("adventDay1.txt")
just want to ask if anyone knows why I cant convert an entire picture into decimal.
Problem: after about 180 couts it turns 0 for the rest of the pixels.
Code:
#include <fstream>
#include <iostream>
int main() {
char unsigned charTemp = 0;
int unsigned intTemp = 0;
std::fstream file;
file.open("PIC.pbm", std::ios::in);
//Ignore header
for (int i = 0; i < 13; i++) {
file.ignore();
}
//read and print
//img res is 40x40 = 1600
for (int i = 0; i < 1600; i++) {
file >> charTemp;
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
std::cout << "\n\n\n";
system("pause");
return 0;
}
Pic: any 40x40 pbm
A better method with picture and image files is to read them as binary files:
std::ifstream file("PIC.pbm", ios::binary);
std::vector<unsigned char> bitmap(1600);
// Skip over the header
file.seekg(13, ios::beg); // Skip over 13 bytes.
// Read in the data at once
file.read((char *) &bitmap[0], 1600);
// Now process the bitmap from memory
for (int i = 0; i < 1600; ++i)
{
cout << static_cast<unsigned int>(bitmap[i]) << " ";
if ((i % 40) == 39)
{
cout << "\n";
}
}
cout << "\n";
The idea here is to read in the bitmap in one transaction into memory. Streams like to flow (don't interrupt the flow). Memory is faster to access than files, so the bitmap values are processed from memory.
The cast is used so that the formatted insertion doesn't treat the byte as a character, but a number.
First, open your PIC.pbm file in another hex editor because it's quite possible that those bytes really are zeroes. If not, then you've got problems reading the file.
The fstream constructor does not default to reading in binary mode, so it reads files as "text" - and I've learned the hard way that you can't trust the standard-library with knowing anything about text anymore (what with mishandling Unicode, line-endings, etc - I feel it's best to always use binary and a dedicated Unicode library).
You should check the fstream::good() function after each read operation to see if it failed, and if so, then check iostate:
using namespace std;
// ...
fstream file;
file.open( "PIC.pbm", ios::in | ios::binary );
file.ignore( 13 );
for (int i = 0; i < 1600; i++) {
file >> charTemp;
if( !file.good() ) {
cout << endl;
cout << "Error reading file: iostate == " << file.iostate << endl;
break;
}
else {
intTemp = charTemp;
std::cout << intTemp << " ";
charTemp = 0;
intTemp = 0;
}
}
I cannot find the problem in my code. readFile function works well, but writeFile function does not make any changes in the file:
#include <iostream>
#include <fstream>
using namespace std;
const int BUF_SIZE = 1024;
void readFile(fstream &file, char buffer[BUF_SIZE]);
void writeFile(fstream &file);
void readFile(fstream &file, char buffer[BUF_SIZE])
{
int position;
cout << "Please enter a position to read from the file some info" << endl;
cin >> position;
file.seekg(position, ios::beg);
file.read((char*) buffer, BUF_SIZE); // <<<<<
for(int i = 0; i < file.gcount(); i++){
cout << buffer[i];
}
}
void writeFile(fstream &file)
{
char temp[100] = "HHHH";
//cout << "Please enter some info to add to the file" << endl;
file.write((char*) &temp, 100);
for(int i = 0; i < file.gcount(); i++){
cout << temp[i];
}
}
int main(int argc, char const *argv[])
{
char buffer[BUF_SIZE];
if (argc != 2){
cout << "Program usage: prog_name file_name";
return 1;
}
fstream file(argv[1], ios::in | ios::out | ios::binary | ios::app);
if (!file){
cout << "File can not open or doesn't exist";
return 1;
}
//Try to read & write some info from/to file in particular position
readFile(file, buffer);
writeFile(file);
file.close();
return 0;
}
When I create a new ostream it works well, but I want to understand why fstream in/out mode works in my code only for reading.
I see several problems:
The reason behind the writing problem is probably because you reach the end of the file (is the file smaller than BUF_SIZE bytes?). This sets the EOF bit, which makes any write operations to fail. You have to clear that bit before (use the std::fstream::clear method):
void readFile(fstream &file, char buffer[BUF_SIZE])
{
int position;
cout << "Please enter a position to read from the file some info" << endl;
cin >> position;
file.seekg(position, ios::beg);
file.read(buffer, BUF_SIZE);
for(int i = 0; i < file.gcount(); i++){
cout << buffer[i];
}
file.clear(); // clears EOF
}
The line file.write((char*) &temp, 100); is wrong since you are actually passing a point to the temp variable, which is also a pointer, but it is camouflaged by the cast. These ones are OK: file.write(temp, 100); or file.write(&temp[0], 100);
When printing the written characters, you are using std::fstream::gcount, which literally means get count (amount of characters read in the last get operation). You are writing (put) not reading (get). Indeed, you are actually indicating how many bytes you are willing to write, so use it:
file.write(temp, 100);
for(int i = 0; i < 100; i++){
cout << temp[i];
}
Finally, you are always writing 100 characters, probably including some garbage from the buffer. As I see that you want to let the user choose what to write (the commented line), you can instead:
const size_t size = strlen(temp);
file.write(temp, size);
for(size_t i = 0; i < size; i++){
cout << temp[i];
}
In addition, some suggestions:
Use a std::string to read the user input, in this way you avoid a possible buffer overflow (if the user enters more than 100 characters).
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // read the link bel
string temp;
getline(cin, temp); // need #include <string>
file.write(temp.c_str(), temp.size());
You will probably want to read this answer to learn more about the first line (basically it avoids the getline to be skipped after using cin >> position).
Avoid the for loop to print the user input. For both the buffer and the std::string options you can just cout << temp << endl;.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
int k = 0;
int n;
int y[0];
cout << "write n\n";
cin >> n;
ifstream infile;
infile.open("xxx.in.txt");
infile >> y[0];
infile.close();
for(int x = 0; x < n; x++)
for(int j = 1; j < n; j++)
if(y[x] > y[j])
k = k++;
ofstream outfile;
outfile.open("xxx.out.txt");
outfile << k;
outfile.close();
}
filexxx.in contains two lines (it is a text file).
The first line has n amount of numbers, the second line has random numbers spaced apart.
I want to read from the second line.
How do I do this?
There are a few ways to get input from the second line of your text file.
If you know how long the first line is you could use istream::seekg.
ifstream infile;
infile.open("xxx.in.txt");
infile.seekg(length_of_first_line); // This would move the cursor to the second line.
// Code to read line 2.
If you do not know the value or it could change. Then you would need to use istream::getline and discard the first line.
char buffer[256];
ifstream infile;
infile.open("xxx.in.txt");
infile.getline(buffer, 256); // Read in the first line.
// Code to read line 2.
Input from text file:
With the use of <vector>, <fstream> and <sstream> you can use something along the lines of the following function:
using namespace std;
vector<vector<int> > getNumbers(string FileName) {
vector<vector<int> > Numbers; //Stores all the file's numbers
ifstream infile(FileName.c_str());
string String;
int a;
while (getline(infile, String)) {
vector<int> Line; //Stores each line's numbers
stringstream Stream(String);
while (Stream >> a) //Extracts numbers from 'Stream'
Line.push_back(a); //Each number is added to Line
Numbers.push_back(Line); //Each Line is added to Numbers
}
return Numbers;
}
It returns a two-dimensional vector of ints, where in getFileNumber[x][y] the x value is the line number (starting at value 0 for line 1), and the y value is the position of the number on the line (0 for the first number).
For example, in a file containing:
464 654334 35665 3456332 4454
2456 788654 3456 5775
The number 3456 would be getFileNumbers[1][2]
Output to another text file:
To copy the entire contents of the getFileNumbers vector to a text file, you'd do this:
std::vector<std::vector<int> > Numbers = getFileNumbers("xxx.in.txt");
std::ofstream Output("xxx.out.txt");
for (unsigned int y = 0; y < Numbers.size(); ++y) {
for (unsigned int x = 0; x < Numbers[y].size(); ++x)
Output << Numbers[y][x] << ' ';
Output << '\n';
}
Line specific output:
If you wanted to output line x of a file with std::cout, you'd do this:
std::vector<std::vector<int> > Numbers = getFileNumbers("xxx.in.txt");
for (unsigned int i = 0; i < Numbers[x].size(); ++i)
std::cout << Numbers[x][i] << ' ';
If you wanted to output line x to a file, you'd simply replace std::cout with a std::ofstream or std::fstream object.