I would like to create a binary file representing an integer. I think the file should be 4 bytes. I use linux. How to do that?
Another question: How do I assign the content of that file to an integer in C?
In standard C, fopen() allows the mode "wb" to write (and "rb" to read) in binary mode, thus:
#include <stdio.h>
int main() {
/* Create the file */
int x = 1;
FILE *fh = fopen ("file.bin", "wb");
if (fh != NULL) {
fwrite (&x, sizeof (x), 1, fh);
fclose (fh);
}
/* Read the file back in */
x = 7;
fh = fopen ("file.bin", "rb");
if (fh != NULL) {
fread (&x, sizeof (x), 1, fh);
fclose (fh);
}
/* Check that it worked */
printf ("Value is: %d\n", x);
return 0;
}
This outputs:
Value is: 1
From the operating system's point of view, all files are binary files. C (and C++) provide a special "text mode" that does stuff like expanding newline characters to newline/carriage-return pairs (on Windows), but the OS doesn't know about this.
In a C program, to create a file without this special treatment, use the "b" flag of fopen():
FILE * f = fopen("somefile", "wb" );
Open the file for binary read/write. fopen takes a b switch for file access mode parameter - see here
See the fopen page in Wikipedia for the difference between text and binary files as well as a code sample for writing data to a binary file
See man for syscalls open, write and read.
Related
I'm working on a simple file splitter/merger program in the C programming language. The problem is, for some reason fopen returns NULL, and because of that, my program is crashing at the fwrite statement. How do I fix this?
Here is the C file:
int SplitFile(char* filename, char* output, size_t size)
{
char current_file_name[256];
int file_count = 0, i = 0;
FILE *file = fopen( filename, "rb" );
printf("split %s into chunks of %d named\n", filename, size);
if (!file)
return E_BAD_SOURCE;
else
{
output = (char *) malloc(size * sizeof(char));
if (output == NULL)
return E_NO_MEMORY;
else
{
int bytes_read = 0;
FILE *outFile;
do
{
bytes_read = fread(output, sizeof(char), size, file );
sprintf(current_file_name, "%s%04lu\n", "part", file_count++);
outFile = fopen (current_file_name, "wb" ); // THIS RETURNS NULL
fwrite(output, sizeof(char), bytes_read, outFile); //CRASHES ON THIS LINE
}
while ( bytes_read > 0 )
;
//fclose(outFile);
}
}
fclose(file);
printf("...\n");
return 0;
}
The proper thing to do is check errno when fopen returns NULL.
I'm going to guess that your problem is that you're trying to write to a filesystem that doesn't allow \n in filenames, but it could be a permissions issue as well.
There are many reasons fopen can return NULL including (but certainly not limited to):
The file doesn't exist
The file is opened in a mode that doesn't allow other accesses
The network is down
The file exists, but you don't have permissions
A file exists with the name you gave, but the current directory of the process is not what you expected so the relative pathname fails to find and open the file.
The way to find out which is responsible is to dig into the errno code.
However just because you resolve this particular error doesn't mean you can assume fopen will never return NULL. When dealing with I/O operations your code simply has to expect failure. It's not possible to predict the success of I/O operations, and they can always fail.
It means that the file might not exist or some permission error occurred while accessing a file such as "Read-Only" or "Write-Protected", so in those cases fopen will return 0 (a NULL pointer). On success it will return a file pointer as a handler.
fp=fopen("c:\\ABC.txt", "r"); cannot be the same as fp=fopen("c:\\abc.txt", "r");.
Use // instead of \\ in a Linux environment.
P.S.: In Linux and Unix-like operating systems file names are case-sensitive.
Is fopen for write return NULL in the first run?
I noticed that in the while you keep open files for write but not closing them.
Try to add fclose(outFile) after fwrite:
outFile = fopen ( current_file_name , "wb" );
fwrite(output, sizeof( char ), bytes_read, outFile);
fclose(outFile)
It is possible you open more files than your OS allows.
In Unix, for fopen(), there is no reason to prepend ./ to a filename passed to fopen().
In my case, i was reading the same file all over again in a while loop and forgot to close it.
I used a function for reading the file and finding a match and the function had a return; statement that terminated the function before doing fclose(fp) :D
The path given for the file is checked from wherever the executable is present.
In my case I was opening the text file in c file when both were present at the same place.
It was continuously giving the error of file not found.
Placed the file in the folder of executable and it started working.
In my case, it was because I was trying to create the file in a directory that does NOT exist.
I wish to open a file using the "a+b" mode, i.e. if it does not exist it is created automatically, but if it does I don't want to overwrite it. I want to be able to read and write to the file.
The file is binary, and I want to save records of a specific struct in it. So I want to do fseek() to the record I want and then save the record using fwrite().
The code looks as follows (MyRecord is a typedef to a struct, while FILENAME is a #define to the file's name):
int saveRecord(MyRecord *pRecord, int pos)
{
FILE* file = fopen(FILENAME, "a+b");
if (file == NULL)
{
printf("Unable to open file %s\n", FILENAME);
return 0;
}
fseek(file, pos * sizeof(MyRecord), SEEK_SET);
fwrite(pRecord, sizeof(MyRecord), 1, file);
fclose(file);
return 1;
}
However this code just appends the record to the end of the file, even if I set pos to 0. Why isn't fseek() with SEEK_SET working in append mode?
I know I can simply open it with "r+b" and if it fails open it with "wb", but I want to know why this doesn't work and why fseek() with SEEK_SET is leaving the file pointer at the end. Any references to places where this behaviour is documented appreciated (because I couldn't find any, or I am using the wrong keywords).
That's because in a mode, writing to the FILE* always appends to the end. fseek only sets the read pointer in this mode. This is documented in the C standard, 7.19.5.3 fopen:
Opening a file with append mode ('a' as the first character in the mode argument)
causes all subsequent writes to the file to be forced to the then current end-of-file,
regardless of intervening calls to the fseek function.
Plain C does not have any sane way to achieve what you want. If you're on a POSIX system or anything remotely close, you can use fd=open(FILENAME, O_CREAT|O_RDRW, 0666) and then fdopen(fd, "rb+").
Edit: Another thing you could try, with plain C:
f = fopen(FILENAME, "a+b");
if (!f) /* ... */
tmp = freopen(0, "r+b", f);
if (tmp) f = tmp;
else /* ... */
Use "r+b" mode and fallback to "w+b" if it fails.
The "a+b" mode, allows you to read and append; the "r+b" allows random read and write.
The documentation for fopen describes how the file behaves with the different modes.
I am using fopen to write to a binary file and using the cstdio (stdio.h) library due to legacy code and it must be cross-platform compatible with Windows and Linux.
For the prototype, FILE * fopen ( const char * filename, const char * mode );, I am using const char * mode = "ab", which will append to a binary file. Writing operations append data at the end of the file. The file is created if it does not exist.
I have N number of input files where I process data from and write to one output file for each type, where I have M types. I process one input file and write the data to each corresponding output file. I then will close that ith input file and open (i + 1)th, and repeat the process by appending the data from the input file to the output files.
If an output file exists at the beginning on the executable, I want it deleted. If it exists and I don't delete it, then when I use the "wb" mode, then it will just append data to the output file, which will result in duplication I don't want. I am open to a boost solution and I like to maintain standards best as possible (i.e avoid POSIX if possible)
fopen C++ reference
Here is one way
char* infile[N] = //input names
char* outfile[M] = //output names
int i, j;
for (i = 0; i < N; i++){
//process input
char* mode = "ab";
if (i == 0) mode = "wb";
for (j = 0; j < M; j++){
FILE* f = fopen(outfile[j], mode);
//write to file
fclose(f);
}
}
The "w" mode should overwrite the file. It is "a" mode that will avoid deleting a file that already exists.
EDIT: You can also remove (const char * filename) if you want to delete the files at the beginning of execution. If that's the case then you never have to use the "wb" mode.
One possibility would be to use open (_open for Windows) to create the appropriate file handle and then use fdopen (_fdopen for Windows) to create a stdio handle out of it. You will need some preprocessor magic to handle the fact that the names are not exactly the same in Linux and Windows:
// Allow us to use Posix compatible names on Windows
#ifdef WINDOWS
#define open _open
#define O_CREAT _O_CREAT
#define O_TRUNC _O_TRUNC
#define O_APEND _O_APPEND
#define S_IREAD _S_IREAD
#define S_IWRITE _S_IWRITE
#define fdopen _fdopen
#endif
int fd = open(filename, O_CREAT | O_TRUNC | O_APPEND, S_IREAD | S_IWRITE);
FILE *fp = fdopen(fd, "a");
If you want to overwrite rather than append, why not just use the mode "wb"? "w" overwrites the file when writing.
I am trying to copy a file from a specified library to the current directory. I can copy text files perfectly. Any other files become corrupt. The program detects a feof before it should.
#include <stdio.h>
int BUFFER_SIZE = 1024;
FILE *source;
FILE *destination;
int n;
int count = 0;
int written = 0;
int main() {
unsigned char buffer[BUFFER_SIZE];
source = fopen("./library/rfc1350.txt", "r");
if (source) {
destination = fopen("rfc1350.txt", "w");
while (!feof(source)) {
n = fread(buffer, 1, BUFFER_SIZE, source);
count += n;
printf("n = %d\n", n);
fwrite(buffer, 1, n, destination);
}
printf("%d bytes read from library.\n", count);
} else {
printf("fail\n");
}
fclose(source);
fclose(destination);
return 0;
}
Are you on a Windows machine? Try adding "b" to the mode strings in the calls to fopen.
From man fopen(3):
The mode string can also include the letter 'b' either as a last character or as a character between the characters in any of the two-character strings described above. This is strictly for compatibility with C89 and has no effect; the 'b' is ignored on all POSIX conforming systems, including Linux. (Other systems may treat text files and binary
files differently, and adding the 'b' may be a good idea if you do I/O
to a binary file and expect that your program may be ported to non-Unix
environments.)
You need to specify the "b" option to fopen:
source = fopen("./library/rfc1350.txt", "rb");
...
destination = fopen("rfc1350.txt", "wb");
Without it, the file is opened in text ("t") mode, and this results in translation of end-of-line characters.
You need to open the files in binary format rather than text format. In your calls to fopen, use "rb" and "wb" rather than "r" and "w" respectively.
This question already has answers here:
How to truncate a file in C?
(6 answers)
Closed 8 years ago.
I am using fopen fseeko64 ftello64 fclose etc. to operating on a file.
How can I truncate a file? I know that there is no standard way to do this in C. All I want is some way that will work on any win32 platform. I'm using mingw gcc to compile.
Please note: I meant truncate the size of the file to a specified size, not make it 0 size. And using a trick like copy part to another file and delete/rename is not appropriate.
SetEndOfFile()
Get a handle to the file with write access, set the file pointer, then call SetEndOfFile().
-Adam
If you want to truncate the file to zero size, you can fopen with the "w" flag:
FILE *fh = fopen("file.txt","w");
if (fh != NULL) fclose(fh);
For truncating to a specific size in standard C, you can do this with a transfer/rename solution, something like:
FILE *finp = fopen ("inp.txt", "rb"); // should check for NULLs
FILE *fout = fopen ("out.txt", "wb");
size_t sz = 100000; // 100,000 bytes
char *buff = malloc (sz); // should check for NULL
sz = fread (buff, 1, sz, fin); // should check for errors
fwrite (buff, 1, sz, fout);
free (buff);
fclose (fin);
fclose (fout);
rename ("out.txt", "inp.txt); // should check for error
Of course, if you have access to the Win32 headers and libraries (and I believe MinGW gives you this), you can use SetEndOfFile(), since it does it in place, rather than having to create a new file and then rename it.
That means using Windows handle-based file I/O rather than the C FILE*-based but, if you're limiting yourself to Windows anyway, that may not matter. If you want portability on the other hand, you'll need a solution based on standard C, such as the transfer/rename solution above.
For FILE based file operations, use _fileno() and _chsize_s() to change the size of a file.
int changesize(FILE *fp, __int64 size)
{
int filedes = _fileno(fp);
return _chsize_s(filedes, size);
}
A truncate version can be written by validating that the supplied size is less than the current file size, as _chsize_s() will truncate or extend a file's size - see http://msdn.microsoft.com/en-us/library/whx354w1(VS.80).aspx.
If you simply fopen() a file with the "w" argument, it will be truncated.
http://www.cplusplus.com/reference/clibrary/cstdio/fopen.html
As mentioned already, you can use fopen() with the "w" flag like:
FILE *f = fopen("file.txt", "w");
Also, if you already have the file opened, you can use the function freopen(), again with the "w" flag:
FILE *f = fopen("file.txt", "r"); //initial fopen() call
...
f = freopen("file.txt", "w", f); //reopens "file.txt" and truncates it
http://www.cplusplus.com/reference/clibrary/cstdio/freopen.html
EDIT: After seeing you've edited your OP, I won't repost what Pax and Adam Davis has already put. Also, I'll confirm what Pax said, that the MinGW does give you access to the Win32 headers.