C: can't write data on file - c

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"

Related

Check if a file is empty or not

How can I check if a text file has something written or not. I tried:
LOGIC checkfile(char * filename)
{
FILE *pf;
pf=fopen(filename,"wt");
fseek(pf,0,SEEK_END);
if(ftell(pf)==0)
printf("empty");
}
This function returns empty everytime, even in my text file I have few words or numbers written.
The problem is that you opened the file for writing. When you do that, everything in the file is lost, and the length of the file is truncated to 0.
So you need to open the file for reading. And the easiest way to see if the file is empty is to try to read the first character with fgetc. If fgetc returns EOF, then the file is empty.
First of all: DO NOT OPEN THE FILE FOR WRITING!
second: for knowing about file status in C you can use fstat which is in sys headear file!
You can use struct stat for using this function
here is a simple example:
#include <sys/stat.h>
int main(void)
{
int fields = 0;
int size = 0;
// Open the file test.txt through open()
// Note that since the call to open directly gives
// integer file descriptor so we used open here.
// One can also use fopen() that returns FILE*
// object. Use fileno() in that case to convert
// FILE* object into the integer file descriptor
if(fields = open(file_path, "r")){
struct stat buf;
fstat(fields, &buf);
size = (int)buf.st_size;
}
printf("size of file is %d", size);
return 0;
}
Note: I just include a header file that related to fstat. You can add other header files yourself
What about using fscanf to read the file, and check if something was actually read?
FILE *fp;
char buff[255] = "";
fp = fopen(filename, "r");
fscanf(fp, "%s", buff);
if (!*buff)
printf("Empty\n");
else
printf("%s\n", buff);
fclose(fp);

C fopen and fgets returning weird characters instead of file contents

