I'm basically trying to create a simple program that simulates a screen whose value is generated randomly and are outputted to a bmp file. However, there are some trouble in the file operation.. when the fwrite is called, the file stays at zero bytes, meaning nothing was written to that file.. I've tried changing the fopen modes (e.g "w+b", "wb+", "wb") but still no luck.. here is the code anyway
char resultFileName[BUFSIZ];
char currentDirectory[BUFSIZ];
//char generatedFileFolder[] = "\\generatedFile";
FILE *resultFile;
getcwd(currentDirectory, sizeof(currentDirectory));
snprintf(resultFileName, sizeof(resultFileName), "%s%s", currentDirectory, "\\result.bmp");
resultFile = fopen(resultFileName, "w+b");
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
fwrite(&bmfh, sizeof(bmfh), 1, resultFile);
fwrite(&bmih, sizeof(bmih), 1, resultFile);
what am I doing wrong here?
You need to call fclose.
The I/O functions starting with f is buffered, which means they only write periodically (when reaching the maximum buffer size), or when you close it.
Since C is not a garbage-collected language (or language with the concept of destructor), your buffers are not flushed unless you flush it or close the file.
Related
I have been trying to write a file from memory in C, more specifically an executable file. Every time I try to use fputs it detects a '00' in memory after a bit and stops writing. But there is still the rest of the file that it has to write. In the file that I am trying to write there are '00's all over the place for padding. I have some code below for reference:
char *buffer;
buffer = malloc(size);
// ...
FILE *file;
file = fopen("somename","w");
fputs(buffer,file);
fclose(file);
Is there any way I would be able to have '00's in memory without fputs taking it as an EOF?
Thanks!
you should use 'fwrite' take the place of fpus
I have this sample code where I'm trying to implement for my operating systems assignment a program that copies the contents of an input file to an output file. I'm only allowed to use POSIX system calls, stdio is forbidden.
I've thought about storing the contents in a buffer but in my implementation I must know the file descriptor contents size. I googled a little and found about
off_t fsize;
fsize = lseek (input, 0, SEEK_END);
But in this case my file descriptor (input) gets messed up and I can't rewind it to the start. I played around with the parameters but I can't figure a way to rewind it back to the first character in the file after using lseek. That's the only thing I need, having that I can loop byte by byte and copy all the contents of input to output.
My code is here, it's very short in case any of you want have to take a look:
https://github.com/lucas-sartm/OSAssignments/blob/master/copymachine.c
I figured it out by trial and error. All that was needed was to read the documentation and take a look at read() return values... This loop solved the issue.
while (read (input, &content, sizeof(content)) > 0){ //this will write byte by byte until end of buffer!
write (output, &content, sizeof(content));
}
I have written a C program in which I am logging the results to a file. There is an infinite while loop - this is a requirement. To debug the code, I need to look at the log file, but as the program is running, I don't see anything written there. Closing the program forcibly using ctrl+C does not help either. I see nothing written on the file.
I am using simple fopen and fprintf functions to read the file in write mode and write to it.
FILE *fp = fopen("filename.txt", "w");
fprintf(fp, "this wants itself to be written the moment this statement is executed\n");
PS: There is no bug in the code. If I put a terminating condition in while loop and program exits gracefully, I do see things written in the log file.
A difference between printing to a console and printing to a file is that streams are line buffered by default when attached to the console, but block buffered when attached to a file. Change your code to:
FILE *fp = fopen("filename.txt", "w");
setvbuf(fp,0,_IOLBF,0);
fprintf(fp, "this wants itself to be written the moment this statement is executed\n");
and your output will be line buffered even though the stream is attached to a file. You can also do unbuffered streams.
[EDIT: ]
Ref C11 7.21.5.6:
Synopsis
#include <stdio.h>
int setvbuf(FILE * restrict stream,
char * restrict buf,
int mode, size_t size);
Description
The setvbuf function may be used only after the stream pointed to by
stream has been associated with an open file and before any other
operation (other than an unsuccessful call to setvbuf) is performed on
the stream. The argument mode determines how stream will be buffered,
as follows: _IOFBF causes input/output to be fully buffered; _IOLBF
causes input/output to be line buffered; _IONBF causes input/output to
be unbuffered. If buf is not a null pointer, the array it points to
may be used instead of a buffer allocated by the setvbuf function
and the argument size specifies the size of the array; otherwise, size
may determine the size of a buffer allocated by the setvbuf function.
The contents of the array at any time are indeterminate.
Returns
The setvbuf function returns zero on success, or nonzero if an invalid
value is given for mode or if the request cannot be honored.
You should to see the the function fopen(),if you fopen a file with "w" mode,it means if this file exist,clear this file and then write.I think you should use "a+" mode to append data in the end.
I am designing an image decoder and as a first step I tried to just copy the using c. i.e open the file, and write its contents to a new file. Below is the code that I used.
while((c=getc(fp))!=EOF)
fprintf(fp1,"%c",c);
where fp is the source file and fp1 is the destination file.
The program executes without any error, but the image file(".bmp") is not properly copied. I have observed that the size of the copied file is less and only 20% of the image is visible, all else is black. When I tried with simple text files, the copy was complete.
Do you know what the problem is?
Make sure that the type of the variable c is int, not char. In other words, post more code.
This is because the value of the EOF constant is typically -1, and if you read characters as char-sized values, every byte that is 0xff will look as the EOF constant. With the extra bits of an int; there is room to separate the two.
Did you open the files in binary mode? What are you passing to fopen?
It's one of the most "popular" C gotchas.
You should use freadand fwrite using a block at a time
FILE *fd1 = fopen("source.bmp", "r");
FILE *fd2 = fopen("destination.bmp", "w");
if(!fd1 || !fd2)
// handle open error
size_t l1;
unsigned char buffer[8192];
//Data to be read
while((l1 = fread(buffer, 1, sizeof buffer, fd1)) > 0) {
size_t l2 = fwrite(buffer, 1, l1, fd2);
if(l2 < l1) {
if(ferror(fd2))
// handle error
else
// Handle media full
}
}
fclose(fd1);
fclose(fd2);
It's substantially faster to read in bigger blocks, and fread/fwrite handle only binary data, so no problem with \n which might get transformed to \r\n in the output (on Windows and DOS) or \r (on (old) MACs)
I have a legacy function accepting a FILE* pointer in a library. The contents I would like to parse is actually in memory, not on disk.
So I came up with the following steps to work around this issue:
the data is in memory at this point
fopen a temporary file (using tmpnam or tmpfile) on disk for writing
fclose the file
fopen the same file again for reading - guaranteed to exist
change the buffer using setvbuf(buffer, size)
do the legacy FILE* stuff
close the file
remove the temporary file
the data can be discarded
On windows, it looks like this:
int bufferSize;
char buffer[bufferSize];
// set up the buffer here
// temporary file name
char tempName [L_tmpnam_s];
tmpnam_s(tempName, L_tmpnam_s);
// open/close/reopen
fopen_s(&fp, tempName,"wb");
fclose(fp);
freopen_s(&fp, tempName,"rb", fp);
// replace the internal buffer
setvbuf(fp, buffer, _IONBF, bufferSize);
fp->_ptr = buffer;
fp->_cnt = bufferSize;
// do the FILE* reading here
// close and remove tmp file
fclose(fp);
remove(tempName);
Works, but quite cumbersome. The main problem, aside from the backwardness of this approach, are:
the temporary name needs to be determined
the temporary file is actually written to disk
the temporary file needs to be removed afterwards
I'd like to keep things portable, so using Windows memory-mapped functions or boost's facilities is not an option. The problem is mainly that, while it is possible to convert a FILE* to an std::fstream, the reverse seems to be impossible, or at least not supported on C++99.
All suggestions welcome!
Update 1
Using a pipe/fdopen/setvbuf as suggested by Speed8ump and a bit of twiddling seems to work. It does no longer create files on disk nor does it consume extra memory. One step closer, except, for some reason, setvbuf is not working as expected. Manually fixing it up is possible, but of course not portable.
// create a pipe for reading, do not allocate memory
int pipefd[2];
_pipe(pipefd, 0, _O_RDONLY | _O_BINARY);
// open the read pipe for binary reading as a file
fp = _fdopen(pipefd[0], "rb");
// try to switch the buffer ptr and size to our buffer, (no buffering)
setvbuf(fp, buffer, _IONBF, bufferSize);
// for some reason, setvbuf does not set the correct ptr/sizes
fp->_ptr = buffer;
fp->_charbuf = fp->_bufsiz = fp->_cnt = bufferSize;
Update 2
Wow. So it seems that unless I dive into the MS-specific implementation CreateNamedPipe / CreateFileMapping, POSIX portability costs us an entire memcopy (of any size!), be it to file or into a pipe. Hopefully the compiler understands that this is just a temporary and optimizes this. Hopefully.
Still, we eliminated the silly device writing intermediate. Yay!
int pipefd[2];
pipe(pipefd, bufferSize, _O_BINARY); // setting internal buffer size
FILE* in = fdopen(pipefd[0], "rb");
FILE* out = fdopen(pipefd[1], "wb");
// the actual copy
fwrite(buffer, 1, bufferSize, out);
fclose(out);
// fread(in), fseek(in), etc..
fclose(in);
You might try using a pipe and fdopen, that seems to be portable, is in-memory, and you might still be able to do the setvbuf trick you are using.
Your setvbuf hack is a nice idea, but not portable. C11 (n1570):
7.21.5.6 The setvbuf function
Synopsis
#include <stdio.h>
int setvbuf(FILE * restrict stream,
char * restrict buf,
int mode, size_t size);
Description
[...] If buf is not a null pointer, the array it points to may be used instead of a buffer allocated by the setvbuf function [...] and the argument size specifies the size of the array; otherwise, size may determine the size of a buffer allocated by the setvbuf function. The contents of the array at any time are indeterminate.
There is neither a guarantee that the provided buffer is used at all, nor about what it contains at any point after the setvbuf call until the file is closed or setvbuf is called again (POSIX doesn't give more guarantees).
The easiest portable solution, I think, is using tmpfile, fwrite the data into that file, fseek to the beginning (I'm not sure if temporary files are guaranteed to be seekable, on my Linux system, it appears they are, and I'd expect them to be elsewhere), and pass the FILE pointer to the function. This still requires copying in memory, but I guess usually no writing of the data to the disk (POSIX, unfortunately, implicitly requires a real file to exist). A file obtained by tmpfile is deleted after closing.