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.
Related
I'm writing a simple code on Linux that writes into a file. That file will be stored in specific path ( not the same path where the executable is located ).The problem is that when I execute the code , the program is terminating with segmentation fault (core dump)
Here is my code :
#include <stdio.h>
int main ()
{
FILE * pFile;
char buffer[] = { 'x' , 'y' , 'z' };
pFile = fopen ("/home/medwajih/Desktop/bufferfile/buffer.txt", "wb");
fwrite (buffer , sizeof(char), sizeof(buffer), pFile);
fclose (pFile);
return 0;
}
Note that the exe of the program is in "/home/medwajih/Desktop/" and the location where I want to create the buffer.txt file is "/home/medwajih/Desktop/bufferfile/"
Thank you.
If the fopen fails (such as if the /home/medwajih/Desktop/bufferfile directory does not exist, or the file exists but has permissions that disallow you replacing it), then pFile will be set to NULL.
Attempting to use it is then undefined behaviour.
You should generally check all calls that may fail to ensure they don't cause issues later on, such as with:
pFile = fopen ("/home/medwajih/Desktop/bufferfile/buffer.txt", "wb");
if (pFile == NULL) {
fprintf (stderr, "Could not create file\n");
return 1;
}
If the problem is actually that the directory does not exist, you can call mkdir beforehand. And, of course, check the return value of that as well :-)
If it's something else (there's not really enough information in the question to ascertain what it is), you need to find a different way to rectify the problem.
The following is my code for a method that copies a file from a path to a file to a directory provided as the destination. The copy works perfectly fine, however my chmod call assigns the wrong permissions to the copied file in the destination. If the permission in the source is 644, the copied file has a permission of 170 or 120.
I have been attempting to debug this for hours and it's driving me slightly crazy so any help is greatly appreciated.
void copy_file(char* src, char* dest) {
char a;
//extract file name through a duplicate ptr
char* fname = strdup(src);
char* dname = basename(fname);
//open read and write streams
FILE* read;
FILE* write;
read = fopen(src, "r");
chdir(dest);
write = fopen(dname, "w");
//error checking
if (read == NULL) //|| (write == NULL))
{
perror("Read Error: ");
exit(0);
}
else if (write == NULL)
{
perror("Write Error: ");
exit(0);
}
//write from src to dest char by char
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
//close files
fclose(read);
fclose(write);
// this is where I attempt to assign source file permissions
//and it goes horribly wrong
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
chmod(dname, src_st.st_mode);
printf("%o\n", src_st.st_mode & 0777);
}
You fopen(src, "r"), then you chdir(dest). This means that when you later call stat(src, &src_st), there is no reason to think that stat will access the same file as fopen did, or indeed that stat will access any file at all.
If stat fails, you proceed to call chmod anyway, so you pass whatever random junk was in src_st.st_mode to chmod.
You should use fstat(fileno(read), &src_st) before calling fclose(src), instead of calling stat(src, &src_st).
The basic problem is you have to check your system calls like fopen, chdir, and stat immediately.
For example, first thing I tried was copy_file( "test.data", "test2.data" ) not realizing it expected a destination directory.
char* fname = strdup(src);
char* dname = basename(fname);
dname is now test.data, same as the source.
read = fopen(src, "r"); // succeeds
chdir(dest); // fails
write = fopen(dname, "w"); // blows away test.data, the source
You do eventually check read and write, but after the damage has been done.
Blowing away your source file is really bad. It's important that your code deals with failed system calls. If you don't, it will sail along causing confusion and destruction.
Most system calls in C return 0 for success. This is an anti-pattern where the return value is an error flag, so false is failure, and anything else indicates what kind of error (though stat doesn't use that, it uses errno).
When it fails, stat returns -1 which is true. So this is the wrong way around.
struct stat src_st;
if(stat(src, &src_st)){
perror("stat: ");
}
Instead, you have to check for non-zero.
struct stat src_st;
if(stat(src, &src_st) != 0 ){
// Note that I don't use perror, it doesn't provide enough information.
fprintf(stderr, "Could not stat %s: %s\n", src, strerror(errno));
exit(1);
}
As you can guess this gets tedious in the extreme, and you're going to forget, or do it slightly different each time. You'll want to write wrappers around those functions to do the error handling for you.
FILE *fopen_checked( const char *file, const char *mode ) {
FILE *fp = fopen(file, mode);
if( file == NULL ) {
fprintf(stderr, "Could not open '%s' for '%s': %s", file, mode, strerror(errno));
exit(1);
}
return fp;
}
It's not the best error handling, but it will at least ensure your code appropriately halts and catches fire.
A note about chdir: if you can avoid it don't use it. chdir affects the global state of the program, the current working directory, and globals add complexity to everything. It's very, very easy for a function to change directory and not change back, as yours does. Now your process is in a weird state.
For example, if one did copy_file( "somefile", "foo" ) this leaves the program in foo/. If they then did copy_file( "otherfile", "foo" ) they'd be trying to copy foo/otherfile to foo/foo/otherfile.
And, as #robmayoff pointed out, your stat fails because the process is now in a different directory. So even the function doing the chdir is confused by it.
Ensuring that your functions always chdir back to the original directory in a language like C is very difficult and greatly complicates error handling. Instead, stay in your original directory and use functions like basename to join paths together.
Finally, avoid mixing your file operations. Use filenames or use file descriptors, but try not to use both. That means if you're using fopen, use fstat and fchmod. You might have to use fileno to get a file descriptor out of the FILE pointer.
This avoids having to carry around and keep in sync two pieces of data, the file descriptor and the filename. It also avoids issues with chdir or the file being renamed or even deleted, the file descriptor will still work so long as it remains open.
This is also a problem:
char a;
...
while (1){
a = fgetc(read);
if (a == EOF)
{
break;
}
fputc(a, write);
}
fgetc() returns int, not char. Per the C Standard, 7.21.7.1 The fgetc function:
7.21.7.1 The fgetc function
Synopsis
#include <stdio.h>
int fgetc(FILE *stream);
Assuming sizeof( int ) > sizeof( char ), char values are signed, 2s-complement integers, and EOF is an int defined to be -1 (all very common values), reading a file with char a = fgetc( stream ); will fail upon reading a valid 0xFF character value. And if your implementation's default char value is unsigned char, char a = fgetc( stream ); will never produce a value that matches EOF.
I'm writing an application which should read some data at some level from a file. When I run the code (including fopen() and fclose())for more than a few hundred times, I got the error message (which I know it means that it cannot open the file):
Debug Assertaion Failed!
Program:
D:\blahblah
file: f:\dd\vctools\crt\crtwin32\stdio\fgets.c
Line: 57
Expression: (string!=NULL)
Can you please help me to understand why it should break after more than three hundered time?
Func_Main(char * filePath, ...){
for(int i=0;i<1000;i++){
Func_1(filePath);
....
}
....
}
Func_1(char* filepath){
char buffer[1024];
FILE * file= NULL;
file = fopen(filepath, "r");
while(fgets(buffer, sizeof(buffer), file)){
\\ do something
}
fclose(file);
}
You should check the return value of fopen. It will return a null pointer if opening the file failed.
And it will fail because \ is an escape character , use \\ in the filename string.
Problems I see:
You never use the argument passed to Func_1. You use a hard coded path instead.
The hard coded path has an error. You are not escaping the backslash in the hard coded path . It should be:
file = fopen("c:\\blahblah.txt", "r");
^^
You are not checking whether fopen was successful. You are assuming it was successful. Use:
file = fopen("c:\\blahblah.txt", "r");
if ( file == NULL )
{
// Deal with the error.
perror("Unable to open the file");
}
Update, after the OP edited the question
The first two points can be ignored. The last point still needs to be considered.
file = fopen(filepath, "r");
if ( file == NULL )
{
// Deal with the error.
perror("Unable to open the file");
}
So, I have this function on my program that is supposed to save a "car_str" structure into the desired place on a file specified as a parameter. But when I run it, it keeps overwriting the first slot again and again, as if fseek didn't point to the specified place on the file. Is there any problem with my code? I think it may be related with the multiplication, since without it the program does well, but I cannot point to the place I want.
void save(int car_nbr)
{
FILE *f;
f = fopen("memory.txt","wb");
if (!f)
{
printf ("error");
}
else
{
car_nbr--;
fseek(f, sizeof(struct car_str)*car_nbr, SEEK_SET);
fwrite(&car,sizeof(struct car_str),1,f);
rewind(f);
fclose(f);
printf("\nsaved");
}
}
you need to fopen with r+b.
if you fail than file not exist, so you can try use "wb"
"w" - write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
"r+" - read/update: Open a file for update (both for input and output). The file must exist.
f = fopen("memory.txt","r+b");
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.