I am doing a coding exercise and I need to open a data file that contains lots of data. It's a .raw file. Before I build my app I open the 'card.raw' file in a texteditor and in a hexeditor. If you open it in textEdit you will see 'bit.ly/18gECvy ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿Vˇƒ' as the first line. (The url points to Rick Roll as a joke by the professor.)
So I start building my app to open the same 'card.raw' file. I'm doing initial checks to see the app print to the console the same "stuff" as when I open it with TextEdit. Instead of printing out I see when I open it with TextEdit (see the text above), it starts and continues printing out text that looks like this:
\377\304 'u\204\206\226\262\302\3227\205\246\266\342GSc\224\225\245\265\305\306\325\326Wgs\244\346(w\345\362\366\207\264\304ǃ\223\227\2678H\247\250\343\344\365\377\304
Now I have no idea what the '\' and numbers are called (what do I search for to read more?), why it's printing that instead of the characters (unicode?) I see when I open in TextEdit, or if I can convert this output to hex or unicode.
My code is:
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main(int argc, const char * argv[]) {
FILE* file;
file = fopen("/Users/jamesgoldstein/CS50/CS50Week4/CS50Recovery/CS50Recovery/CS50Recovery/card.raw", "r");
char output[LINE_MAX];
if (file != NULL)
{
for (int i = 1; fgets(output, LINE_MAX, file) != NULL; i++)
{
printf("%s\n", output);
}
}
fclose(file);
return 0;
}
UPDATED & SIMPLIFIED CODE USING fread()
#include <stdio.h>
#include <string.h>
int main(int argc, const char * argv[]) {
FILE* fp = fopen("/Users/jamesgoldstein/CS50/CS50Week4/CS50Recovery/CS50Recovery/CS50Recovery/card.raw", "rb");
char output[256];
if (fp == NULL)
{
printf("Bad input\n");
return 1;
}
for (int i = 1; fread(output, sizeof(output), 1, fp) != NULL; i++)
{
printf("%s\n", output);
}
fclose(fp);
return 0;
}
Output is partially correct (here's a snippet of the beginning):
bit.ly/18gECvy
\377\330\377\340
\221\241\26145\301\321\341 "#&23DE\3616BFRTUe\202CVbdfrtv\222\242
'u\204\206\226\262\302\3227\205\246\266\342GSc\224\225\245\265\305\306\325\326Wgs\244\346(w\345\362\366\207\264\304ǃ\223\227\2678H\247\250\343\344\365\377\304
=\311\345\264\352\354 7\222\315\306\324+\342\364\273\274\205$z\262\313g-\343wl\306\375My:}\242o\210\377
3(\266l\356\307T饢"2\377
\267\212ǑP\2218 \344
Actual card.raw file snippet of beginning
bit.ly/18gECvy ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿Vˇƒ
ˇƒÖ
!1AQa$%qÅë°±45¡—· "#&23DEÒ6BFRTUeÇCVbdfrtví¢
I think you should open the .raw file in the mode "rb".
Then use fread()
From the presence of the string "JFIF" in the first line of the file card.raw ("bit.ly/18gECvy ˇÿˇ‡JFIFHHˇ€Cˇ€Cˇ¿Vˇƒ") it seems like card.raw is a JPEG image format file that had the bit.ly URL inserted at its beginning.
You are going to see weird/special characters in this case because it is not a usual text file at all.
Also, as davmac pointed out, the way you are using fgets isn't appropriate even if you were dealing with an actual text file. When dealing with plain text files in C, the best way is to read the entire file at once instead of line by line, assuming sufficient memory is available:
size_t f_len, f_actualread;
char *buffer = NULL;
fseek(file, 0, SEEK_END)
f_len = ftell(fp);
rewind(fp);
buffer = malloc(f_len + 1);
if(buffer == NULL)
{
puts("malloc failed");
return;
}
f_actualread = fread(buffer, 1, f_len, file);
buffer[f_actualread] = 0;
printf("%s\n", output);
free(buffer);
buffer = NULL;
This way, you don't need to worry about line lengths or anything like that.
You should probably use fread rather than fgets, since the latter is really designed for reading text files, and this is clearly not a text file.
Your updated code in fact does have the very problem I originally wrote about (but have since retracted), since you are now using fread rather than fgets:
for (int i = 1; fread(output, sizeof(output), 1, fp) != NULL; i++)
{
printf("%s\n", output);
}
I.e. you are printing the output buffer as if it were a null-terminated string, when in fact it is not. Better to use fwrite to STDOUT.
However, I think the essence of the problem here is trying to display arbitrary bytes (which don't actually represent a character string) to the terminal. The terminal may interpret some byte sequences as commands which affect what you see. Also, textEdit may determine that the file is in some character encoding and decode characters accordingly.
Now I have no idea what the '\' and numbers are called (what do I search for to read more?)
They look like octal escape sequences to me.
why it's printing that instead of the characters (unicode?)
It's nothing to do with unicode. Maybe it's your terminal emulator deciding that those characters are unprintable, and so replacing them with an escape sequence.
In short, I think that your method (comparing visually what you see in a text editor with what you see on the terminal) is flawed. The code you have to read from the file looks correct; I'd suggest proceeding with the exercise and checking results then, or if you really want to be sure, look at the file using a hex editor, and have your program output the byte values it reads (as numbers) - and compare those with what you see in the hex editor.

Proper way to get file size in C

I am working on an assignment in socket programming in which I have to send a file between sparc and linux machine. Before sending the file in char stream I have to get the file size and tell the client. Here are some of the ways I tried to get the size but I am not sure which one is the proper one.
For testing purpose, I created a file with content " test" (space + (string)test)
Method 1 - Using fseeko() and ftello()
This is a method I found on https://www.securecoding.cert.org/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
While the fssek() has a problem of "Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END), has undefined behavior for a binary stream", fseeko() is said to have tackled this problem but it only works on POSIX system (which is fine because the environment I am using is sparc and linux)
fd = open(file_path, O_RDONLY);
fp = fopen(file_path, "rb");
/* Ensure that the file is a regular file */
if ((fstat(fd, &st) != 0) || (!S_ISREG(st.st_mode))) {
/* Handle error */
}
if (fseeko(fp, 0 , SEEK_END) != 0) {
/* Handle error */
}
file_size = ftello(fp);
fseeko(fp, 0, SEEK_SET);
printf("file size %zu\n", file_size);
This method works fine and get the size correctly. However, it is limited to regular files only. I tried to google the term "regular file" but I still not quite understand it thoroughly. And I do not know if this function is reliable for my project.
Method 2 - Using strlen()
Since the max. size of a file in my project is 4MB, so I can just calloc a 4MB buffer. After that, the file is read into the buffer, and I tried to use the strlen to get the file size (or more correctly the length of content). Since strlen() is portable, can I use this method instead? The code snippet is like this
fp = fopen(file_path, "rb");
fread(file_buffer, 1024*1024*4, 1, fp);
printf("strlen %zu\n", strlen(file_buffer));
This method works too and returns
strlen 8
However, I couldn't see any similar approach on the Internet using this method. So I am thinking maybe I have missed something or there are some limitations of this approach which I haven't realized.
Regular file means that it is nothing special like device, socket, pipe etc. but "normal" file.
It seems that by your task description before sending you must retrieve size of normal file.
So your way is right:
FILE* fp = fopen(...);
if(fp) {
fseek(fp, 0 , SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0 , SEEK_SET);// needed for next read from beginning of file
...
fclose(fp);
}
but you can do it without opening file:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct stat buffer;
int status;
status = stat("path to file", &buffer);
if(status == 0) {
// size of file is in member buffer.st_size;
}
OP can do it the easy way as "max. size of a file in my project is 4MB".
Rather than using strlen(), use the return value from fread(). stlen() stops on the first null character, so may report too small a value. #Sami Kuhmonen Also we do not know the data read contains any null character, so it may not be a string. Append a null character (and allocate +1) if code needs to use data as a string. But in that case, I'd expect the file needed to be open in text mode.
Note that many OS's do not even use allocated memory until it is written.
Why is malloc not "using up" the memory on my computer?
fp = fopen(file_path, "rb");
if (fp) {
#define MAX_FILE_SIZE 4194304
char *buf = malloc(MAX_FILE_SIZE);
if (buf) {
size_t numread = fread(buf, sizeof *buf, MAX_FILE_SIZE, fp);
// shrink if desired
char *tmp = realloc(buf, numread);
if (tmp) {
buf = tmp;
// Use buf with numread char
}
free(buf);
}
fclose(fp);
}
Note: Reading the entire file into memory may not be the best idea to begin with.

How to read data from a string in memory using file functions

I have a function which reads data from a file (i.e. it is passed a FILE*).
What I want to accomplish is to use that function for reading the data from a string, i.e. I would like to treat the data in the string as if it were data in a physical file (e.g. using fgets, fseek etc.), so in effect, a memory file.
I tried to associate the data string with a /dev/null (NUL) file via setvbuf (similar to what I read in this stackoverflow question), but either I did it wrong or that's not how it's done.
Can somebody help me achieving this in C, preferably in a portable fashion (actually, I don't mind using OS-specific functions/ifdefs as long as it works and it's not /too/ complicated).
Edit:
#include <stdio.h>
#include <string.h>
#define NULL_L "/dev/null"
#define NULL_W "NUL"
FILE* open_memfile(char *pc_file_as_string) {
FILE *f = fopen(NULL_L, "rb");
int i_size = strlen(pc_file_as_string);
setvbuf(f, pc_file_as_string, _IOLBF, i_size);
return f;
}
int main()
{
char c_line[100] = "";
char pc_file_as_string[] = "line1 asdf\nline2 fsa afds\n\nline4";
FILE *f = open_memfile(pc_file_as_string);
int i = 4;
while (i > 0) {
fgets(c_line, 100, f);
if (c_line == NULL)
break;
else
puts(c_line);
i--;
}
fclose(f);
return 0;
}
On linux you would use fmemopen.
On Windows there is no fmemopen function available.
You can create and map an in memory (paging) file with the CreateFileMapping / MapViewOfFile functions, but this will return you a Windows file handle, which is unusable for your purposes.
Use sscanf and other string processing functions provided in stdio.

reading from a binary file in C

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.

Resources