I've been doing my project and the last thing I need to do is to save to and start reading a structure array from a file on startup of the program, but I can't figure out why the code isn't loading the information of the file. Earlier I asked a similar question and got referred to serialization, which didn't work and I decided to turn my strings into chars and change the functions to work with chars, since I thought that I might be serializing wrong, considering the fact that I first learned how to do it today, unfortunately the program still doesn't read, even though it writes in the file. My style is pretty bad, so I apologize in advance. Here's the code sample only of the struct fread and fwrite with the main:
#include <iostream>
#include <string>
#include<fstream>
using namespace std;
struct property {
int num;
char nBrok[50];
char type[10];
char adress [70];
char outlook[20];
double price;
double size;
int nRooms;
int floor;
int status;
};
fstream fp;
void fileWrite(property bDanni[], int n) {
fp.open("dbase.dat", ios::binary | ios::out);
if (!fp) {
cout << "\n Error in file \n"; exit(1);
}
fp.write((char*)bDanni, sizeof(property) *n);
fp.close();
}
int fileRead(property bDanni[]) {
long pos; int n = 0, i; property b;
fp.open("dbase.dat", ios::binary | ios::in);
if (!fp) {
cout << "\n file does not exist\n"; return n;
}
fp.seekg(0l, ios::end);
pos = fp.tellg();
fp.close();
n = pos / (sizeof(property));
fp.open("dbase.dat", ios::binary | ios::in);
if (!fp) {
cout << "\n Error in file \n"; exit(1);
}
for (i = 0; i < n; i++) {
fp.read((char*)&b, sizeof(property));
bDanni[i] = b;
}
fp.close();
return n;
}
int main() {
property bDanni[100];
char answer;
int total = 0;
cout << "Do you wat to read from the save file?(y/n): ";
cin >> answer;
if (answer == 'y') {
int total = fileRead(bDanni);
}
}
The code posted works, the issue was the way the main loaded the function.
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've been doing my project and the last thing I need to do is to save to and start reading a structure array from a file on startup of the program, but I can't figure out why the code isn't loading the information of the file. I know that it does save something since I can open the .dat file and read it in a text editor.
I apologize for the terrible style, but I'm still new. That's a sample of just that function in the code:
#include <iostream>
#include <string>
#include<fstream>
using namespace std;
struct property {
int num;
char nBrok[50];
char type[10];
string adress;
char outlook[20];
double price;
double size;
int nRooms;
int floor;
int status;
};
fstream fp;
void fileWrite(property bDanni[], int n) {
fp.open("dbase.dat", ios::binary | ios::out);
if (!fp) {
cout << "\n Error in file \n"; exit(1);
}
fp.write((char*)bDanni, sizeof(property) *n);
fp.close();
}
int fileRead(property bDanni[]) {
long pos; int n = 0, i; property b;
fp.open("dbase.dat", ios::binary | ios::in);
if (!fp) {
cout << "\n file does not exist\n"; return n;
}
fp.seekg(0l, ios::end);
pos = fp.tellg();
fp.close();
n = pos / (sizeof(property));
fp.open("dbase.dat", ios::binary | ios::in);
if (!fp) {
cout << "\n Error in file \n"; exit(1);
}
for (i = 0; i < n; i++) {
fp.read((char*)&b, sizeof(property));
bDanni[i] = b;
}
fp.close();
return n;
}
int main() {
property bDanni[100];
char answer;
int total = 0;
cout << "Do you wat to read from the save file?(y/n): ";
cin >> answer;
if (answer == 'y') {
int total = fileRead(bDanni);
}
}
The problem is that a C++ std::string is much more complex than a char array. The implementation is not mandated by the standard, but in common implementation, the string element contains a pointer to a character array. That means that your code only stores into the file a pointer value instead of a character string.
In C++ idiom, the std::string type is said not to be trivially copyable. And the fread-fwrite method can only be used with trivially copyable types.
That means that you will have to use serialization to replace the raw byte representation of a std::string with a sequence of bytes that represent the useful content of the object, something that you will be able to use at read time to construct back the object. Not really complex but beyond a mere fwrite.
#include<iostream>
#include<fstream>
using namespace std;
void read_file(fstream &file);
int main()
{
fstream inFile;
inFile.open("Data.txt");
if (inFile.fail())
{
cerr << "Error with opening file";
exit(1);
}
else
{
read_file(inFile);
}
inFile.close();
return 0;
}
void read_file(fstream &file)
{
int arr[100];
fstream inFile;
int number;
int number_trash;
int number_hold;
while (!inFile.eof())
{
for (int i = 0; i < 101; i++)
{
inFile >> number;
number_hold = number;
if (number != number_hold)
{
arr[i] = number;
cout << arr[i] << endl;
}
else
{
number_trash = number;
}
}
}
}
In your read_file() function, you're passing an fstream instance of an already open file, which is correct, however, later in the same function, you declare a new instance of fstream called inFile which is not open and you're trying to read from this file stream.
Remove the fstream inFile and read from the file which your function takes as an argument.
Also, your algorithm is not correct - the first if statement condition will be always evaluated to false. You're assigning number to number_hold and then you're checking for their non-equality.
As a solution, consider something like this:
void read_file(fstream &file)
{
set<int> arr; // storage for your unique numbers
while (!file.eof())
{
int number;
file >> number; // read the number
// check if this number is already in your unique list
if (arr.find(number) == arr.end()) { // If it isn't, print it out...
cout << number << endl;
arr.insert(number); // ...and put it to your unique list
}
}
}
Note that for this to work you have to include another header file called set
#include <set>
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;.
I am trying to read a text file into an array of integers but my read doesn't affect anything and my array stays at its default value of 0, my code is as follows
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream myfile;
int a[1000] = {0};
myfile.open ("Euler7.txt", ios::out | ios::app | ios::binary);
for (int i=0;i<1000;i++)
{
myfile << a[i];
cout << a[i] << endl;
}
myfile.close();
int c = 0;
for (int b=0;b>995;b++)
{
if (a[b]*a[b+1]*a[b+2]*a[b+3]*a[b+4] > c)
c = a[b]*a[b+1]*a[b+2]*a[b+3]*a[b+4];
}
cout << c << a[0];
return 0;
}
i suspect i need an fin.ignore somewhere in there somewhere, but my skills with files go about as far as #include , the file i am trying to open goe something like
6717653133062491922511967442657474235534919493496983520312774506326239578318
No spaces or separation between numbers. i need each item of the array to hold an individual digit, there are 1000 numbers in the file.
Your file stream object is an ofstream, which is for writing out to a file. Instead, you want ifstream, which is for input. You'll also want to get rid of the ios::out and ios::app flags in the call to open. In addition, you're using operator << which is for output, rather than >> for input.
Seems like the fstream technique wasn't needed at all to solve this problem. Special thanks to Tacet for parts of this code:
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int pause;
string series="7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";
unsigned int max = 0; //if it can not be less than zero, use a unsigned type
const unsigned int end = series.size()-4;
for (int i=0;i<end;i++)
if ((series[i]-'0')*(series[i+1]-'0')*(series[i+2]-'0')*(series[i+3]-'0')*(series[i+4]-'0') > max)
max = (series[i]-'0')*(series[i+1]-'0')*(series[i+2]-'0')*(series[i+3]-'0')*(series[i+4]-'0');
cout << max << '\n';
cin >> pause;
return 0;
}