Copying all file contents into a char array with fread - c

I'm trying to copy the contents of a file, specifically a PDF file into a character array so that I can send it over the network.
I'm using the fopen with fread for this.
//Get the file path
getFilePath();
//Open the file
fopen_s(&fp, filePath, "r");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
rewind(fp);
//allocate memory
buffer = (char*)malloc(sizeof(char)*size);
int charsTransferred = fread(buffer, 1, size, fp);
fclose(fp);
free(buffer);
I have charsTransferred to see how many characters were transferred over by fread. Using size I can tell how many characters should have been moved over, but obviously I'm not getting that many back. Does anyone know what the issue here could be?

There may be a problem in the part of your code you didn't show.
This works:
#include <stdio.h>
#include <stdlib.h>
void main()
{
FILE *fp;
if (fopen_s(&fp, "somepdfile.pdf", "rb"))
{
printf("Failed to open file\n");
exit(1);
}
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
char *buffer = (char*)malloc(sizeof(char)*size);
if (!buffer)
{
printf("Failed to malloc\n");
exit(1);
}
int charsTransferred = fread(buffer, 1, size, fp);
printf("charsTransferred = %d, size = %d\n", charsTransferred, size);
fclose(fp);
free(buffer);
}

Firstly you need to open in binary mode if a PDF, which I believe is a binary format. Then the seek end / ftell method tends to fail for very large files, as well as for text files (which have suppressed characters physically on the disk). There isn't a pure ANSI C way of statting a file, but the function stat() is widely avialable, and gives you file size.

Related

Getting excess characters with fread() in C

Okay, so I have tried to read a whole file with fread(), and I can do it successfully, but the longer the file, the more the excess characters I get on the output.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
FILE* fpointer = fopen("test.txt", "r");
char* wholeFile;
long int fileSize;
if (fpointer == NULL) return 0;
fseek(fpointer, 0, SEEK_END);
fileSize = ftell(fpointer);
rewind(fpointer);
printf("fileSize == %ld\n", fileSize);
wholeFile = (char*)malloc(fileSize+1, sizeof(char));
if (wholeFile == NULL) return 1;
fread(wholeFile, sizeof(char), fileSize, fpointer);
fclose(fpointer);
wholeFile[fileSize] = '\0';
printf("This is whole file:\n\n%s", wholeFile);
free(wholeFile);
return 0;
}
If the file looks like this:
This is cool file.
I get this as output:
This is cool file.²²²²
And if the file is like this:
This
is
cool
file.
I get this as the output:
This
is
cool
file.═══²²²²
Any idea where I'm wrong?
EDIT: Edited code according to comments.
You need to allocate one more than the size of the file and set the last position in the buffer to 0.
C expects character arrays to be null terminated.
Use "rb" to open the file in binary mode. This will ensure you get a reliable count of bytes in the file from Windows.
FILE* fpointer = fopen("test.txt", "rb");
wholeFile = (char*)malloc(fileSize + 1);
wholeFile[fileSize] = '\0';

Reverse file text

I'm trying to make a program that uses fgets to take the text from a preexisting file, invert it and then write it to another file. This is the code I've written so far:
#include <stdio.h>
#include <string.h>
int main()
{
int c, d;
FILE *file1, *file2;
char string [100], *begin, *end, temp;
file1 = fopen("StartingFile.txt", "rt");
if (file1 == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fgets(string, 100, file1);
fclose (file1);
begin = string;
end = begin + strlen(string) - 1;
while (end > begin)
{
temp = *begin;
*begin = *end;
*end = temp;
++begin;
--end;
}
file2 = fopen("FinalFile.txt", "wt");
fprintf (file2, "%s", string);
fclose (file2);
printf ("%s\n", string);
return 0;
}
It works fine if the text in the preexisting file is all in one line, but if it has more than one line, only the first one is inverted and written to the new file. I think that fgets can only read one line, so I think I'll have to use a loop, but I'm having trouble implementing it. Can someone give me a hand? Thanks in advance!
To read each line separately from file use fgets in while loop as below,
while(fgets(string, sizeof(string), file1) != NULL)
{
...
}
fclose(file1);
Inside the loop operate on each line to reverse it.
Your code has quite a few logical errors in it. I would recommend using other f* methods instead.
If you want an easy solution, open the file, determine its length, create two buffers of the size of the file, fill the first buffer with the file's contents and then do a loop to copy the reverse to the other buffer, then write that buffer back. Roughly that would look like this:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *file;
file = fopen("StartingFile.txt", "rt");
if (file == NULL)
{
printf ("Error - Couldn't open file\n");
return (-1);
}
fseek(file, 0, SEEK_END); // move file pointer to end of file
long size = ftell(file); // file pointer position == character count in file
fseek(file, 0, SEEK_SET); // move back to beginning of file
char* buffer = malloc(size * sizeof(char));
fread(buffer, sizeof(char), size, file) // read file contents to buffer
for(long i = 0; i < size/2; ++i)
{
buffer[i] = buffer[size-i-1];
}
fseek(file, 0, SEEK_SET); // The fread set the file pointer to the end so we need to put it to the front again.
fwrite(buffer, sizeof(char), size, file); // Write reverted content
delete buffer;
fclose (file);
}
I haven't tested it and it may contain a few errors since I haven't programmed in C for some time. The only reason to still be programming in C anyways is efficiency and if you want your program to be efficient, the two buffer solution isn't the best either. At least not in terms of memory usage.
I highly recommend getting familiar with all the functions available in C (stdio and so on) cplusplus.com is a great reference for that.
Regards, Xaser

