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';
Related
I made a simple script to rewrite one file contents into another.
Here's code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char filename[1024];
scanf("%s", &filename);
// printf("Filename: '%s'\n", filename);
int bytesToModify; scanf("%d", &bytesToModify);
FILE *fp;
fp = fopen(filename, "r");
fseek(fp, 0, SEEK_END);
int fSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
printf("%d\n", fSize);
char *buf = malloc(fSize*sizeof(char));
for (int i = 0; i < fSize; i++) {
buf[i] = getc(fp);
}
fclose(fp);
FILE *fo;
fo = fopen("out_file.txt", "w");
for (int i = 0; i < fSize; i++) {
fwrite(&buf[i], 1, 1, fo);
}
fclose(fo);
return 0;
}
Even on small file like this I can see the artifact. Cyrillic sybmol 'я' is coming in the end of file.
If I'll try to rewrite executable file, i get this:
99% of file just turned to these symbols. What is wrong with my code?
I'm using CodeBlocks with GCC Compiler, version 10.1.0.
My Operation System is Windows 10.
Thanks for your help.
You did not open the file in binary mode: "rb" and "wb". Therefore, fgetc will turn all \r\n to a single \n.
For each line terminator there is one character less read. Yet you attempt to read nevertheless, and fgetc will return EOF (and fgetc returns an int, not char). As EOF has value -1 on Windows, when written to file converted to unsigned char this results in Я in the encoding you're using in Notepad (most likely Windows-1251).
Furthermore, since you're using fwrite, then you could similarly use fread. And no need to read, write the characters one at a time, just use
char *buf = malloc(fSize);
int bytesRead = fread(buf, 1, fSize, fp);
fclose(fp);
and
int bytesWritten = fwrite(buf, 1, bytesRead, fo);
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.
I'm trying to read the hex values from an image file using C. In Linux, this code works fine, but with Windows it reads only the first 334 bytes and I don't understand why.
The code to read the file is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
void readHexFile(char* path) {
FILE *fp;
if ((fp = fopen (path, "r")) != NULL) {
struct stat st;
stat(path, &st);
int i;
int ch;
for (i = 0; i < st.st_size; i++) {
ch = fgetc(fp);
printf("%x ", ch);
}
fclose(fp);
}
else {
return NULL;
}
}
st.st_size comes from <sys/stat.h> package and contains the right value (the size, in bytes, of the image file)
This image show what my program outputs, and the actual binary content of the file it is reading:
As you see after the sequence of 17, 18, 19 there is also hex values but my program prints ffffffff repeatedly.
You opened the file in a text mode, and not as binary. Different platforms may behave differently.
In this case, Microsoft Windows decided that this plain text file ends at the first occurrence of Ctrl+Z (0x1A), and returns EOF for all fgetc afterwards.
Explicitly state that you want to open the file as binary:
fp = fopen ("yourfile", "rb");
and the problem goes away.
I think your loop should look like this:
int ch;
while (!feof(fp)) {
ch = fgetc(fp);
printf("%x ", ch);
}
It's completely unclear to me why you are using st.st_size here.
On Windows, the character 0x1A (Ctrl+Z) is the EOF character for text mode; see this question.
If you're reading from a binary file like a JPEG, you should do so with first opening the file as binary (fopen mode "rb"), then fread into a pre-allocated buffer, the size of which you would determine with ftell with the file pointer at the end of the file:
size_t i, len;
char *buffer = NULL;
fp = fopen(argv[1], "rb");
if(!fp)
// handle error
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
buffer = malloc(len + 1);
if(!buffer)
// handle error
fread(buffer, 1, len, fp);
for(i = 0; i < len; i++)
{
printf("%.2X ", buffer[i]);
}
free(buffer);
buffer = NULL;
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'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