I am actually writing a c++ program that reads any kind of file and saves it as a bmp file, but first I need to read the file, and thats were the issue is
char fileName[] = "test.jpg";
FILE * inFileForGettingSize;//This is for getting the file size
fopen_s(&inFileForGettingSize, fileName, "r");
fseek(inFileForGettingSize, 0L, SEEK_END);
int fileSize = ftell(inFileForGettingSize);
fclose(inFileForGettingSize);
ifstream inFile;//This is for reading the file
inFile.open(fileName);
if (inFile.fail()) {
cerr << "Error Opening File" << endl;
}
char * data = new char[fileSize];
inFile.read(data, fileSize);
ofstream outFile;//Writing the file back again
outFile.open("out.jpg");
outFile.write(data, fileSize);
outFile.close();
cin.get();
But when I read the file, lets say its a plainttext file it allways outputs some wierd charactes at the end, for example:
assdassaasd
sdaasddsa
sdadsa
passes to:
assdassaasd
sdaasddsa
sdadsaÍÍÍ
So when I do this with a jpg, exe, etc. It corrupts it.
I am not trying to COPY a file, I know there are other ways for that, Im just trying to read a complete file byte per byte. Thanks.
EDIT:
I found out that those 'Í' are equal to the number of end lines the file has, but this doesn't help me much
This is caused by newline handling.
You open the files in text mode (because you use "r" instead of "rb" for fopen and because you don't pass ios::binary to your fstream open calls), and on Windows, text mode translates "\r\n" pairs to "\n" on reading and back to "\r\n" when writing. The result is that the in-memory size is going to be shorter than the on-disk size, so when you try to write using the on-disk size, you go past the end of your array and write whatever random stuff happens to reside in memory.
You need to open files in binary mode when working with binary data:
fopen_s(&inFileForGettingSize, fileName, "rb");
inFile.open(fileName, ios::binary);
outFile.open("out.jpg", ios::binary);
For future reference, your copy routine could be improved. Mixing FILE* I/O with iostream I/O feels awkward, and opening and closing the file twice is extra work, and (most importantly), if your routine is ever run on a large enough file, it will exhaust memory trying to load the entire file into RAM. Copying a block at a time would be better:
const int BUFFER_SIZE = 65536;
char buffer[BUFFER_SIZE];
while (source.good()) {
source.read(buffer, BUFFER_SIZE);
dest.write(buffer, source.gcount());
}
It's a binary file, so you need to read and write the file as binary; otherwise it's treated as text, and assumed to have newlines that need translation.
In your call to fopen(), you need add the "b" designator:
fopen_s(&inFileForGettingSize, fileName, "rb");
And in your fstream::open calls, you need to add std::fstream::binary:
inFile.open(fileName, std::fstream::binary);
// ...
outFile.open("out.jpg", std::fstream::binary);
Related
Using a REST library, I am trying to set it up as a file sharing server, but am running into issues when transferring large files.
As I understand it, the file transfer should mean opening a stream to the file, getting its buffer in a stringstream,then write it within a response body. This seems to work with small files of only a few bytes or KB, but anything larger fails.
std::string filePath = "some_accessible_file";
struct stat st;
if(stat(filePath.c_str(), &st) != 0)
{
//handle it
}
size_t fileSize = st.st_size;
std::streamsize sstreamSize = fileSize;
std::fstream str;
str.open(filePath.c_str(), std::ios::in);
std::ostringstream sstream;
sstream << str.rdbuf();
const std::string str1(sstream.str());
const char* ptr = str1.c_str();
response.headers().add(("Content-Type"), ("application/octet-stream"));
response.headers().add(("Content-Length"), fileSize);
if (auto resp = request.respond(std::move(response))) //respond returns shared pointer to respond type
{
resp->write(ptr, sstreamSize ); //Access violation for large files
}
Not quite sure why large files would fail. Does file type make a difference? I was able to transfer small text files etc. but a small pdf failed...
The root cause of this error was std::fstream not reading the entire file because it was opened in text mode. In windows, this makes reading stop at a end of file (0x1A) character.
The fix is to open the file in std::ios::binary mode.
I'm new to C++, I have an image named "test.jpg", i convert it to base64 and decode it again like this:
std::ifstream inputFile;
inputFile.open("test.jpg",std::ios::binary);
std::filebuf* pbuf = inputFile.rdbuf();
inputFile.seekg (0, ios::end);
int length = inputFile.tellg();
// allocate memory to contain file data
char* buffer=new char[length];
// get file data
pbuf->sgetn (buffer,length);
inputFile.close();
CBase64 base64;
string encodedData = base64.base64_encode((unsigned char*)buffer,length);
delete[] buffer;
string decodedData = base64.base64_decode(encodedData);
ofstream outPutFile;
outPutFile.open("test2.jpg",ios::binary | ios::out);
outPutFile.write(decodedData.c_str(), decodedData.length());
outPutFile.close();
the "test2.jpg" has exact same size as "test.jpg"(the original file) but, i can't open it.
i couldn't find what is the problem.
i got it working. i just replaced:
outPutFile.open("test2.jpg",ios::binary | ios::out);
with
outPutFile.open("test2.jpg", ios_base::out | ios_base::binary);
std::string path = "file.txt";
std::string cfgString = "data";
std::ofstream output(path.c_str(), ios_base::out | std::ios::binary);
if (output.is_open()) {
output.write(cfgString.data(), cfgString.length());
}
output.close();
Apparently, there is no superficial problem with your file writing logic even though there are some irregularities. The biggest problem is in your main logic.
The program seems to be simple program of copying a file. What you are doing is reading a file, converting its data to base64 string and then again decoding the data to std::string. Now one small problem. Conversion of base64 string cannot be successfully done into a null terminated ANSI string for obvious reasons that any 0 in decoded binary data will terminate the string prematurely. Secondly you are opening a file in binary mode to write but trying to write std::string in the file. But that doesn't matter as you data has already been corrupted in your previous operation.
To solve this, you can simply use file copying example as this or make sure you write only binary data with care to your output file which means read in binary from input file and write to output file the same buffer. No base64 encoding decoding is required.
it looks like you forgot to write
inputFile.seekg (0, ios::beg);
after getting file length. it means you try to read from the end of the file instead of its beginning.
i try to read the entire text file using vc++ with this code
ifstream file (filePath, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = (long)file.tellg();
char *contents = new char [size];
file.seekg (0, ios::beg);
file.read (contents, size);
file.close();
isInCharString("eat",contents);
delete [] contents;
}
but it's not fetch all entire file ,why and how to handle this?
Note : file size is 1.87 MB and 39854 line
You are missing the following line
file.seekg (0, file.end);
before:
size = file.tellg();
file.seekg (0, file.beg);
As discribed in this example: http://www.cplusplus.com/reference/istream/istream/read/
Another way to do this is:
std::string s;
{
std::ifstream file ("example.bin", std::ios::binary);
if (file) {
std::ostringstream os;
os << file.rdbuf();
s = os.str();
}
else {
// error
}
}
Alternatively, you can use the C library functions fopen, fseek, ftell, fread, fclose. The c-api can be faster in some cases at the expense of a more STL interface.
You really should get the habit of reading documentation. ifstream::read is documented to sometimes not read all the bytes, and
The number of characters successfully read and stored by this function
can be accessed by calling member gcount.
So you might debug your issues by looking into file.gcount() and file.rdstate(). Also, for such big reads, using (in some explicit loop) the istream::readsome member function might be more relevant. (I would suggest reading by e.g. chunks of 64K bytes).
PS it might be some implementation or system specific issue.
Thanks all, i found the error where,
simply the code below reads the entire file ,
the problem was in VS watcher itself it was just display certain amount of data not the full text file.
std::ifstream sr(path.c_str());
if (!sr)
throw runtime_error("Could not open file '"+path+"\'");
sr.seekg(0, ios::end);
streampos lastPos = sr.tellg(); //returns 3161125
unsigned dataSize = (int)lastPos - 100; //dataSize becomes 3161025
char* data = (char*)malloc(dataSize);
if (!data)
throw runtime_error("Out of memory whean allocating read buffer");
sr.clear();
sr.seekg(0, ios::beg);
sr.read(data, dataSize); //sr.read(data, 3110000) works!
if(sr.fail()) //fails
This code fails, but if I read 3110000 bytes, the read() succeeds and fail() is false. I can load the file via stream iterators like this:
string data(std::istreambuf_iterator<char>(sr),
std::istreambuf_iterator<char>());
Any idea why read() fails?
The value returned by seekg() + tellg() is reliable only if the file is opened in binary mode. In text mode line endings are translated, with a different result depending on the way your operating system stores files.
Specifically, on Windows the CR+LF pair is translated to a single character '\n'.
I need to read bytes from a jpg file in c++ so write this codes:
ifstream in("1.jpg"ios::binary);
while(!in.eof()){
char ch = in.get();
}
as you know a jpg file consist of 256 difference chars that we can save it's repeat in a a arr.but the problem is that this code that i wrote read chars in the form of unicode so it consist of 9256 difference char.how can i read from 1.jpg that it wasn't unicode?
The get function reads unformatted data from the file, it just casts the char it read as an int. Are you seeing data read from the file as different to the actual data in the file? If you are there could be a problem elsewhere in the code, and you should provide more.
Alternatively you could read chunks of unformatted data using read.
int main()
{
std::ifstream in("1.jpg", std::ios::binary);
char buffer[1024];
while (in)
{
in.read(buffer, sizeof(buffer));
if (in.gcount() > 0)
{
// read in.gcount() chars from the file
// process them here.
}
}
}