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

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.

Related

How do I store a txt file into a char array?

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

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

simple c++ binary file reading

I have a binary file created by some fortran code. I want to write a c++ code to read this binary file and then spit it out through std::cout. Here is so far my code:
#include<fstream>
#include<iostream>
using namespace std;
int main(){
ifstream file("tofu.txt", ios::binary | ios::in | ios::ate);
ifstream::pos_type size;
if(file.is_open()){
size = file.tellg();
cout << "size = " << size << '\n';
file.seekg(0);
char bar[500];
file.read((char*) (&bar), size);
file.close();
string foo(bar);
cout << "foo = " << foo << '\n';
}
else cout << "Unable to open file";
return 0;
}
However, when compiled and run, the code gives me nothing:
size = 250
foo =
Could someone tell me where I'm doing wrong in the code? Thanks!
You forgot to terminate your char array, leading to undefined behaviour. Fix it like this:
char bar[500];
assert(size < 500);
file.read((char*) (&bar), size - 1);
bar[size] = '\0';
(Make sure you check that size isn't larger than you have space for, too!)

Split a Large File In C++

I'm trying to write a program that takes a large file (of any type) and splits it into many smaller "chunks". I think I have the basic idea down, but for some reason I cannot create a chunk size over 12 kb. I know there are a few solutions on google, etc. but I am more interested in learning what the origin of this limitation is then actually using the program to split files.
//This file splits are larger into smaller files of a user inputted size.
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include <direct.h>
#include <stdlib.h>
using namespace std;
void GetCurrentPath(char* buffer)
{
_getcwd(buffer, _MAX_PATH);
}
int main()
{
// use the function to get the path
char CurrentPath[_MAX_PATH];
GetCurrentPath(CurrentPath);//Get the current directory (used for displaying output)
fstream bigFile;
string filename;
int partsize;
cout << "Enter a file name: ";
cin >> filename; //Recieve target file
cout << "Enter the number of bites in each smaller file: ";
cin >> partsize; //Recieve volume size
bigFile.open(filename.c_str(),ios::in | ios::binary);
bigFile.seekg(0, ios::end); // position get-ptr 0 bytes from end
int size = bigFile.tellg(); // get-ptr position is now same as file size
bigFile.seekg(0, ios::beg); // position get-ptr 0 bytes from beginning
for (int i = 0; i <= (size / partsize); i++)
{
//Build File Name
string partname = filename; //The original filename
string charnum; //archive number
stringstream out; //stringstream object out, used to build the archive name
out << "." << i;
charnum = out.str();
partname.append(charnum); //put the part name together
//Write new file part
fstream filePart;
filePart.open(partname.c_str(),ios::out | ios::binary); //Open new file with the name built above
//Check if near the end of file
if (bigFile.tellg() < (size - (size%partsize)))
{
filePart.write(reinterpret_cast<char *>(&bigFile),partsize); //Write the selected amount to the file
filePart.close(); //close file
bigFile.seekg(partsize, ios::cur); //move pointer to next position to be written
}
//Changes the size of the last volume because it is the end of the file
else
{
filePart.write(reinterpret_cast<char *>(&bigFile),(size%partsize)); //Write the selected amount to the file
filePart.close(); //close file
}
cout << "File " << CurrentPath << partname << " produced" << endl; //display the progress of the split
}
bigFile.close();
cout << "Split Complete." << endl;
return 0;
}
Any ideas?
You are writing to the split file, but not reading from the bigfile. What you are writing it the in-memory structure of the bigfile, not the contents of bigfile. You need to allocate a buffer, read into it from bigfile and write it to the splitfile(s).