How do I read the whole 64 bytes of a binary file? - c++

I am writing a little program that reads a disk image file in binary and then checks its partition entry tables to display each partition, it's type, start sector and size.
So far it reads the first 16 bytes accurately but the rest of the partition entries are not recognized or have some kind of error.
The result looks like this:
EDIT: The first line of the output is supposed to look like this:
`Partition 0: Type: FAT-16 Start: 63 Size: 518760`
What am I missing? How do I fix the code so that all the partition entries give the appropriate result?
using namespace std;
#include <iostream>
#include <fstream>
struct Partition { char type; int start_sect; int size; } part_entry[4]; // 4 x partition table entry
int main(int argc, char *argv[])
{
//DECLARATIONS
int i, offset = 26, not_exist = 0;
char buf_part_table[64], vol_type[12];
char* diskdata;
int n;
streampos begin, end;
ifstream diskimage;
diskimage.open("Sample_1.dd", ios::in | ios::binary | ios::out);
diskdata = new char[begin];
begin = diskimage.tellg();
diskdata = new char[begin];
diskimage.seekg(446, ios::beg);
diskimage.read(buf_part_table, 64);
for (i = 0; i < 4; i++)
{
part_entry[i].type = *(char*)(buf_part_table + 0x04 + (i * offset));
if (part_entry[i].type == 0) not_exist++;
part_entry[i].start_sect = *(int*)(buf_part_table + 0x08 + (i * offset));
part_entry[i].size = *(int*)(buf_part_table + 0x0C + (i * offset));
switch (part_entry[i].type)
{
case 00: strcpy(vol_type, "NOT-VALID");
break;
case 06: strcpy(vol_type, "FAT-16");
break;
case 07: strcpy(vol_type, "NTFS");
break;
case 0x0B: strcpy(vol_type, "FAT-32");
break;
default: strcpy(vol_type, "NOT-DECODED");
break;
}
cout << "Partition " << i << ":" << " Type:" << vol_type << " Start: " << part_entry[i].start_sect << " Size: " << part_entry[i].size << endl;
}
return 0;
}

You unnecesary made program unreadable and harder to debug.
You can read whole boot sector at once and than display desired content.
Here is my quick example (it does not check if file exists, some may complain it should use memcpy for some fields etc.)
#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstddef>
#include <iomanip>
using namespace std;
struct partition_t {
uint8_t status;
uint8_t start_CHS[3];
uint8_t type;
uint8_t end_CHS[3];
uint32_t start_LBA;
uint32_t size_LBA;
} __attribute__((packed));
struct mbr_t
{
uint8_t bootstrap[446];
partition_t partitions[4];
uint16_t signature;
} __attribute__((packed));
int main(int argc, char *argv[])
{
mbr_t mbr;
ifstream diskimage;
diskimage.open( "/tmp/mbr.dd", ios::in | ios::binary );
diskimage.read( reinterpret_cast<char*>(&mbr), sizeof(mbr) );
diskimage.close();
for( int idx = 0 ; idx < 4 ; idx++ )
{
string bootable = (mbr.partitions[idx].status == 128) ? "yes" : "no";
cout << " bootable : " << setw(5) << bootable <<
" type : " << setw(5) << (int)mbr.partitions[idx].type <<
" start LBA : " << setw(10) << mbr.partitions[idx].start_LBA <<
" size : " << setw(10) << mbr.partitions[idx].size_LBA << endl;
}
return 0;
}
It is easier to read, right?

Related

Finding int value in large binary file c++

