I'm learning the fopen() on Ubuntu, and here is my code. Could you help on what is the specific failure reason?
a.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main() {
char reg_filename[] = "/home/chuck/Documents/enable";
FILE* f;
char val[2];
f = fopen(reg_filename, "r");
if (f == NULL) {
perror(reg_filename);
printf("error\n");
return 1;
}
setvbuf(f, (char *)NULL, _IONBF, 0);
if (fread(&val, sizeof(val), 1, f) == 0) {
perror(reg_filename);
printf("Read_error\n");
return 1;
}
return 0;
}
Build & run it...
chuck#ubuntu:~/Documents$ gcc a.c
chuck#ubuntu:~/Documents$ ./a.out
/home/chuck/Documents/enable: Success
Read_error
In the code, "enable" is a file in my system.
What I know is that it fails on fread() since "Read_error" pops. But what this "Success" mean? If it failed, why it gives the "Success" word?
And about how to use the fread(), I'm totally new... This fread() will read from f (the file path) with size of val[] length and read to val[], right?
And does it related with the val[] size, in this case, I just put it 2 then sizeof(val) should be 3? Then how will fread gonna to work to read the f (/home/chuck/Documents/enable) into it?
Read the man page for fread
size_t fread(void *ptr, size_t size, size_t nmembFILE *" stream );
And it clearly states,
The function fread() reads nmemb items of data, each size bytes long,
from the stream pointed to by stream, storing them at the location
given by ptr.
Importantly, you might want to change
fread(&val, sizeof(val), 1, f)
to
fread(val, sizeof(val), 1, f)
So it would return 0 if your enable file could be empty!
If you read a short count, (i.e. fewer items than you expected) then fread() has either encountered an error or reached the end of file before reading enough bytes.
In your case, you read 0 items instead of 1 item so there was either an error or end of file was encountered before reading a whole item. Use feof() or ferror() to find out whether you have end of file or an error. i.e. if ferror() returns non zero, there was an error and errno is meaningful.
Related
I am currently working on a project in which I have to read from a binary file and send it through sockets and I am having a hard time trying to send the whole file.
Here is what I wrote so far:
FILE *f = fopen(line,"rt");
//size = lseek(f, 0, SEEK_END)+1;
fseek(f, 0L, SEEK_END);
int size = ftell(f);
unsigned char buffer[MSGSIZE];
FILE *file = fopen(line,"rb");
while(fgets(buffer,MSGSIZE,file)){
sprintf(r.payload,"%s",buffer);
r.len = strlen(r.payload)+1;
res = send_message(&r);
if (res < 0) {
perror("[RECEIVER] Send ACK error. Exiting.\n");
return -1;
}
}
I think it has something to do with the size of the buffer that I read into,but I don't know what it's the correct formula for it.
One more thing,is the sprintf done correctly?
If you are reading binary files, a NUL character may appear anywhere in the file.
Thus, using string functions like sprintf and strlen is a bad idea.
If you really need to use a second buffer (buffer), you could use memcpy.
You could also directly read into r.payload (if r.payload is already allocated with sufficient size).
You are looking for fread for a binary file.
The return value of fread tells you how many bytes were read into your buffer.
You may also consider to call fseek again.
See here How can I get a file's size in C?
Maybe your code could look like this:
#include <stdint.h>
#include <stdio.h>
#define MSGSIZE 512
struct r_t {
uint8_t payload[MSGSIZE];
int len;
};
int send_message(struct r_t *t);
int main() {
struct r_t r;
FILE *f = fopen("test.bin","rb");
fseek(f, 0L, SEEK_END);
size_t size = ftell(f);
fseek(f, 0L, SEEK_SET);
do {
r.len = fread(r.payload, 1, sizeof(r.payload), f);
if (r.len > 0) {
int res = send_message(&r);
if (res < 0) {
perror("[RECEIVER] Send ACK error. Exiting.\n");
fclose(f);
return -1;
}
}
} while (r.len > 0);
fclose(f);
return 0;
}
No, the sprintf is not done correctly. It is prone to buffer overflow, a very serious security problem.
I would consider sending the file as e.g. 1024-byte chunks instead of as line-by-line, so I would replace the fgets call with an fread call.
Why are you opening the file twice? Apparently to get its size, but you could open it only once and jump back to the beginning of the file. And, you're not using the size you read for anything.
Is it a binary file or a text file? fgets() assumes you are reading a text file -- it stops on a line break -- but you say it's a binary file and open it with "rb" (actually, the first time you opened it with "rt", I assume that was a typo).
IMO you should never ever use sprintf. The number of characters written to the buffer depends on the parameters that are passed in, and in this case if there is no '\0' in buffer then you cannot predict how many bytes will be copied to r.payload, and there is a very good chance you will overflow that buffer.
I think sprintf() would be the first thing to fix. Use memcpy() and you can tell it exactly how many bytes to copy.
I'm trying to write a small program to find the buffer size of an open file stream. After searching around a little bit, I found the __fbufsize() function. This is the code I wrote:
#include <stdio.h>
#include <stdio_ext.h>
void main() {
FILE *f;
int bufsize;
f = fopen("test.txt","wb");
if (f == NULL) {
perror("fopen failed\n");
return;
}
bufsize = __fbufsize(f);
printf("The buffer size is %d\n",bufsize);
return;
}
I get the buffer size as zero. I'm a bit confused as to why this is happening. Shouldn't the stream be buffered by default? I get a non-zero value if I use setvbuf with _IOFBF before calling fbufsize.
Note that the correct return type for main() is int, not void.
This code compiles on Linux (Ubuntu 14.04 derivative tested):
#include <stdio.h>
#include <stdio_ext.h>
int main(void)
{
FILE *f;
size_t bufsize;
f = fopen("test.txt", "wb");
if (f == NULL)
{
perror("fopen failed\n");
return -1;
}
bufsize = __fbufsize(f);
printf("The buffer size is %zd\n", bufsize);
putc('\n', f);
bufsize = __fbufsize(f);
printf("The buffer size is %zd\n", bufsize);
fclose(f);
return 0;
}
When run, it produces:
The buffer size is 0
The buffer size is 4096
As suggested in the comments, until you use the file stream, the buffer size is not set. Until then, you could change the size with setvbuf(), so the library doesn't set the buffer size until you try to use it.
The macro BUFSIZ defined in <stdio.h> is the default buffer size. There's no standard way to find the buffer size set by setvbuf(). You need to identify the platform you're working on to allow useful commentary on __fbufsize() as a function (though it seems to be a GNU libc extension: __fbufsize()).
There are numerous small improvements that should be made in the program, but they're not immediately germane.
__fbufsize man page says:
The __fbufsize() function returns the size of the buffer currently used by the given stream.
so I think this is buffer size used by the stream.
What is the best way to get the contents of a file into a single character array?
I have read this question:
Easiest way to get file's contents in C
But from the comments, I've seen that the solution isn't great for large files. I do have access to the stat function. If the file size is over 4 gb, should I just return an error?
The contents of the file is encrypted and since it's supplied by the user it could be as large as anyone would want it to be. I want it to return an error and not crash if the file is too big. The main purpose of populating the character array with the contents of a file, is to compare it to another character array and also (if needed and configured to do so) to log both of these to a log file (or multiple log files if necessary).
You may use fstat(3) from sys/stat.h. Here is a little function to get size of the file, allocate memory if file is less than 4GB's and return (-1) otherwise. It reads the file to the char array passed to char *buffer a char *, which contains the contents of the whole file.It should be free'd after use.
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
char *loadlfile(const char *path)
{
int file_descr;
FILE *fp;
struct stat buf;
char *p, *buffer;
fstat((file_descr = open(path, O_RDONLY)), &buf);
// This check is done at preprocessing and requires no check at runtime.
// It basically means "If this machine is not of a popular 64bit architecture,
// it's probably not 128bit and possibly has limits in maximum memory size.
// This check is done for the sake of omission of malloc(3)'s unnecessary
// invocation at runtime.
// Amd 64 Arm64 Intel 64 Intel 64 for Microsofts compiler.
#if !defined(__IA_64) || !defined(__aarch64__) || !defined(__ia64__) || !defined(_M_IA64)
#define FILE_MAX_BYTES (4000000000)
// buf.st_size is of off_t, you may need to cast it.
if(buf.st_size >= FILE_MAX_BYTES-1)
return (-1);
#endif
if(NULL == (buffer = malloc(buf.st_size + 1)))
return NULL;
fp = fdopen(file_descr, "rb");
p = buffer;
while((*p++ = fgetc(fp)) != EOF)
;
*p = '\0';
fclose(fp);
close(file_descr);
return buffer;
}
A very broad list of pre-defined macros for various things can be found # http://sourceforge.net/p/predef/wiki/Home/. The reason for the architecture and file size check is, malloc can be expensive at times and it is best to omit/skip it's usage when it is not needed. And querying a memory of max. 4gb for a whole block of 4gb storage is just waste of those precious cycles.
From that guy's code just do, if I understand your question correctly:
char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
if(length > MY_MAX_SIZE) {
return -1;
}
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
// start to process your data / extract strings here...
}
i want to open a file, write some data on it so i have to use (Fopen) " i can't use open because i need fopen in some other things "
now if i want to write on the file using fwrite it just don't i don't know why this is what i referred to in my code #option1, but if i get the file descriptor and use normal write method everything works fine see #option 2 below.
anyone can help me to make fwrite works ?
char file_data[256] // has some values
int file_size = strlen(file_data);
FILE *file;
file = fopen(MY_FILE_NAME, "w+");
if(!file){//edited
return false;
}
#option 1//this is not working
fwrite(file_data,1,file_size,file);
#end of option 1
#option 2//this works
int fd = fileno(file);
int x = write(fd,file_data,file_size);//
#end of option 1
EDIT
my file_data is something like this
4 bytes is reserved for an integer (required)
200 bytes is reserved for a string (optional)
buffered IO operations use a buffer that is managed by the C lib. Your "problem" is that fwrite is buffered meaning that in order to write to the file you most likely need to flush it with fflush() or just close the file.
First of all:
if(!file < 0 ){
return false;
}
file is either NULL (on failure) or not (on success) - there's no point in testing it against 0 as it's a pointer (therefore, unsigned).
Your fwrite call seems OK, but you should make sure that the amount you're trying to write is correct (is there a null-terminated string inside file_data?).
Another problem you may be facing is that you don't close or flush the file - this may cause some data to remain in the file-buffer and not be written to the disk.
If you want to check the fopen() return value, do like this:
if (file == NULL) return false;
then, if you want to write a string fputs() is preferable, IMHO, because it communicates better that what you're writing is a string.
Since, according to your last edit, you aren't writing ASCII strings, this is what you should code:
#include <stdio.h>
struct String
{
int size;
char data[200];
};
int main()
{
struct String s;
FILE* file = NULL;
file = fopen("filename", "wb+");
memset(&s, '\0', sizeof(s));
strcpy(s.data, "Hello, world!");
s.size = strlen(s.data);
fwrite(&s, 1, sizeof(s), file);
if (!file) return 1;
fclose(file);
}
At first sight, the mistake seems to be at line #2:
int file_size = strlen(file_data);
This only works if there exists a terminal nul character. So file_size must be either provided for example as a function argument or the you must use the full size of the array.
The following should work:
int write_in_my_file(int data_int, const char* data_str)
{
size_t written;
FILE* file = fopen(MY_FILE_NAME, "wb+"); /* SuperJulietta */
if (!file) return false;
written = fwrite(&data_int, sizeof(data_int), 1, file);
if (written == sizeof(data_int))
{
if (opt_str) fputs(opt_str, file);
}
fclose(file);
return written == sizeof(data_int);
}
Note: this code was not compiled, and error handling is partial.
Edit : if you don't close the file, you'll have to call fflush instead.
You have to put a fflush(file); after the fwrite to force the writing of the data or you can also remove the buffer completely by doing a setbuf(file, NULL); after your fopen call.
I think you need to either do fclose(file) or fflush(file). because fopen is buffered IO so It does not write immidiately, so to ensure that file write is done, you need to do this.
I guess your fwrite code is not the problem.
Whenever the first byte in your file_data is \0 then you write nothing. Since the data is not a string, write 256 bytes. This code works:
#include <stdio.h>
#include <string.h>
#define MY_FILE_NAME "sample.bin"
#define SAMPLE_DATA "Content Content"
int main()
{
char file_data[256];
int file_size = sizeof(file_data);
// fill in some sample data
memcpy(file_data, SAMPLE_DATA, sizeof(SAMPLE_DATA));
FILE *file = fopen(MY_FILE_NAME, "w+");
if (file) {
fwrite(file_data, 1, file_size, file);
fclose(file);
}
}
You see, this is your fwrite. I use sizeof instead of strlen to determine the amount of bytes that will be written...
BR
fwrite is used for binary output, so you have to open file with "wb"
I used this code to read file. But fread function always return 0. What is my mistake?
FILE *file = fopen(pathToSourceFile, "rb");
if(file!=NULL)
{
char aByte[50000];
int ret = fread(aByte, sizeof(aByte), 1, file);
if(ret != 0)
{
not jump into there;
fseek(file, 0, SEEK_SET);
fwrite(aByte, ret, 1, file);
}
}
fclose(file);
are you sure that your file has a size greater than 50000 ? otherwise you could try:
fread(aByte,1, sizeof(aByte), file);
ferror() will tell when something is wrong.
You can print the actual error message using perror().
You can't fwrite to a file open in rb mode.
Your statement that ret is always zero is false. If you had properly instrumented your code, you'd not be making false claims:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *file = fopen("junk.dat", "rb");
if(file!=NULL)
{
char aByte[50000];
int ret = fread(aByte, sizeof(aByte), 1, file);
fprintf(stderr, "fread returned %d\n", ret);
if(ret != 0)
{
int fs = fseek(file, 0, SEEK_SET);
if(fs == -1) {
perror("fseek");
exit(1);
}
fs = fwrite(aByte, ret, 1, file);
if(fs != ret) {
perror("fwrite");
exit(1);
}
}
}
fclose(file);
return 0;
}
Yields:
fread returned 1
fwrite: Bad file descriptor
when run.
In my case I wanted to read a file of size 6553600 bytes (an mp3), and it was returning 0 bytes read. It drove me crazy, till, I tried to manually hardcode 30 bytes, and it did read 30 bytes.
I started playing with it and see how much can it read, and it turns out that it can read exactly 262144 (2^18) bytes, if you ask it to read 262145 bytes it reads 0.
Conclusion: at least with this function you can't load the whole file in one go.
In case someone else runs into this. I just ran into a similar issue. It is because the 2nd argument to fread should be the size of each element in the buffer. In OP's code it is the size of the pointer to the buffer.
This should work provided buff has at least 1 element:
int ret = fread(aByte, sizeof(aByte[0]), 1, file);
Please check man fread
man fread(3)
size_t fread(void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);
RETURN VALUE
On success, fread() and fwrite() return the number of items read
or written. This number equals the number of bytes transferred
only when size is 1. If an error occurs, or the end of the file
is reached, the return value is a short item count (or zero).
As your file is smaller than 50000Bytes aka. size of a item, the read item count is 0.
In my case,
fseek(rFile, 0, SEEK_END);
iTotalSize = ftell(rFile);
fseek(rFile, 0, SEEK_SET); // <-- I wrote SEEK_END, not SEEK_SET
so it read 0 byte(anything)
Did you:
#include <unistd.h>
If not, and if you compile without -Wall, the C compiler can incorrectly assume that the second argument to fread() is an int rather than an off_t, which can mess up the function call. Your code snippet doesn't show any #include statements, so please make sure you're including everything that you're using.