I'm trying to understand how to read and write in C. Would this store entries from the binary file into the buffer until the end of file.
unsigned char *buffer = (char*) malloc (sizeof(char) * SIZE);
FILE *file = fopen(FILEPATH, "rb");
if(file == NULL){
//error
} else {
while(!feof(file)){
fread(&buffer, SIZE*sizeof(char), 1, file);
// Print out buffer (should be different everytime assume I have different numbers in the file)
}
}
Or would I have to use fseek somewhere there?
Vice-versa to write something to a document would this work? Thanks
unsigned char *buffer = (char*) malloc (sizeof(char) * SIZE);
FILE *file = fopen(FILEPATH, "wb");
for(int i=0; i<SIZE; i++){
// put something into buffer based on i
fwrite(&buffer, SIZE*sizeof(char), 1, file);
}
No, that would probably crash. :)
You're taking the address of buffer, which is already a pointer: this is wrong. Just pass buffer directly to fread(). The value of buffer and &buffer are only the same when buffer is an array; not when it's allocated on the heap like your is.
Don't use feof(), rely on the return value of fread().
Don't cast the return value of malloc() in C.
Don't scale allocations by sizeof (char), that's always 1 so it adds nothing.
Related
I am trying to compare 2 texts from files byte by byte using memcmp, after I read both of them into memory, one file into a buffer(char* or char[], tried both). the problem is, the file I read into a buffer have a lot of 0 bytes, which makes him stop at the first 0 byte thinking it is a null terminating zero, which makes a segmentation fault. how can I make the function keep compare bytes even so there are 0 bytes?
I already tried to check if the buffer is full or not, I printed it byte by byte and it showed all of the bytes including the 0 bytes. when I print it completely using printf("%s", buffer) I get only the first byte(the second byte is 0 byte).
void detect_virus(char *buffer, unsigned int size){
link* l = (link*) malloc(sizeof(link));
load(l);
unsigned int location = 0;
while(l != NULL){
location = 0;
while(location < size - l->vir->SigSize){
int isVirus = memcmp(buffer + location, l->vir->sig, l->vir->SigSize);
if(isVirus == 0)
printf("%d, %s, %d\n", location, l->vir->virusName, l->vir->SigSize);
location++;
}
}
free(l);
}
void detect(link* list){
char filename[50];
fgets(filename, 50, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "rb");
char* buffer = (char*) malloc(10000);
fseek(file, 0, SEEK_END);
unsigned int size = ftell(file);
fseek(file, 0, SEEK_SET);
fread(buffer, 1, size, file);
detect_virus(buffer, size);
fclose(file);
}
I get a segmentation fault at the first time the memcmp function is called, instead of fully compare the texts. any ideas how to fix that?
edit
code for load function:
void load(link* list){
printf("Enter Viruses file name: \n");
char* filename = (char*) malloc(100);
fgets(filename, 100, stdin);
sscanf(filename, "%s", filename);
FILE* file = fopen(filename, "r");
while(!feof(file)){
short length = 0;
fread(&length, 2, 1, file);
if(length == 0)
break;
struct virus* v = (struct virus*)malloc(length);
fseek(file, -2, SEEK_CUR);
fread(v, length, 1, file);
v->SigSize = v->SigSize - 18;
list_append(list, v);
}
list = list->nextVirus;
free(filename);
fclose(file);
}
as a note, I tested the function before and it worked.
edit
I found out the problem, thank you all!
Per 7.21.6.7 The sscanf function, paragraph 2 of the C standard (bolding mine):
The sscanf function is equivalent to fscanf, except that input is obtained from a string (specified by the argument s) rather than from a stream. Reaching the end of the string is equivalent to encountering end-of-file for the fscanf function. If copying takes place between objects that overlap, the behavior is undefined.
Note the bolded portion.
In your code:
sscanf(filename, "%s", filename);
the filename array certainly overlaps with the filename array, thus invoking undefined behavior.
Remove that line of code.
You also need to add error checking, especially checking that the return from fopen() is not NULL.
I have a function which should store content of a file to pointer of pointer - content. When I am trying to check the result of fwrite function - it returns nothing to writn. What am I doing wrong here? Did I allocate memory correctly (if I want to copy the whole file)?
bool load(FILE* file, BYTE** content, size_t* length)
{
int len = 0, writn = 0;
fseek(file, 0, SEEK_END);
*length = len = ftell(file);
rewind(file);
*content = (char) malloc((len + 1) * sizeof(char)); //(len + 1) * sizeof(char)
writn = fwrite(*content, len + 1, 1, file);
return true;
}
You probably opened the file for reading "r" mode and fwrite() will write into the file, not read. If this is the case fwrite() will fail of course.
Perhaps you simply need
// Use long int for `length' to avoid a problem with `ftell()'
// read the documentation
bool load(FILE* file, BYTE **content, long int *length)
{
fseek(file, 0, SEEK_END);
*length = ftell(file);
rewind(file);
if (*length == -1)
return false;
*content = malloc(*length + 1);
if (*content == NULL)
return false;
if (fread(*content, 1, *length, file) != *length) {
free(*content);
*content = NULL;
return false;
}
(*content)[*length] = '\0';
return true;
}
You also, try to "read" more data than available, since you get the file length and still try to read 1 more byte.
What I see this function do is:
determine the size of the file;
allocate a chunk of memory that size;
write that chunk to the file.
This assumes that file is opened for reading and writing. The fseek seeks to the end of the file (a read operation); following the rewind the chunk is written (write operation). If the file is only opened for writing, then fseek will probably fail, so your size will be zero. If the file is only open for reading, then your fwrite will fail. In addition, tou write uninitialized data to the file (the allocated memory has not been ininitialized).
Is this what it is supposed to do?
FILE* inFile = fopen(inF, "rb");
if (inFile == NULL) {
printf("Invalid input!\n");
exit(EXIT_FAILURE);
}
char* bigBuffer;
char* nextChar = (char*) malloc(sizeof(char));
unsigned long i = 0;
unsigned long j;
while ((j = fread(nextChar, sizeof(char), 1, inFile)) == 1) {
i += j;
}
bigBuffer = malloc(i * sizeof(char));
fread(bigBuffer, sizeof(char), i, inFile);
fclose(inFile);
printf("%s\n", outF);
FILE* outFile = fopen(outF, "wb");
//if (outFile == NULL)
//printf("null\n");
j = fwrite(bigBuffer, sizeof(char), i, outFile);
printf("%lu\n", j);
fclose(outFile);
free (bigBuffer);
free (nextChar);
I'm trying to write a binary file using fopen in wb mode. After running my program, a file of the proper name is made in the proper place, but I just can't open it or read it. When I try to open it, a message pops up saying "Can't open...." In addition, the name of the file itself isn't formatted properly in Finder (I'm on a Mac). The name is elevated and cut off a little. It definitely looks like something is wrong with the file. I tried just making a regular file using fopen in w mode, and that worked beautifully. So I'm pretty sure I'm just doing something wrong when it comes to writing binary files using wb mode. Can anyone help? Thanks.
The main problem:
you didn't seek to the beginning of the file before reading, so your call to fread to read the entire file will fail
Change:
bigBuffer = malloc(i * sizeof(char));
fread(bigBuffer, sizeof(char), i, inFile);
to:
bigBuffer = malloc(i); // allocate buffer
rewind(inFile); // reset file pointer to start of file
fread(bigBuffer, 1, i, inFile); // read entire file
Additional notes:
sizeof(char) is 1 by definition, and therefore redundant
you should not cast the result of malloc in C
you should add error checking to any call that might fail, especially I/O calls
malloc-ing a single char is inefficient - just use a local variable
reading a file one char at a time to determine its length is very inefficient
The file with the opening in wb truncated to 0 length. Use for simultaneous read / write mode or addition mode rb +, a.
I'm writing a wrapper to help me in my future projects (I finished C book), and want to copy a file without using fgetc. Here's my code, it doesn't work:
int CopyFile(char* filename, char* dest)
{
FILE* fp, *fout;
fp = fopen(filename,"rb");
//fout = fopen(dest, "wb");
if(fp == NULL)
{
return -1;
}
/*while((c = fgetc(fp)) != EOF)
{
fputc(c,fout);
}*/
long size = GetFileSize(fp);
printf("%lu", size);
char* file = malloc(size);
fread(file, size, 1, fp);
//fclose(fp);
fout = fopen(dest, "wb");
fwrite(file, size, 1, fout);
fclose(fp);
fclose(fout);
return 0;
}
I even open the files with a hexeditor and they aren't similar. What am I doing wrong?
The problem is in the GetFileSize function, where you move the file-pointer to the end, but you never rewind to the beginning again.
That means your fread function call will not actually read anything, as the pointer already is at the end of the file. So what's written is the contents of the allocated memory, which is indeterminate (and will be seemingly random).
If you checked what fread returned, you would have seen this immediately.
Let this be a lesson on always checking the return values of functions which can fail in one way or the other.
I have a text file named test.txt
I want to write a C program that can read this file and print the content to the console (assume the file contains only ASCII text).
I don't know how to get the size of my string variable. Like this:
char str[999];
FILE * file;
file = fopen( "test.txt" , "r");
if (file) {
while (fscanf(file, "%s", str)!=EOF)
printf("%s",str);
fclose(file);
}
The size 999 doesn't work because the string returned by fscanf can be larger than that. How can I solve this?
The simplest way is to read a character, and print it right after reading:
int c;
FILE *file;
file = fopen("test.txt", "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
c is int above, since EOF is a negative number, and a plain char may be unsigned.
If you want to read the file in chunks, but without dynamic memory allocation, you can do:
#define CHUNK 1024 /* read 1024 bytes at a time */
char buf[CHUNK];
FILE *file;
size_t nread;
file = fopen("test.txt", "r");
if (file) {
while ((nread = fread(buf, 1, sizeof buf, file)) > 0)
fwrite(buf, 1, nread, stdout);
if (ferror(file)) {
/* deal with error */
}
fclose(file);
}
The second method above is essentially how you will read a file with a dynamically allocated array:
char *buf = malloc(chunk);
if (buf == NULL) {
/* deal with malloc() failure */
}
/* otherwise do this. Note 'chunk' instead of 'sizeof buf' */
while ((nread = fread(buf, 1, chunk, file)) > 0) {
/* as above */
}
Your method of fscanf() with %s as format loses information about whitespace in the file, so it is not exactly copying a file to stdout.
There are plenty of good answers here about reading it in chunks, I'm just gonna show you a little trick that reads all the content at once to a buffer and prints it.
I'm not saying it's better. It's not, and as Ricardo sometimes it can be bad, but I find it's a nice solution for the simple cases.
I sprinkled it with comments because there's a lot going on.
#include <stdio.h>
#include <stdlib.h>
char* ReadFile(char *filename)
{
char *buffer = NULL;
int string_size, read_size;
FILE *handler = fopen(filename, "r");
if (handler)
{
// Seek the last byte of the file
fseek(handler, 0, SEEK_END);
// Offset from the first to the last byte, or in other words, filesize
string_size = ftell(handler);
// go back to the start of the file
rewind(handler);
// Allocate a string that can hold it all
buffer = (char*) malloc(sizeof(char) * (string_size + 1) );
// Read it all in one operation
read_size = fread(buffer, sizeof(char), string_size, handler);
// fread doesn't set it so put a \0 in the last position
// and buffer is now officially a string
buffer[string_size] = '\0';
if (string_size != read_size)
{
// Something went wrong, throw away the memory and set
// the buffer to NULL
free(buffer);
buffer = NULL;
}
// Always remember to close the file.
fclose(handler);
}
return buffer;
}
int main()
{
char *string = ReadFile("yourfile.txt");
if (string)
{
puts(string);
free(string);
}
return 0;
}
Let me know if it's useful or you could learn something from it :)
Instead just directly print the characters onto the console because the text file maybe very large and you may require a lot of memory.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f;
char c;
f=fopen("test.txt","rt");
while((c=fgetc(f))!=EOF){
printf("%c",c);
}
fclose(f);
return 0;
}
Use "read()" instead o fscanf:
ssize_t read(int fildes, void *buf, size_t nbyte);
DESCRIPTION
The read() function shall attempt to read nbyte bytes from the file associated with the open file descriptor, fildes, into the buffer pointed to by buf.
Here is an example:
http://cmagical.blogspot.com/2010/01/c-programming-on-unix-implementing-cat.html
Working part from that example:
f=open(argv[1],O_RDONLY);
while ((n=read(f,l,80)) > 0)
write(1,l,n);
An alternate approach is to use getc/putc to read/write 1 char at a time. A lot less efficient. A good example: http://www.eskimo.com/~scs/cclass/notes/sx13.html
You can use fgets and limit the size of the read string.
char *fgets(char *str, int num, FILE *stream);
You can change the while in your code to:
while (fgets(str, 100, file)) /* printf("%s", str) */;
Two approaches leap to mind.
First, don't use scanf. Use fgets() which takes a parameter to specify the buffer size, and which leaves any newline characters intact. A simple loop over the file that prints the buffer content should naturally copy the file intact.
Second, use fread() or the common C idiom with fgetc(). These would process the file in fixed-size chunks or a single character at a time.
If you must process the file over white-space delimited strings, then use either fgets or fread to read the file, and something like strtok to split the buffer at whitespace. Don't forget to handle the transition from one buffer to the next, since your target strings are likely to span the buffer boundary.
If there is an external requirement to use scanf to do the reading, then limit the length of the string it might read with a precision field in the format specifier. In your case with a 999 byte buffer, then say scanf("%998s", str); which will write at most 998 characters to the buffer leaving room for the nul terminator. If single strings longer than your buffer are allowed, then you would have to process them in two pieces. If not, you have an opportunity to tell the user about an error politely without creating a buffer overflow security hole.
Regardless, always validate the return values and think about how to handle bad, malicious, or just malformed input.
You can use getline() to read your text file without worrying about large lines:
getline() reads an entire line from stream, storing the address of the buffer containing the text into *lineptr. The buffer is null-terminated and includes the newline character, if one was found.
If *lineptr is set to NULL before the call, then getline() will allocate a buffer for storing the line. This buffer should be freed by the user program even if getline() failed.
bool read_file(const char *filename)
{
FILE *file = fopen(filename, "r");
if (!file)
return false;
char *line = NULL;
size_t linesize = 0;
while (getline(&line, &linesize, file) != -1) {
printf("%s", line);
free(line);
}
free(line);
fclose(file);
return true;
}
You can use it like this:
int main(void)
{
if (!read_file("test.txt")) {
printf("Error reading file\n");
exit(EXIT_FAILURE);
}
}
I use this version
char* read(const char* filename){
FILE* f = fopen(filename, "rb");
if (f == NULL){
exit(1);
}
fseek(f, 0L, SEEK_END);
long size = ftell(f)+1;
fclose(f);
f = fopen(filename, "r");
void* content = memset(malloc(size), '\0', size);
fread(content, 1, size-1, f);
fclose(f);
return (char*) content;
}
You could read the entire file with dynamic memory allocation, but isn't a good idea because if the file is too big, you could have memory problems.
So is better read short parts of the file and print it.
#include <stdio.h>
#define BLOCK 1000
int main() {
FILE *f=fopen("teste.txt","r");
int size;
char buffer[BLOCK];
// ...
while((size=fread(buffer,BLOCK,sizeof(char),f)>0))
fwrite(buffer,size,sizeof(char),stdout);
fclose(f);
// ...
return 0;
}