copying contents of a text file in c

I want to read a text file and transfer it's contents to another text file in c, Here is my code:
char buffer[100];
FILE* rfile=fopen ("myfile.txt","r+");
if(rfile==NULL)
{
printf("couldn't open File...\n");
}
fseek(rfile, 0, SEEK_END);
size_t file_size = ftell(rfile);
printf("%d\n",file_size);
fseek(rfile,0,SEEK_SET);
fread(buffer,file_size,1,rfile);
FILE* pFile = fopen ( "newfile.txt" , "w+" );
fwrite (buffer , 1 ,sizeof(buffer) , pFile );
fclose(rfile);
fclose (pFile);
return 0;
}
the problem that I am facing is the appearence of unnecessary data in the receiving file,
I tried the fwrite function with both "sizeof(buffer)" and "file_size",In the first case it is displaying greater number of useless characters while in the second case the number of useless characters is only 3,I would really appreciate if someone pointed out my mistake and told me how to get rid of these useless characters...
Your are writing all the content of buffer (100 char) in the receiving file. You need to write the exact amount of data read.
fwrite(buffer, 1, file_size, pFile)
Adding more checks for your code:
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 100
int main(void) {
char buffer[BUFFER_SIZE];
size_t file_size;
size_t ret;
FILE* rfile = fopen("input.txt","r+");
if(rfile==NULL)
{
printf("couldn't open File \n");
return 0;
}
fseek(rfile, 0, SEEK_END);
file_size = ftell(rfile);
fseek(rfile,0,SEEK_SET);
printf("File size: %d\n",file_size);
if(!file_size) {
printf("Warring! Empty input file!\n");
} else if( file_size >= BUFFER_SIZE ){
printf("Warring! File size greater than %d. File will be truncated!\n", BUFFER_SIZE);
file_size = BUFFER_SIZE;
}
ret = fread(buffer, sizeof(char), file_size, rfile);
if(file_size != ret) {
printf("I/O error\n");
} else {
FILE* pFile = fopen ( "newfile.txt" , "w+" );
if(!pFile) {
printf("Can not create the destination file\n");
} else {
ret = fwrite (buffer , 1 ,file_size , pFile );
if(ret != file_size) {
printf("Writing error!");
}
fclose (pFile);
}
}
fclose(rfile);
return 0;
}
You need to check the return values from all calls to fseek(), fread() and fwrite(), even fclose().
In your example, you have fread() read 1 block which is 100 bytes long. It's often a better idea to reverse the parameters, like this: ret = fread(buffer,1,file_size,rfile). The ret value will then show how many bytes it could read, instead of just saying it could not read a full block.
Here is an implementation of an (almost) general purpose file copy function:
void fcopy(FILE *f_src, FILE *f_dst)
{
char buffer[BUFSIZ];
size_t n;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
{
if (fwrite(buffer, sizeof(char), n, f_dst) != n)
err_syserr("write failed\n");
}
}
Given an open file stream f_src to read and another open file stream f_dst to write, it copies (the remainder of) the file associated with f_src to the file associated with f_dst. It does so moderately economically, using the buffer size BUFSIZ from <stdio.h>. Often, you will find that bigger buffers (such as 4 KiB or 4096 bytes, even 64 KiB or 65536 bytes) will give better performance. Going larger than 64 KiB seldom yields much benefit, but YMMV.
The code above calls an error reporting function (err_syserr()) which is assumed not to return. That's why I designated it 'almost general purpose'. The function could be upgraded to return an int value, 0 on success and EOF on a failure:
enum { BUFFER_SIZE = 4096 };
int fcopy(FILE *f_src, FILE *f_dst)
{
char buffer[BUFFER_SIZE];
size_t n;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f_src)) > 0)
{
if (fwrite(buffer, sizeof(char), n, f_dst) != n)
return EOF; // Optionally report write failure
}
if (ferror(f_src) || ferror(f_dst))
return EOF; // Optionally report I/O error detected
return 0;
}
Note that this design doesn't open or close files; it works with open file streams. You can write a wrapper that opens the files and calls the copy function (or includes the copy code into the function). Also note that to change the buffer size, I simply changed the buffer definition; I didn't change the main copy code. Also note that any 'function call overhead' in calling this little function is completely swamped by the overhead of the I/O operations themselves.
Note ftell returns a long, not a size_t. Shouldn't matter here, though. ftell itself is not necessarily a byte-offset, though. The standard requires it only to be an acceptable argument to fseek. You might get a better result from fgetpos, but it has the same portability issue from the lack of specification by the standard. (Confession: I didn't check the standard itself; got all this from the manpages.)
The more robust way to get a file-size is with fstat.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd>
struct stat stat_buf;
if (fstat(filename, &buf) == -1)
perror(filename), exit(EXIT_FAILURE);
file_size = statbuf.st_size;
I think the parameters you passed in the fwrite are not in right sequence.
To me it should be like that-
fwrite(buffer,SIZE,1,pFile)
as the syntax of fwrite is
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
The function fwrite() writes nmemb elements of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by ptr.
So change the sequence and try again.

