How do I store a txt file into a char array? - c++

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;
}

Related

File isn't being read? (C++)

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")

Problems with fstream reads ok but not write user input string

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;.

How properly to read data from binary file to char array

How can i properly write data from binary file to new char array.
I know that this question was asked several times here, but still i couldn't figure out how to do it properly.
This what i have so far..
struct Computer_Details {
char computer_type[99];
int release_year;
float price;
};
Computer_Details pc_details;
cout << "Enter Computer Type: ";
cin.getline(pc_details.computer_type, 255);
cout << "Enter Computer Release Date: ";
cin >> pc_details.release_year;
cout << "Enter Computer Price: ";
cin >> pc_details.price;
cout << "\n\n";
//Create File
ofstream file;
file.open("PC_Database.data", ios::binary | ios::app);
if (!file) cout << "Couldn't open file\n";
else {
file.write((char*)&pc_details, sizeof(Computer_Details));
file.close();
}
ifstream readFile;
readFile.open("PC_Database.data", ios::binary);
if (!readFile) cout << "Couldn't Open File\n";
else {
readFile.seekg(0, ios::end);
int fileSize = readFile.tellg();
int pcCount = fileSize / sizeof(Computer_Details);
readFile.seekg(0, ios::beg);
Computer_Details *pc_details = new Computer_Details[pcCount];
readFile.read((char*)pc_details, pcCount * sizeof(Computer_Details));
char *buff = new char[299];
for (int i = 0; i < pcCount; i++)
{
//write to buff char
}
readFile.close();
}
Try
std::ifstream input(szFileName, std::ios::binary);
data = std::vector<char>(std::istreambuf_iterator<char>(input),
(std::istreambuf_iterator<char>()));
char* charArray = &data[0];
size_t arraySize = data.size();
data vector's buffer is the needed char array. Its constructor's arguments are two iterators. The first one is the current reading position in ifstream (begin of stream in this case). The second one's constructor is default and it is treated as an end iterator.
Probably problem is size of your structure,
check sizes for structure and compare it to size of this structure:
struct Computer_Details {
char computer_type[100];
int release_year;
float price;
};
Same problem is when you trying to read/write structure which contains bool variable between two other types like int.
Try this :
readFile.read((char*)pc_details->computer_type, sizeof(Computer_Details::computer_type));
readFile.read((char*)pc_details->release_year, sizeof(Computer_Details::release_year));
readFile.read((char*)pc_details->price, sizeof(Computer_Details::price));
edit: look at examples in this comment: https://stackoverflow.com/a/119128/7981164
My guess is that you want to shove pc_details into the buff so you can send it somewhere and reconstruct the data.
If that is the case, you could do this:
for( int i=0; i < pcCount; i++ )
{
memcpy( buff, (char*)pc_details, sizeof(computer_details));
buff += sizeof(computer_details);
pc_details++;
}
However, when doing this you must be mindful of alignment and provide
padding accordingly. And your code should check your array bounds.

How to read a binary files and print 3's on screen?

I want to read a binary file of integer type and print the occurrence of the number of 3's in the file. I somehow wrote a program to open and read a binary file.
Here is the couple of problems I am facing:
If I try to print the file on my terminal, the execution continues
forever and the loop never ends.
I have no idea of how to filter out 3's from it.
Here is my code:
#include <iostream>
#include <fstream>
using namespace std;
int main () {
streampos size;
char * memblock;
ifstream file ("threesData.bin", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "the entire file content is in memory";
for (int i = 0; i < size; i += sizeof(int))
{
cout << *(int*)&memblock[i] << endl;
}
delete[] memblock;
}
else
cout << "Unable to open file";
return 0;
}
Here is a way to implement your requirements:
int main()
{
unsigned int quantity = 0U;
ifstream file ("threesData.bin", ios::in|ios::binary|ios::ate);
uint8_t byte;
while (file >> byte)
{
if (byte == 3U)
{
++ quantity;
}
}
cout << "The quantity of 3s is: " << quantity << endl;
return 0;
}
The first step should always get a simple version working first. Only optimize if necessary.
Allocating memory for a file and reading the entire file is an optimization. For example, your platform may not have enough available memory to read the entire file into memory before processing.

Reading in a text file from a command line and storing the content of the file into a c-string

I am learning C++ in one of my classes and I am having difficulties storing the content of a .txt file into a c string.
I have figured out how to validate that the .txt file exists but when I try storing the characters into a c-string it crashes.
This is my most recent attempt:
char * fileContent[MAX_SIZE];
ifstream ifile(argv[1]);
while (int i = 0 < MAX_SIZE)
{
ifile >> fileContent[i];
cout << fileContent[i];
if (ifile.eof())
break;
i++;
}
ifile.close();
Every-time the console gets to the loop it crashes. Are there any suggestions to help make this work?
I need it to be a c-string so that I can run the c-string through other functions. I am still pretty new to C++.
The assignment states: "Reads a text file into memory, one byte at a time"
I hope what I am trying to do is this.
Thank you
You can use the following code to read from a text file and save the string as a C-string. The output file (output.txt) contains the c-string output.
#include <string>
#include <iostream>
#include <fstream>
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
char *out_c_string;
char ch;
int index=0;
while(cin >> ch)
out_c_string[index++] = ch;
for(int i=0; i<index; i++)
cout << out_c_string[i]; // the c string of the file :)
return 0;
}
There were few bugs in your code, try this:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int MAX_SIZE = 128;
int main(int argc, char* argv[])
{
char fileContent[MAX_SIZE]; //bad idea never do that!
// use an std::vector<char> instead!
// and reverse a minimum amount of chars
// using `reserve` if you are after performance
ifstream ifile(argv[1]);
int i = 0;
while (i < MAX_SIZE)
{
ifile >> fileContent[i];
cout << fileContent[i];
if (ifile.eof())
break;
i++;
}
ifile.close();
}
Combining everyones answers, I got this as my function:
void get_file_info(char * argv, char (&fileContent) [MAX_SIZE], int & filesize ){
freopen(argv, "r", stdin);
char ch;
int index = 0;
while (cin >> noskipws >> ch)
fileContent[index++] = ch;
cout << endl << index << endl;
#if SHOW_DEBUG_CODE
for (int count = 0; count < index; count++)
cout << fileContent[count];
#endif
fclose(stdin);
}
It seems to work just fine. I will look into vectors my next free time but for right now, I am going to continue with char array.
Thank you for your suggestions.
I would do this. It's more general to cope with any size file.
void ReadFile(char*file,char**buff,int*size){
// Open file as binary putting file position at the end
ifstream is(file,ios::binary|ios::ate);
// Get the current file position, which is the file end
*size=is.tellg();
// Put file pointer back at the start
is.seekg(0,ios::beg);
// errors
if (!*size){
cout<<"Unable to open input file or file empty\n";
exit(9);
}
// allocate a buffer one bigger to allow for zero terminator
*buff=new char[*size+1];
// read the whole file in one hit
is.read(*buff,*size);
// Done. So close and zero delimit data.
is.close();
*(*buff+*size)=0;
}