I tried to make a program that loads chunks of a large (We're speaking of a few MBs) of file, and searches for a value, and prints its address and value, except my program every few times throws a !myfile , doesn't give the value except a weird symbol (Although I've used 'hex' in cout), the addresses seem to loop sorta, and it doesn't seem to find all the values at all. I've tried for a long time and I gave up, so I'm asking experiences coders out there to find the issue.
I should note that I'm trying to find a 32 bit value in this file, but all I could make was a program that checks bytes, i'd require assistance for that too.
#include <iostream>
#include <fstream>
#include <climits>
#include <sstream>
#include <windows.h>
#include <math.h>
using namespace std;
int get_file_size(std::string filename) // path to file
{
FILE *p_file = NULL;
p_file = fopen(filename.c_str(),"rb");
fseek(p_file,0,SEEK_END);
int size = ftell(p_file);
fclose(p_file);
return size;
}
int main( void )
{
ifstream myfile;
myfile.open( "file.bin", ios::binary | ios::in );
char addr_start = 0,
addr_end = 0,
temp2 = 0x40000;
bool found = false;
cout << "\nEnter address start (Little endian, hex): ";
cin >> hex >> addr_start;
cout << "\nEnter address end (Little endian, hex): ";
cin >> hex >> addr_end;
unsigned long int fsize = get_file_size("file.bin");
char buffer[100];
for(int counter = fsize; counter != 0; counter--)
{
myfile.read(buffer,100);
if(!myfile)
{
cout << "\nAn error has occurred. Bytes read: " << myfile.gcount();
myfile.clear();
}
for(int x = 0; x < 100 - 1 ; x++)
{
if(buffer[x] >= addr_start && buffer[x] <= addr_end)
cout << "Addr: " << (fsize - counter * x) << " Value: " << hex << buffer[x] << endl;
}
}
myfile.close();
system("PAUSE"); //Don't worry about its inefficiency
}
A simple program to search for a 32-bit integer in a binary file:
int main(void)
{
ifstream data_file("my_file.bin", ios::binary);
if (!data_file)
{
cerr << "Error opening my_file.bin.\n";
EXIT_FAILURE;
}
const uint32_t search_key = 0x12345678U;
uint32_t value;
while (data_file.read((char *) &value, sizeof(value))
{
if (value == search_key)
{
cout << "Found value.\n";
break;
}
}
return EXIT_SUCCESS;
}
You could augment the performance by reading into a buffer and searching the buffer.
//...
const unsigned int BUFFER_SIZE = 1024;
static uint32_t buffer[BUFFER_SIZE];
while (data_file.read((char *)&(buffer[0]), sizeof(buffer) / sizeof(uint32_t))
{
int bytes_read = data_file.gcount();
if (bytes_read > 0)
{
values_read = ((unsigned int) bytes_read) / sizeof(uint32_t);
for (unsigned int index = 0U; index < values_read; ++index)
{
if (buffer[index] == search_key)
{
cout << "Value found.\n";
break;
}
}
}
}
With the above code, when the read fails, the number of bytes should be checked, and if any bytes were read, the buffer then searched.

Frequency table in C++

This is what I have so far; I am trying to have an array with probability of all chars and space in a text file, but I have a problem with the data type.
int main()
{
float x[27];
unsigned sum = 0;
struct Count {
unsigned n;
void print(unsigned index, unsigned total) {
char c = (char)index;
if (isprint(c)) cout << "'" << c << "'";
else cout << "'\\" << index << "'";
cout << " occured " << n << "/" << total << " times";
cout << ", propability is " << (double)n / total << "\n";
}
Count() : n() {}
} count[256];
ifstream myfile("C:\\text.txt"); // one \ masks the other
while (!myfile.eof()) {
char c;
myfile.get(c);
if (!myfile) break;
sum++;
count[(unsigned char)c].n++;
}
for (unsigned i = 0; i<256; i++)
{
count[i].print(i, sum);
}
x[0] = count[33];
int j=68;
for(int i=1;i<27;i++)
{
x[i]=count[j];
j++;
}
return 0;
}
#include <iostream>
#include <fstream>
#include <cctype>
using namespace std;
double probabilities[256]; // now it can be accessed by Count
int main()
{
unsigned sum = 0;
struct Count {
unsigned n;
double prob;
void print ( unsigned index, unsigned total ) {
// if ( ! n ) return;
probabilities[index] = prob = (double)n/total;
char c = (char) index;
if ( isprint(c) ) cout << "'" << c << "'";
else cout << "'\\" << index << "'";
cout<<" seen "<<n<<"/"<<total<<" times, probability is "<<prob<<endl;
}
Count(): n(), prob() {}
operator double() const { return prob; }
operator float() const { return (float)prob; }
} count[256];
ifstream myfile("C:\\text.txt"); // one \ masks the other
while(!myfile.eof()) {
char c;
myfile.get(c);
if ( !myfile ) break;
sum++;
count[(unsigned char)c].n++;
}
for ( unsigned i=0; i<256; i++ ) count[i].print(i,sum);
return 0;
}
I incorporated various changes suggested - Thanks!
Now, who finds the 4 ways to access the actual probabilities?
you are allocating a buffer with size 1000000 1 million characters.
char file[1000000] = "C:\text.txt";
This is not good as the extra values in the buffer are not guaranteed to be zero, the can be anything.
For Windows to read a file you need something like this. I will not give you the solution, you need to learn using msdn and documentation to understand this fully::
you need to include the #include <windows.h> header from the SDK first.
Look at this example here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363778(v=vs.85).aspx
this example as appending a file to another. Your solution will be similar, instead of writing list to other file, process the buffer to increment your local variables and update the state of the table.
Do not set a large number you come up with for the buffer, as there will risk of not enough buffer space, and thus overflow. You should do like example:
read some bytes in buffer
process that buffer and increment the table
repeat until you reach end of file
while (ReadFile(hFile, buff, sizeof(buff), &dwBytesRead, NULL)
&& dwBytesRead > 0)
{
// write you logic here
}

string parsing for C++

I have a text file that has #'s in it...It looks something like this.
#Stuff
1
2
3
#MoreStuff
a
b
c
I am trying to use std::string::find() function to get the positions of the # and then go from there, but I'm not sure how to actually code this.
This is my attempt:
int pos1=0;
while(i<string.size()){
int next=string.find('#', pos1);
i++;}
Here's one i made a while ago... (in C)
int char_pos(char c, char *str) {
char *pch=strchr(str,c);
return (pch-str)+1;
}
Port it to C++ and there you go! ;)
If : Not Found Then returns Negative.
Else : Return 'Positive', Char's 1st found position (1st match)
It's hard to tell from your question what you mean by "position", but it looks like you are trying to do something like this:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream incoming{"string-parsing-for-c.txt"};
std::string const hash{"#"};
std::string line;
for (auto line_number = 0U; std::getline(incoming, line); ++line_number)
{
auto const column = line.find(hash);
if (std::string::npos != column)
{
std::cout << hash << " found on line " << line_number
<< " in column " << column << ".\n";
}
}
}
...or possibly this:
#include <fstream>
#include <iostream>
int main()
{
std::ifstream incoming{"string-parsing-for-c.txt"};
char const hash{'#'};
char byte{};
for (auto offset = 0U; incoming.read(&byte, 1); ++offset)
{
if (hash == byte)
{
std::cout << hash << " found at offset " << offset << ".\n";
}
}
}

lz4 compression c++ example [duplicate]

This question already has answers here:
Question about seekg() function of ifstream in C++?
(3 answers)
Closed 8 years ago.
In the process of writing a lz4 csv to compressed binary file converter (high volume forex tick data csv) in the hope of reducing the storage/disk bandwidth requirements on my tiny vps.
self contained code to illustrate
#include <string>
#include <fstream>
#include <iostream>
#include "lz4.h"
using namespace std;
int main()
{
char szString[] = "2013-01-07 00:00:04,0.98644,0.98676 2013-01-07 00:01:19,0.98654,0.98676 2013-01-07 00:01:38,0.98644,0.98696";
const char* pchSource = szString;
int nInputSize = sizeof(szString);
cout <<"- pchSource -" << endl << pchSource << endl;
cout <<"nbytes = "<< nInputSize << endl << endl;
ofstream source("pchSource.txt");
source << pchSource;
int nbytesPassed = 0;
int nMaxCompressedSize = LZ4_compressBound(nInputSize);
char *pszDest = new char[nMaxCompressedSize];
nbytesPassed = LZ4_compress(pchSource, pszDest, nInputSize);
cout <<"- pszDest Compressed-" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszDest << endl << endl;
// pszDest garbage ?
char *pszDestUnCompressed = new char[nInputSize];
LZ4_uncompress(pszDest, pszDestUnCompressed, nInputSize);
cout <<"- pszDestUnCompressed -" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszDestUnCompressed << endl << endl;
//pszDestUnCompressed is correct ?
delete[] pszDestUnCompressed;
pszDestUnCompressed = 0;
// ok lets write compressed pszDest to pszDest.dat
ofstream outCompressedFile("pszDest.dat",std::ofstream::binary);
outCompressedFile.write (pszDest,nMaxCompressedSize);
delete[] pszDest;
pszDest = 0;
//read it back in and try to uncompress it
ifstream infile("pszDest.dat",std::ifstream::binary);
infile.seekg (0,infile.end);
int nCompressedInputSize = infile.tellg();
infile.seekg (0);
char* buffer = new char[nCompressedInputSize];
infile.read (buffer,nCompressedInputSize);
const char* pchbuffer = buffer;
char* pszUnCompressedFile = new char[nInputSize];
nbytesPassed = LZ4_uncompress(pchbuffer, pszUnCompressedFile, nInputSize);
cout <<"- pszUnCompressedFile -" << endl;
cout <<"nbytesPassed = "<< nbytesPassed << endl;
cout << pszUnCompressedFile << endl;
//write uncompressed pszDest.dat to pszUnCompressedFile.txt
ofstream outUncompressedSource("pszUnCompressedFile.txt");
outUncompressedSource << pszUnCompressedFile;
// On my system 32bit ArchLinux 3.7.10-1 - gcc 4.7.2-4
// file contains random Garbage
delete[] buffer;
buffer = 0;
delete[] pszUnCompressedFile;
pszUnCompressedFile = 0;
return 0;
}
CONSOLE OUTPUT :
- pchSource -
2013-01-07 00:00:04,0.98644 .....
nbytes = 108
- pszDest Compressed-
nbytesPassed = 63
�2013-01-07 00:
- pszDestUnCompressed -
nbytesPassed = 63
2013-01-07 00:00:04,0.98644 .....
- pszUnCompressedFile -
nbytesPassed = -17
�W��W�-07 q
Process returned 0 (0x0) execution time : 0.010 s
Press ENTER to continue.
I'm obviously missing something, apart form the samples included in the source are there any-other usage examples ?
All working now thanks, here is the code for anyone that is interested
#include <fstream>
#include <iostream>
#include "lz4.h"
using namespace std;
int main()
{
char szSource[] = "2013-01-07 00:00:04,0.98644,0.98676 2013-01-07 00:01:19,0.98654,0.98676 2013-01-07 00:01:38,0.98644,0.98696";
int nInputSize = sizeof(szSource);
// compress szSource into pchCompressed
char* pchCompressed = new char[nInputSize];
int nCompressedSize = LZ4_compress((const char *)(&szSource), pchCompressed, nInputSize);
// write pachCompressed to binary lz4.dat
ofstream outBinaryFile("lz4.dat",ofstream::binary);
outBinaryFile.write(pchCompressed, nCompressedSize);
outBinaryFile.close();
delete[] pchCompressed;
pchCompressed = 0;
//read compressed binary file (assume we pass/encode nInputSize but don't know nCompressedSize)
ifstream infCompressedBinaryFile( "lz4.dat", ifstream::binary );
//Get compressed file size for buffer
infCompressedBinaryFile.seekg (0,infCompressedBinaryFile.end);
int nCompressedInputSize = infCompressedBinaryFile.tellg();
infCompressedBinaryFile.clear();
infCompressedBinaryFile.seekg(0,ios::beg);
//Read file into buffer
char* pchCompressedInput = new char[nCompressedInputSize];
infCompressedBinaryFile.read(pchCompressedInput,nCompressedSize);
infCompressedBinaryFile.close();
// Decompress buffer
char* pchDeCompressed = new char[nInputSize]; //(nCompressedInputSize *2) +8
LZ4_uncompress(pchCompressedInput, pchDeCompressed, nInputSize);
delete[] pchCompressedInput;
pchCompressedInput = 0;
// write decompressed pachUnCompressed to
ofstream outFile("lz4.txt");
outFile.write(pchDeCompressed, nInputSize);
outFile.close();
delete[] pchDeCompressed;
pchDeCompressed = 0;
return 0;
}
I am also working on a a simple CLI csv to binary I/O example here

How to display a progress indicator in pure C/C++ (cout/printf)?

I'm writing a console program in C++ to download a large file. I know the file size, and I start a work thread to download it. I want to show a progress indicator to make it look cooler.
How can I display different strings at different times, but at the same position, in cout or printf?
With a fixed width of your output, use something like the following:
float progress = 0.0;
while (progress < 1.0) {
int barWidth = 70;
std::cout << "[";
int pos = barWidth * progress;
for (int i = 0; i < barWidth; ++i) {
if (i < pos) std::cout << "=";
else if (i == pos) std::cout << ">";
else std::cout << " ";
}
std::cout << "] " << int(progress * 100.0) << " %\r";
std::cout.flush();
progress += 0.16; // for demonstration only
}
std::cout << std::endl;
http://ideone.com/Yg8NKj
[> ] 0 %
[===========> ] 15 %
[======================> ] 31 %
[=================================> ] 47 %
[============================================> ] 63 %
[========================================================> ] 80 %
[===================================================================> ] 96 %
Note that this output is shown one line below each other, but in a terminal emulator (I think also in Windows command line) it will be printed on the same line.
At the very end, don't forget to print a newline before printing more stuff.
If you want to remove the bar at the end, you have to overwrite it with spaces, to print something shorter like for example "Done.".
Also, the same can of course be done using printf in C; adapting the code above should be straight-forward.
You can use a "carriage return" (\r) without a line-feed (\n), and hope your console does the right thing.
For a C solution with an adjustable progress bar width, you can use the following:
#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
#define PBWIDTH 60
void printProgress(double percentage) {
int val = (int) (percentage * 100);
int lpad = (int) (percentage * PBWIDTH);
int rpad = PBWIDTH - lpad;
printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
fflush(stdout);
}
It will output something like this:
75% [|||||||||||||||||||||||||||||||||||||||||| ]
Take a look at boost progress_display
http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display
I think it may do what you need and I believe it is a header only library so nothing to link
You can print a carriage return character (\r) to move the output "cursor" back to the beginning of the current line.
For a more sophisticated approach, take a look at something like ncurses (an API for console text-based interfaces).
I know I am a bit late in answering this question, but I made a simple class that does exactly what you want. (keep in mind that I wrote using namespace std; before this.):
class pBar {
public:
void update(double newProgress) {
currentProgress += newProgress;
amountOfFiller = (int)((currentProgress / neededProgress)*(double)pBarLength);
}
void print() {
currUpdateVal %= pBarUpdater.length();
cout << "\r" //Bring cursor to start of line
<< firstPartOfpBar; //Print out first part of pBar
for (int a = 0; a < amountOfFiller; a++) { //Print out current progress
cout << pBarFiller;
}
cout << pBarUpdater[currUpdateVal];
for (int b = 0; b < pBarLength - amountOfFiller; b++) { //Print out spaces
cout << " ";
}
cout << lastPartOfpBar //Print out last part of progress bar
<< " (" << (int)(100*(currentProgress/neededProgress)) << "%)" //This just prints out the percent
<< flush;
currUpdateVal += 1;
}
std::string firstPartOfpBar = "[", //Change these at will (that is why I made them public)
lastPartOfpBar = "]",
pBarFiller = "|",
pBarUpdater = "/-\\|";
private:
int amountOfFiller,
pBarLength = 50, //I would recommend NOT changing this
currUpdateVal = 0; //Do not change
double currentProgress = 0, //Do not change
neededProgress = 100; //I would recommend NOT changing this
};
An example on how to use:
int main() {
//Setup:
pBar bar;
//Main loop:
for (int i = 0; i < 100; i++) { //This can be any loop, but I just made this as an example
//Update pBar:
bar.update(1); //How much new progress was added (only needed when new progress was added)
//Print pBar:
bar.print(); //This should be called more frequently than it is in this demo (you'll have to see what looks best for your program)
sleep(1);
}
cout << endl;
return 0;
}
Note: I made all of the classes' strings public so the bar's appearance can be easily changed.
Another way could be showing the "Dots" or any character you want .The below code will print progress indicator [sort of loading...]as dots every after 1 sec.
PS : I am using sleep here. Think twice if performance is concern.
#include<iostream>
using namespace std;
int main()
{
int count = 0;
cout << "Will load in 10 Sec " << endl << "Loading ";
for(count;count < 10; ++count){
cout << ". " ;
fflush(stdout);
sleep(1);
}
cout << endl << "Done" <<endl;
return 0;
}
Here is a simple one I made:
#include <iostream>
#include <thread>
#include <chrono>
#include <Windows.h>
using namespace std;
int main() {
// Changing text color (GetStdHandle(-11), colorcode)
SetConsoleTextAttribute(GetStdHandle(-11), 14);
int barl = 20;
cout << "[";
for (int i = 0; i < barl; i++) {
this_thread::sleep_for(chrono::milliseconds(100));
cout << ":";
}
cout << "]";
// Reset color
SetConsoleTextAttribute(GetStdHandle(-11), 7);
}
May be this code will helps you -
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <cmath>
using namespace std;
void show_progress_bar(int time, const std::string &message, char symbol)
{
std::string progress_bar;
const double progress_level = 1.42;
std::cout << message << "\n\n";
for (double percentage = 0; percentage <= 100; percentage += progress_level)
{
progress_bar.insert(0, 1, symbol);
std::cout << "\r [" << std::ceil(percentage) << '%' << "] " << progress_bar;
std::this_thread::sleep_for(std::chrono::milliseconds(time));
}
std::cout << "\n\n";
}
int main()
{
show_progress_bar(100, "progress" , '#');
}
Simple, you can just use string's fill constructor:
#include <iostream> //for `cout`
#include <string> //for the constructor
#include <iomanip> //for `setprecision`
using namespace std;
int main()
{
const int cTotalLength = 10;
float lProgress = 0.3;
cout <<
"\r[" << //'\r' aka carriage return should move printer's cursor back at the beginning of the current line
string(cTotalLength * lProgress, 'X') << //printing filled part
string(cTotalLength * (1 - lProgress), '-') << //printing empty part
"] " <<
setprecision(3) << 100 * lProgress << "%"; //printing percentage
return 0;
}
Which would print:
[XXX-------] 30%
If you need it in pure C
and you would like to be able to customize the size and filler characters at runtime:
#include <stdio.h> //for `printf`
#include <stdlib.h> //for `malloc`
#include <string.h> //for `memset`
int main()
{
const int cTotalLength = 10;
char* lBuffer = malloc((cTotalLength + 1) * sizeof *lBuffer); //array to fit 10 chars + '\0'
lBuffer[cTotalLength] = '\0'; //terminating it
float lProgress = 0.3;
int lFilledLength = lProgress * cTotalLength;
memset(lBuffer, 'X', lFilledLength); //filling filled part
memset(lBuffer + lFilledLength, '-', cTotalLength - lFilledLength); //filling empty part
printf("\r[%s] %.1f%%", lBuffer, lProgress * 100); //same princip as with the CPP method
//or you can combine it to a single line if you want to flex ;)
//printf("\r[%s] %.1f%%", (char*)memset(memset(lBuffer, 'X', lFullLength) + lFullLength, '-', cTotalLength - lFullLength) - lFullLength, lProgress * 100);
free(lBuffer);
return 0;
}
but if you don't need to customize it at runtime:
#include <stdio.h> //for `printf`
#include <stddef.h> //for `size_t`
int main()
{
const char cFilled[] = "XXXXXXXXXX";
const char cEmpty[] = "----------";
float lProgress = 0.3;
size_t lFilledStart = (sizeof cFilled - 1) * (1 - lProgress);
size_t lEmptyStart = (sizeof cFilled - 1) * lProgress;
printf("\r[%s%s] %.1f%%",
cFilled + lFilledStart, //Array of Xs starting at `cTotalLength * (1 - lProgress)` (`cTotalLength * lProgress` characters remaining to EOS)
cEmpty + lEmptyStart, //Array of -s starting at `cTotalLength * lProgress`...
lProgress * 100 //Percentage
);
return 0;
}
I needed to create a progress bar and some of the answers here would cause the bar to blink or display the percentage short of 100% when done. Here is a version that has no loop other than one that simulates cpu work, it only prints when the next progress unit is incremented.
#include <iostream>
#include <iomanip> // for setw, setprecision, setfill
#include <chrono>
#include <thread> // simulate work on cpu
int main()
{
int batch_size = 4000;
int num_bars = 50;
int batch_per_bar = batch_size / num_bars;
int progress = 0;
for (int i = 0; i < batch_size; i++) {
if (i % batch_per_bar == 0) {
std::cout << std::setprecision(3) <<
// fill bar with = up to current progress
'[' << std::setfill('=') << std::setw(progress) << '>'
// fill the rest of the bar with spaces
<< std::setfill(' ') << std::setw(num_bars - progress + 1)
// display bar percentage, \r brings it back to the beginning
<< ']' << std::setw(3) << ((i + 1) * 100 / batch_size) << '%'
<< "\r";
progress++;
}
// simulate work
std::this_thread::sleep_for(std::chrono::nanoseconds(1000000));
}
}