this code seems to work under Windows (with unexpected results) and Ubuntu. But when I run it under FreeBSD 9.0 AMD 64 it causes the system to freeze. I get error messages like this:
ahcich0: Timeout on slot 28 port 0
Does anybody know what the problem could be?
Thanks.
#include <cmath>
#include <cstdlib>
#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
const string FILENAME = "testfile";
const string COPYNAME = "copy";
const int FILES = 5;
const int SIZE_MULTIPLIER = 6;
const int BUFFER_SIZE = pow(2.0, 16);
time_t times[2][FILES];
srand (time(NULL));
// create test files
for (int i = 1; i < FILES + 1; i++){
ofstream os;
string filename(FILENAME);
filename += (char)i + 48;
os.open(filename.c_str(), ios::binary);
if (os.is_open()){
cout << "Writing file " << i << " of " << FILES;
long filesize =pow(2.0, i * SIZE_MULTIPLIER);
cout << " (" << filesize << " bytes)" << endl;
while(filesize--){
os << (char)(rand() % 256);
}
cout << os.tellp() << " bytes written.\n";
os.close();
}else{
cerr << "Could not create file " << filename;
cerr << endl;
}
}
// copy the files
timeval tv;
time_t start;
char buffer[BUFFER_SIZE];
char ci;
for (int i = 0; i < FILES; i++){
ci = (char)i + 49;
string filename(FILENAME);
filename += ci;
string copyname("c");
copyname += COPYNAME;
copyname += ci;
cout << "Copying file " << filename.c_str() << endl;
cout << "the c way: ";
cout.flush();
start = time(NULL);
FILE *pFile = fopen(filename.c_str(), "rb");
FILE *pCopy = fopen(copyname.c_str(), "wb");
if (!(pFile == NULL || pCopy == NULL)){
do{
int bytesRead = fread(
buffer, 1, BUFFER_SIZE, pFile);
fwrite(buffer, 1, bytesRead, pCopy);
}while(!feof(pFile));
fclose(pFile);
fclose(pCopy);
cout << " Done.\n";
}else{
cerr << "Could not open either " << filename;
cerr << " or " << copyname << endl;
}
times[0][i] = time(NULL) - start;
remove(copyname.c_str());
copyname = "cpp";
copyname += COPYNAME;
copyname += ci;
cout << "the c++ way: ";
cout.flush();
start = time(NULL);
ifstream in;
in.open(filename.c_str(), ios::binary);
in.rdbuf()->pubsetbuf(buffer, BUFFER_SIZE);
ofstream out;
out.open(copyname.c_str(), ios::binary);
char copyBuffer[BUFFER_SIZE];
out.rdbuf()->pubsetbuf(copyBuffer, BUFFER_SIZE);
if (in.is_open() && out.is_open()){
out << in.rdbuf();
in.close();
out.close();
cout << " Done.\n";
}else{
cerr << "Could not open either " << filename;
cerr << " or " << copyname << endl;
}
times[1][i] = time(NULL) - start ;
remove(copyname.c_str());
}
cout << "Summary:\n";
cout << "\tc\tc++\n";
for (int i = 0; i < FILES; i++){
ci = (char)i + 49;
cout << "copy" << ci << "\t" << times[0][i];
cout << "\t" << times[1][i] << endl;
}
return 0;
}
After changing FILES to 4 (because it takes very long otherwise), your program ran just fine here:
Writing file 1 of 4 (64 bytes)
64 bytes written.
Writing file 2 of 4 (4096 bytes)
4096 bytes written.
Writing file 3 of 4 (262144 bytes)
262144 bytes written.
Writing file 4 of 4 (16777216 bytes)
16777216 bytes written.
Copying file testfile1
the c way: Done.
the c++ way: Done.
Copying file testfile2
the c way: Done.
the c++ way: Done.
Copying file testfile3
the c way: Done.
the c++ way: Done.
Copying file testfile4
the c way: Done.
the c++ way: Done.
Summary:
c c++
copy1 0 0
copy2 0 0
copy3 0 0
copy4 0 0
(FreeBSD 9.0-RELEASE-p3 amd64, compiled with clang++)
There could've been a bug in the achi-driver in 9.0, that showed up under heavy load. Or, it could've been a buggy controller, that was failing under the same load -- and not failing under other OSes, because they weren't taxing it as much.
Is this still a problem with FreeBSD 9.2?
As for your program, you ought to check not just for feof(), but also for ferror() in your read/write loop. Further, in my opinion, such read/write loops are a thing from the past. These days, when size_t and offset_t are of the same width (64-bit platforms), you ought to simply mmap() your source file and fwrite it into destination in one go. Look, ma, no loop!
Related
I'm trying to create a program that displays output of a bmp file in the form of hexadecimal. So far I get the output, but I need it to be organized a certain way.
The way it needs to be organized is with the address of the bmp file to be on the left column and then 16 bytes of data in hex across each row in the order they appear in the file. While leaving an extra space between every 8 bytes. So far, I got the hexadecimal to show up, I just need help with organizing it.
What I have:
What I'm trying to make it look like:
Here is my code:
#include <iostream> // cout
#include <fstream> // ifstream
#include <iomanip> // setfill, setw
#include <stdlib.h>
using namespace std; // Use this to avoid repeated "std::cout", etc.
int main(int argc, char *argv[]) // argv[1] is the first command-line argument
[enter image description here][1]{
// Open the provided file for reading of binary data
ifstream is("C:\\Users\\Test\\Documents\\SmallTest.bmp", ifstream::binary);
if (is) // if file was opened correctly . . .
{
is.seekg(0, is.end); // Move to the end of the file
int length = is.tellg(); // Find the current position, which is file length
is.seekg(0, is.beg); // Move to the beginning of the file
char * buffer = new char[length]; // Explicit allocation of memory.
cout << "Reading " << length << " characters... ";
is.read(buffer, length); // read data as a block or group (not individually)
if (is)
cout << "all characters read successfully.\n";
else
cout << "error: only " << is.gcount() << " could be read.\n";
is.close();
// Now buffer contains the entire file. The buffer can be printed as if it
// is a _string_, but by definition that kind of print will stop at the first
// occurrence of a zero character, which is the string-ending mark.
cout << "buffer is:\n" << buffer << "\n"; // Print buffer
for (int i = 0; i < 100; i++) // upper range limit is typically length
{
cout << setfill('0') << setw(4) << hex << i << " ";
cout << setfill('0') << setw(2) << hex << (0xff & (int)buffer[i]) << " ";
}
delete[] buffer; // Explicit freeing or de-allocation of memory.
}
else // There was some error opening file. Show message.
{
cout << "\n\n\tUnable to open file " << argv[1] << "\n";
}
return 0;
}
You could do it something like this:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cctype>
std::ostream& fullLine(std::ostream& out, const std::vector<uint8_t>& v, size_t offset)
{
//save stream state so we can restore it after all the hex/setw/setfill nonsense.
std::ios oldState(0);
oldState.copyfmt(out);
out << std::hex << std::setfill('0') << std::setw(8) << offset << " ";
for (size_t i = 0; i < 16; ++i)
{
if (i == 8) out << " ";
out << std::hex << std::setfill('0') << std::setw(2) << static_cast<uint32_t>(v[i + offset]) << " ";
}
out << " ";
//restore stream state to print normal text
out.copyfmt(oldState);
for (size_t i = 0; i < 16; ++i)
{
out << (std::isprint(v[i + offset]) ? static_cast<char>(v[i + offset]) : '.');
}
out << "\n";
return out;
}
int main()
{
std::vector<uint8_t> data;
std::ifstream f("test.txt", std::ios::binary);
if (f)
{
f.seekg(0, f.end);
data.resize(static_cast<size_t>(f.tellg()));
f.seekg(0, f.beg);
f.read((char*)data.data(), data.size());
const size_t numFullLines = data.size() / 16;
const size_t lastLineLength = data.size() % 16;
for (size_t i = 0; i < numFullLines; ++i)
{
if (!fullLine(std::cout, data, i * 16))
{
std::cerr << "Error during output!\n";
return -1;
}
}
}
return 0;
}
There's probably a fancy way to do it, but I usually go for brute force when I'm looking for particular output using iostreams.
How to handle the partial last line is up to you. :)
Use the % operator to break the line after every 16th count:
cout << hex;
for(int i = 0; i < 100; i++)
{
if(i && (i % 16) == 0)
cout << "\n";
cout << setfill('0') << setw(2) << (buffer[i] & 0xFF) << " ";
}
I need it to be organized a certain way.
In another answer, I submitted this form of dumpByteHex()... perhaps it can help you achieve what you want. (see also https://stackoverflow.com/a/46083427/2785528)
// C++ support function
std::string dumpByteHex (char* startAddr, // reinterpret_cast explicitly
size_t len, // allows to char* from T*
std::string label = "",
int indent = 0)
{
std::stringstream ss;
if(len == 0) {
std::cerr << "\n dumpByteHex() err: data length is 0? " << std::endl << std::dec;
assert(len != 0);
}
// Output description
ss << label << std::flush;
unsigned char* kar = reinterpret_cast<unsigned char*>(startAddr); // signed to unsigned
std::string echo; // holds input chars until eoln
size_t indx;
size_t wSpaceAdded = false;
for (indx = 0; indx < len; indx++)
{
if((indx % 16) == 0)
{
if(indx != 0) // echo is empty the first time through for loop
{
ss << " " << echo << std::endl;
echo.erase();
}
// fields are typically < 8 bytes, so skip when small
if(len > 7) {
if (indent) { ss << std::setw(indent) << " "; }
ss << std::setfill('0') << std::setw(4) << std::hex
<< indx << " " << std::flush;
} // normally show index
}
// hex code
ss << " " << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<int>(kar[indx]) << std::flush;
if((indx % 16) == 7) { ss << " "; wSpaceAdded = true; } // white space for readability
// defer the echo-of-input, capture to echo
if (std::isprint(kar[indx])) { echo += kar[indx]; }
else { echo += '.'; }
}
// finish last line when < 17 characters
if (((indx % 16) != 0) && wSpaceAdded) { ss << " "; indx++; } // when white space added
while ((indx % 16) != 0) { ss << " "; indx++; } // finish line
// the last echo
ss << " " << echo << '\n';
return ss.str();
} // void dumpByteHex()
Output format:
0000 11 22 33 44 55 66 00 00 00 00 77 88 99 aa ."3DUf....w...
The following code only saves the first 7 bytes to the file correctly and the remaining 3072-7=3065 bytes are incorrect. "correct" meaning the same value as stored in 'data'.
#define byte unsigned char
void bytesToImage(byte width, byte height, byte* data, size_t byte_count, char* fileNameWithoutExtension)
{
{
std::ofstream file("k3000", std::ios::binary);
file.write((char *)data, 3000);
}
}
However this code does save the first 500 bytes correctly:
#define byte unsigned char
void bytesToImage(byte width, byte height, byte* data, size_t byte_count, char* fileNameWithoutExtension)
{
{
std::ofstream file("k500", std::ios::binary);
file.write((char *)data, 500);
}
}
data has a length of 3072 and the function is called as follows:
size_t imageByteCount = 32 * 32 * 3;
byte* imageBufferOut = (byte*)malloc(sizeof(byte) * imageByteCount);
//(imageBufferOut is initialized...)
bytesToImage(32, 32, imageBufferOut, imageByteCount, "img");
Please excuse the redundant parameters, I have removed as much as possible to try find the bug.
Hex dumps:
Try adding some more instrumentation. For example:
{
cout << "before:";
for (int i = 0; i < 16; ++i)
cout << ' ' << std::hex << int(data[i]);
cout << '\n';
std::ofstream file("k3000", std::ios::binary);
if (file)
cout << "opened\n";
else
cout << "couldn't open\n";
file.write((char *)data, 3000);
file.flush();
if (file)
cout << "wrote ok\n";
else
cout << "write failed\n";
cout << "after:";
for (int i = 0; i < 16; ++i)
cout << ' ' << std::hex << int(data[i]);
cout << '\n';
}
I am new in C++ in general, and thus, also in file handling in C++.
I need to read a .raw file which has 16-bit integers, and have dimension 512 x 512.
For that I am using following code:
ifstream myData("myData.raw");
short value;
int i = 0;
char buf[sizeof(short)];
while (myData.read(buf,sizeof(buf)))
{
memcpy(&value, buf, sizeof(value));
cout << value << " ";
i++;
}
cout << endl << "Total count: " << i << endl;
The value i am getting for i is not 512 x 512. So I guess something is not right.
Can someone please help me in this regard?
The default open mode is "text" and some characters will be possibly dropped or treated as end of file. ios::binary stops these alterations.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream myData("myData.raw", ios::binary);
short value;
int i = 0;
char buf[sizeof(short)];
while (myData.read(buf, sizeof(buf)))
{
memcpy(&value, buf, sizeof(value));
cout << value << " ";
i++;
}
cout << endl << "Total count: " << i << endl;
}
The code below does not work under Windows and GNU C++, VS10,VS12, Intel C++ 14.0. The code below does work under Linux and GNU C++ 4.7, 4.8, Intel C++ 14, Open64 5.0.Replacing DIMEN with DIMEN-256 in the inner test for-loop ... works!? Any idea?
//============================//
// Read and Write binary file //
// using buffers //
//============================//
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;
int main()
{
// 1. variables and parameters
const long int DIMEN = static_cast<long int>(pow(10.0,8.0));
const long int I_DO_MAX = 100;
const string fileName = "my_file.bin";
ofstream fileOUT;
ifstream fileIN;
double* myArrayAlpha = new double [DIMEN];
double* myArrayBeta = new double [DIMEN];
long int i;
long int j;
// 2. build the array with some data
cout << " 1 --> Build the array with some data" << endl;
for (i = 0; i < DIMEN; i++)
{ myArrayAlpha[i] = static_cast<double>(i); }
for (i = 0; i < I_DO_MAX; i++)
{
// 3. open the file stream
cout << "-------------->>> " << i << endl;
cout << " 2 --> Open the file stream" << endl;
fileOUT.open(fileName.c_str(), ios::out | ios::binary | ios::trunc);
fileIN.open(fileName.c_str(), ios::in | ios::binary);
// 4. test if the file stream is opened
cout << " 3 --> Test if the file stream is opened with success" << endl;
if (!fileOUT.is_open())
{ cout << "Error! The output file stream is not opened. Exit."
<< endl; return -1; }
if (!fileIN.is_open())
{ cout << "Error! The input file stream is not opened. Exit."
<< endl; return -1; }
// 5. write the contents of myArrayAlpha[] to a file
cout << " 4 --> Write and then Read to the file" << endl;
fileIN.seekg(0, fileIN.beg);
fileOUT.seekp(0);
fileOUT.write(reinterpret_cast<char*>(&myArrayAlpha[0]),
DIMEN * sizeof(double));
fileIN.read(reinterpret_cast<char*>(&myArrayBeta[0]),
DIMEN * sizeof(double));
// 6. test that I am writting and reading correctly
for (j = 0; j < DIMEN; j++) // replace DIMEN
{ // with DIMEN-256 to work under Windows
if (myArrayAlpha[j] != myArrayBeta[j])
{ cout << myArrayAlpha[j] << endl;
cout << myArrayBeta[j] << endl;
cout << "j = " << j << endl;
cout << "Error!"; return -1; }
}
cout << " 5 --> Read and Write with success" << endl;
cout << " 6 --> Close the I/O streams" << endl;
// 7. close the file stream
fileIN.close();
fileOUT.close();
}
// 8. free up the RAM
delete [] myArrayAlpha;
delete [] myArrayBeta;
return 0;
}
The problem is that your data is not being flushed to the external sequence after the write call, so it is still positioned in the internal buffer. Add this line after write():
fileOUT << std::flush;
I am making a c++ installer and I have appended both the file to extract and an 8 byte filesize of the file to extract within the program, to the executable. My program exits on a file read error, whats going wrong? To note I don't have any knowledge about c file managing, apart from what I've learned today. I am writing the file test_before.tar.gz, which is 161 bytes, the executable is 12335 bytes long and the filesize file is 8 bytes long, containing 0000161. What's wrong? Ask for more info if needed.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Opening the executable as read-only!" << endl;
FILE *exeFile; // The executable file pointer
FILE *outFile; // The file to write pointer
// Check whether a file name was supplied
if(argc < 2)
{
cout << "Please enter the file to write!" << endl;
return 1;
}
// Open the executable as read-only
if((exeFile = fopen(argv[0], "rb")) == 0)
{
cout << "Error opening the executable!" << endl;
return 1;
}
cout << "Getting the executables size!" << endl;
// Get the files size
fseek(exeFile, 0, SEEK_END);
int size = ftell(exeFile);
cout << "Reading ofset!" << endl;
// Read the ofset bytes contained in the last 7-bytes
char filesize_char[9];
fseek(exeFile, -8, SEEK_END);
fgets(filesize_char, 9, exeFile);
// Convert
int filesize = atoi(filesize_char);
int ofset = (size - filesize) - 8;
cout << "The ofset size is " << ofset << " bytes!" << endl;
cout << "The file size is " << filesize << " bytes!" << endl;
cout << "Reading the file to extract!" << endl;
// Create the variable to contain the file and goto the ofset
char* contents = new char[filesize + 1];
fseek(exeFile, ofset, SEEK_SET);
// Read the file to extract
if(fread(contents, sizeof(char), filesize + 1, exeFile) != sizeof(contents))
{
// Error has occured
if(feof(exeFile)) {
cout << "Premature end of file!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
delete[] contents;
return 1;
} else {
cout << "File read error!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
delete[] contents;
return 1;
}
}
cout << "Writing the file to " << argv[1] << "!" << endl;
// Write the file to extract
if((outFile = fopen(argv[1], "wb")) == 0)
{
cout << "Error opening the file to write!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
fclose(outFile);
delete[] contents;
return 1;
}
fwrite(contents, 1, sizeof(contents), outFile);
//delete variables
fclose(exeFile);
fclose(outFile);
delete[] contents;
return 0;
}
You don't need the while loop at all. After all, you already allocated the memory that would contain all your data. Move file pointer to the start of data fseek(exeFile, ofset, SEEK_SET), then use fread to read it as whole, and then use fwrite to write it into outFile.
You should open your exeFile and outFile with "rb" and "wb" flags otherwise your code would work reliably only with text data.