Can't read file in linux [duplicate]

This question already has an answer here:
/proc/[pid]/cmdline file size
(1 answer)
Closed 10 years ago.
I was trying to read the proc/stat file but I couldn't though I am sure that my code is working because I tried reading another files and it worked perfectly ..
here is the code:
#include <stdio.h>
#include <stdlib.h> // for the malloc
int main (int argc,char *argv[])
{
char *file_name = "/proc/stat";
char *contents;
FILE *file;
int filesize = 0;
file = fopen(file_name, "r");
if(file != NULL)
{
//get the file size
fseek(file, 0, SEEK_END);
filesize = ftell(file);
fseek(file, 0, SEEK_SET);
printf("the file size is: %d\n", filesize);
contents = (char *)malloc(filesize+1); // allocate memory
fread(contents, filesize,1,file);
contents[filesize]=0;
fclose(file);
printf("File has been read: %s \n", contents);
}
else
{
printf("the file name %s doesn't exits", file_name);
}
return 0;
}
You cannot determine the size of special files in /proc and you can't seek to the end in them. Their contents are generated on-the-fly. With these files, you have to keep reading until you encounter an EOF. You cannot know how much data you're going to get beforehand.
So keep reading data in, say, 512 byte blocks, until you get a short read. Then you'll know that you can't read any more data.
Edit:
It just occurred to me that I answered this in a past question already: /proc/[pid]/cmdline file size

Buffer Failure in C

I am try to write a buffer so I can remove a lot of null "00" characters in a file. The characters are useless and are completely random. They are wreaking havoc on the searcher in the program. The code below compiles but just seems to hang when a file is passed to it. Any suggestions will be helpful.
void ReadFile(char *name)
{
FILE *dbg;
char *buffer;
unsigned long fileLen;
//Open file
dbg = fopen(dbg, "w+");
if (!dbg)
{
fprintf(stderr, "Unable to open file %s", name);
return;
}
//Get file length
fseek(dbg, 0, SEEK_END);
fileLen = ftell(dbg);
fseek(dbg, 0, SEEK_SET);
//Allocate memory
buffer = (char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(dbg);
return;
}
//Read file contents into buffer
fread(buffer, fileLen, 1, dbg);
for(i = fileLen-1; i >= 0 && buffer[i] == 0; i--);
i++;
if (i > 0)
{
fwrite(buffer, 1, i, dbg);
}
fclose(dbg);
//Do what ever with buffer
free(buffer);
}
Change
dbg = fopen(dbg, "w+");
to
dbg = fopen(name, "w+");
Also, if you want to read the file, change it then write it, you shouldn't open it with "w+". You should first open the file with "r", read from it, do whatever change you want, then fclose it, then again open it but this time with "w" so that you write over it. After you have opened it in "w"rite mode, you can write the modified buffer back into the file.
You opened a file for writing and then you try to read from it.
Check the return value of fread and all the other calls.

Resources