I want to make copies of the exe file itself multiple times.
I tried the following code:
#include <fstream>
#include <string>
int main() {
std::ifstream from("main.exe", std::ios::binary);
auto buf { from.rdbuf() };
for(int x { 0 }; x <= 10; ++x) {
std::string name { "main" + std::to_string(x) + ".exe" };
std::ofstream out(name, std::ios::binary);
out << buf;
out.close();
}
from.close();
return 0;
}
But it doesn't work as I expected (It does not copy the executable repeatedly. See the size column in the following screenshot):
How do I solve this problem?
Reading from the input file stream buffer consumes the data. You need to reset the stream to the start after copying the file:
...
for (int x{ 0 }; x <= 10; ++x) {
std::string name{ "main" + std::to_string(x) + ".exe" };
std::ofstream out(name, std::ios::binary);
out << buf;
out.close();
from.seekg(0, std::ios::beg); // need to go back to the start here
}
...
You could simply use the std::filesystem standard library functionality for this though:
int main() {
std::filesystem::path input("main.exe");
for (int x{ 0 }; x <= 10; ++x) {
std::filesystem::path outfile("main" + std::to_string(x) + ".exe");
std::filesystem::copy_file(input, outfile, std::filesystem::copy_options::overwrite_existing);
}
return 0;
}
After you read all of the contents from the input buffer during your first iteration, your input buffer is empty. Thus, your subsequent iterations will also render empty copies. I suggest moving the from buffer initialization inside the loop like so:
#include <fstream>
#include <string>
int main() {
for (int x{ 0 }; x <= 10; ++x) {
std::ifstream from("main.exe", std::ios::binary);
auto buf{ from.rdbuf() };
std::string name{ "main" + std::to_string(x) + ".exe" };
std::ofstream out(name, std::ios::binary);
out << buf;
out.close();
from.close();
}
return 0;
}
Here's what you should get:
In the other answers the data will be read from the file multiple times (once per save).
This will happen if you create a new std::ifstream object inside the loop, and also happen if you use seekg to go to the beginning of the stream.
Since disk access is relatively slow (when compared to memory access), it will more efficient to read it once into memory, then save as many times as needed from memory.
The code below reads the file binary content into a std::vector. Then write the content of the vector multiple times to create the new files:
#include <string>
#include <vector>
#include <fstream>
int main() {
// Read the entire main.exe file into memory:
const std::string inFilename{ "main.exe" };
std::ifstream inFile{ inFilename, std::ios_base::binary };
std::vector<char> inFileData{ std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>() };
inFile.close();
// Save it as many times as needed:
for (int x{ 0 }; x <= 10; ++x)
{
std::string name{ "main" + std::to_string(x) + ".exe" };
std::ofstream outFile{ name, std::ios::binary };
outFile.write(inFileData.data(), inFileData.size());
outFile.close();
}
}
The first copy is done perfectly. My best guess is that the input buffer is empty afterwards, so all consecutive copies are empty.
Related
I want to read data in an input file partially. For example, input file is 1GB, I want to read only 100MB each time, then store in a vector. How can I continue reading the next line after the first loop? As you can see in my code below, after the first loop of i, maybe the vector v stored 1000 lines from the input file. I'm not sure if the next loop of i, the command while(std::getline(infile, line)) will continue to read from line 1001 from the input file or not? If not, how can I modify my code to get lines from the input in several groups (1~1000), (1001~2000), (2001~3000)... then store in vector v?
#define FILESIZE 1000000000 // size of the file on disk
#define TOTAL_MEM 100000 // max items the memory buffer can hold
void ExternalSort(std::string infilepath, std::string outfilepath)
{
std::vector<std::string> v;
int runs_count;
std::ifstream infile;
if(!infile.is_open())
{
std::cout << "Unable to open file\n";
}
infile.open(infilepath, std::ifstream::in);
if(FILESIZE % TOTAL_MEM > 0)
runs_count = FILESIZE/TOTAL_MEM + 1;
else
runs_count = FILESIZE/TOTAL_MEM;
// Iterate through the elements in the file
for(i = 0; i < runs_count; i++)
{
// Step 1: Read M-element chunk at a time from the file
for (j = 0; j < (TOTAL_MEM < FILESIZE ? TOTAL_MEM : FILESIZE); j++)
{
while(std::getline(infile, line))
{
// If line is empty, ignore it
if(line.empty())
continue;
new_line = line + "\n";
// Line contains string of length > 0 then save it in vector
if(new_line.size() > 0)
v.push_back(new_line);
}
}
// Step 2: Sort M elements
sort(v.begin(), v.end()); //sort(v.begin(), v.end(), compare);
// Step 3: Create temporary files and write sorted data into those files.
std::ofstream tf;
tf.open(tfile + ToString(i) + ".txt", std::ofstream::out | std::ofstream::app);
std::ostream_iterator<std::string> output_iterator(tf, "\n");
std::copy(v.begin(), v.end(), output_iterator);
v.clear();
//for(std::vector<std::string>::iterator it = v.begin(); it != v.end(); ++it)
// tf << *it << "\n";
tf.close();
}
infile.close();
I didn’t have the patience to check the whole code. It was easier to write a splitter from scratch. Here are some observations, anyhow:
std::ifstream infile;
if (!infile.is_open())
{
std::cout << "Unable to open file\n";
}
infile.open(infilepath, std::ifstream::in);
You will always get the message since you check before opening the file. One correct way to open a file is:
std::ifstream infile(infilepath);
if (!infile)
throw "could not open the input file";
if (infile.peek() == std::ifstream::traits_type::eof())
This will be true, for instance, even for nonexistent files. The algorithm should work for empty files, too.
if(FILESIZE % TOTAL_MEM > 0)
runs_count = FILESIZE/TOTAL_MEM + 1;
else
runs_count = FILESIZE/TOTAL_MEM;
Why do you need the number of resulting files before generate them? You will never be able to calculate it correctly since it depends on how long lines are (you cannot read half of line just to fit it into TOTAL_MEM). You should read from input file at most TOTAL_MEM bytes (but a line, at least), sort & save and then continue from where you left (see the loop in execute, below).
How can I continue reading the next line after the first loop?
If you do not close the input stream, the next read will continue from exactly where you left.
A solution:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <vector>
#include <iterator>
std::vector<std::string> split_file(const char* fn, std::size_t mem); // see the implementation below
int main()
{
const std::size_t max_mem = 8;
auto r = split_file("input.txt", max_mem);
std::cout << "generated files:" << std::endl;
for (const auto& fn : r)
std::cout << fn << std::endl;
}
class split_file_t
{
public:
split_file_t(std::istream& is, std::size_t mem) :is_{ is }, mem_{ mem }
{
// nop
}
std::vector<std::string> execute()
{
while (make_file())
;
return std::move(ofiles_);
}
protected:
std::istream& is_;
std::size_t mem_;
std::vector<std::string> ofiles_;
static std::string make_temp_file()
{
std::string fn(512, 0);
tmpnam_s(&fn.front(), fn.size()); // this might be system dependent
std::ofstream os(fn);
os.close();
return fn;
}
bool make_file()
{
using namespace std;
// read lines
vector<string> lines;
{
streamsize max_gpos = is_.tellg() + streamsize(mem_);
string line;
while (is_.tellg() < max_gpos && getline(is_, line))
lines.push_back(line);
}
//
if (lines.empty())
return false;
// sort lines
sort(lines.begin(), lines.end());
// save lines
{
string ofile = make_temp_file();
ofstream os{ ofile };
if (!os)
throw "could not open output file";
copy(lines.begin(), lines.end(), ostream_iterator<string>(os, "\n"));
ofiles_.push_back(ofile);
}
//
return bool(is_);
}
};
std::vector<std::string> split_file(const char* fn, std::size_t mem)
{
using namespace std;
ifstream is{ fn };
if (!is)
return vector<string>();
return split_file_t{ is, mem }.execute();
}
Please examine following code :
#include <iostream>
#include <string>
#include <fstream>
int main()
{
char mybuffer[512];
std::filebuf* optr = new std::filebuf();
optr->pubsetbuf(mybuffer, 512);
const char sentence[] = "Sample sentence";
auto ptr = optr->open("bd.bin", std::ios::binary | std::ios::trunc | std::ios::out);
if (ptr) {
float fx = 13;
auto n = optr->sputn(sentence, sizeof(sentence) - 1);
n += optr->sputn(reinterpret_cast<const char*>(&fx), sizeof(fx));
optr->pubsync();
}
optr->close();
if(optr) { delete optr; }
return 0;
}
After run this program no data has been written in to the file whilesputn -> n is returning valid amount of writtne characters(verified through debugging).
You code runs fine on my system, producing a bd.bin with 19 characters.
Are you sure this is exactly what you built and ran? Perhaps you're using a problematic compiler, or you're out of disk space or something.
Use the right tool for the job. filebuf is just the buffer that is streamed into. The actual thing that does the writing in the iostreams API is std::ostream:
std::filebuf file;
if (file.open(...)) {
std::ostream os(&file);
os << sentence;
os.write(reinterpret_cast<const char*>(&fx), sizeof(fx));
}
It's also easier to remember to use << and write() rather than deal with the maze of cryptically named functinos that is the streambuf API.
Hi I'm trying to read string from txt file and transform it into binary file which is bitset<12> string form.
int main()
{
using namespace std;
std::ifstream f("fruit.txt");
std::ofstream out("result.txt");
std::hash<std::string>hash_fn;
int words_in_file = 0;
std::string str;
while (f >> str){
++words_in_file;
std::bitset<12>* bin_str = new std::bitset<12>[3000];
int temp_hash[sizeof(f)];
std::size_t str_hash = hash_fn(str);
temp_hash[words_in_file] = (unsigned int)str_hash;
bin_str[words_in_file] = std::bitset<12>((unsigned int)temp_hash[words_in_file]);
out << bin_str[words_in_file] << endl;
delete[] bin_str;
}
out.close();
}
but there is error. How can I change it?
Here is some code that I wrote that turns the input file "file.txt" into binary. It does this by taking the ascii value of each character and representing that number as a binary value, although I'm not sure how to write bin_str to a file here.
#include <string>
#include <fstream>
#include <streambuf>
#include <bitset>
#include <iostream>
int main(){
std::ifstream f("file.txt");
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>()); // Load the file into the string
std::bitset<12> bin_str[str.size()]; // Create an array of std::bitset that is the size of the string
for (int i = 0; i < str.size(); i++) {
bin_str[i] = std::bitset<12>((int) str[i]); // load the array
std::cout << bin_str[i] << std::endl; // print for checking
}
}
SIDE NOTE:
std::bitset<12> may not be what you want, if you look at ascii characters the highest number you can have is 127 and in binary that's only 7 digits so I'd assume you'd want something more like std::bitset<7> or std::bitset<8>
EDIT:
If you want to write it to a file you'll need to open a file with std::ios::binary and then loop through the array of bitsets and write their unsigned long representative, given from to_ulong(), as a const char pointer ((const char*)&ulong_bin). Now when you open the file with a binary editor you will see the difference between the binary write and the regular write, but you'll notice that programs like cat can still decipher the binary you've written as simple ascii letters.
std::ofstream out("file.bin", std::ios::binary);
for (int i = 0; i < str.size(); i++) {
unsigned long ulong_bin = bin_str[i].to_ulong();
out.write((const char*)&ulong_bin, sizeof(ulong_bin));
}
EDIT: Credit to #PeterT
It has come to my attention that VLAs, variable length arrays, are not supported in C++11 and up so the line std::bitset<12> bin_str[str.size()]; should be changed to one of the following:
std::bitset<12> *bin_str = new std::bitset<12>[str.size()]; // make sure you delete it later
// OR
std::vector<std::bitset<12>> bin_str(str.size());
// OR
std::unique_ptr<std::bitset<12>[]> str_ptr (new std::bitset<12>[str.size()]);
I am reading numbers from a file, say:
1 2 3 4 5
I want to read this data from a file into a string into an array for further processing. Here's what I've done:
float *ar = nullptr;
while (getline(inFile, line))
{
ar = new float[line.length()];
for (unsigned int i = 0; i < line.length(); i++)
{
stringstream ss(line);
ss >> ar[i];
}
}
unsigned int arsize = sizeof(ar) / sizeof(ar[0]);
delete ar;
Suffice it to say that it works insofar it only gets the first value from the file. How do I get the array to be input ALL the values? I debugged the program and I can confirm that line has all the necessary values; but the float array doesn't. Please help, thanks!
line.length() is the number of characters in the line, not the number of words/numbers/whatevers.
Use a vector, which can be easily resized, rather than trying to juggle pointers.
std::vector<float> ar;
std::stringstream ss(line);
float value;
while (ss >> value) { // or (inFile >> value) if you don't care about lines
ar.push_back(value);
}
The size is now available as ar.size(); your use of sizeof wouldn't work since ar is a pointer, not an array.
The easiest option is to use the standard library and its streams.
$ cat test.data
1.2 2.4 3 4 5
Given the file you can use the stream library like this:
#include <fstream>
#include <vector>
#include <iostream>
int main(int argc, char *argv[]) {
std::ifstream file("./test.data", std::ios::in);
std::vector<float> res(std::istream_iterator<float>(file),
(std::istream_iterator<float>()));
// and print it to the standard out
std::copy(std::begin(res), std::end(res),
std::ostream_iterator<float>(std::cout, "\n"));
return 0;
}
I ran into this problem earlier when I wanted to extract data line by line from a file to fill my sql database that I wanted to use.
There are many solutions to this specific problem such as:
The solution is using stringstream with a while statement to put data from file into the array with a while statement
//EDIT
While statement with getline
//This solution isn't very complex and is pretty easy to use.
New Improved simple solution:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
ifstream line;
line.open("__FILENAME__");
string s;
vector<string> lines;
while(getline(line, s))
{
lines.push_back(s);
}
for(int i = 0;i < lines.size();i++)
{
cout << lines[i] << " ";
}
return 0;
}
compiled code to check - http://ideone.com/kBX45a
What about atof?
std::string value = "1.5";
auto converted = atof ( value.c_str() );
Rather complete:
while ( std::getline ( string ) )
{
std::vector < std::string > splitted;
boost::split ( splitted, line, boost::is_any_of ( " " ) );
std::vector < double > values;
for ( auto const& str: splitted ) {
auto value = atof ( str.c_str() );
values.push_back ( value );
}
}
I would like to know how to output an array of doubles to the hard drive.
edit:
for further clarification. I would like to output it to a file on the hard drive (I/O functions). Preferably in a file format that can be quickly translated back into an array of doubles in another program. It would also be nice if it was stored in a standard 4 byte configuration so that i can look at it through a hex viewer and see the actual values.
Hey... so you want to do it in a single write/read, well its not too hard, the following code should work fine, maybe need some extra error checking but the trial case was successful:
#include <string>
#include <fstream>
#include <iostream>
bool saveArray( const double* pdata, size_t length, const std::string& file_path )
{
std::ofstream os(file_path.c_str(), std::ios::binary | std::ios::out);
if ( !os.is_open() )
return false;
os.write(reinterpret_cast<const char*>(pdata), std::streamsize(length*sizeof(double)));
os.close();
return true;
}
bool loadArray( double* pdata, size_t length, const std::string& file_path)
{
std::ifstream is(file_path.c_str(), std::ios::binary | std::ios::in);
if ( !is.is_open() )
return false;
is.read(reinterpret_cast<char*>(pdata), std::streamsize(length*sizeof(double)));
is.close();
return true;
}
int main()
{
double* pDbl = new double[1000];
int i;
for (i=0 ; i<1000 ; i++)
pDbl[i] = double(rand());
saveArray(pDbl,1000,"test.txt");
double* pDblFromFile = new double[1000];
loadArray(pDblFromFile, 1000, "test.txt");
for (i=0 ; i<1000 ; i++)
{
if ( pDbl[i] != pDblFromFile[i] )
{
std::cout << "error, loaded data not the same!\n";
break;
}
}
if ( i==1000 )
std::cout << "success!\n";
delete [] pDbl;
delete [] pDblFromFile;
return 0;
}
Just make sure you allocate appropriate buffers! But thats a whole nother topic.
Use std::copy() with the stream iterators. This way if you change 'data' into another type the alterations to code would be trivial.
#include <algorithm>
#include <iterator>
#include <fstream>
int main()
{
double data[1000] = {/*Init Array */};
{
// Write data too a file.
std::ofstream outfile("data");
std::copy(data,
data+1000,
std::ostream_iterator<double>(outfile," ")
);
}
{
// Read data from a file
std::ifstream infile("data");
std::copy(std::istream_iterator<double>(infile),
std::istream_iterator<double>(),
data // Assuming data is large enough.
);
}
}
You can use iostream .read() and .write().
It works (very roughly!) like this:
double d[2048];
fill(d, d+2048, 0);
ofstream outfile ("save.bin", ios::binary);
outfile.write(reinterpret_cast<char*>(&d), sizeof(d));
ifstream infile ("save.bin", ios::binary);
infile.read(reinterpret_cast<char*>(&d), sizeof(d));
Note that this is not portable between CPU architectures. Some may have different sizes of double. Some may store the bytes in a different order. It shouldn't be used for data files that move between machines or data that is sent over the network.
#include <fstream.h>
void saveArray(double* array, int length);
int main()
{
double array[] = { 15.25, 15.2516, 84.168, 84356};
saveArray(array, 4);
return 0;
}
void saveArray(double* array, int length)
{
ofstream output("output.txt");
for(int i=0;i<length;i++)
{
output<<array[i]<<endl;
}
}
here is a way to output an array of doubles to text file one per line. hope this helps
EDIT
Change top one line to this two, and it will compile in VS. You can use multithreading to not blocking system wile saving data
#include <fstream>
using namespace std;
Now I feel old. I asked this question a long time ago (except about ints).
comp.lang.c++ link
#include <iostream>
#include <fstream>
using namespace std;
int main () {
double [] theArray=...;
int arrayLength=...;
ofstream myfile;
myfile.open ("example.txt");
for(int i=0; i<arrayLength; i++) {
myfile << theArray[i]<<"\n";
}
myfile.close();
return 0;
}
adapted from http://www.cplusplus.com/doc/tutorial/files/
Just set theArray and arrayLength to whatever your code requires.