Copy textfile using fwrite, ending up with trash? C - c

Iam trying to copy a text file to a new file. I was thinking that if I want to do it smart, I just copy everything binary so the copy will be identical to the first. However I'am ending up with weird character in the new document.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[])
{
FILE * fporgi, * fpcopy;
if((fporgi = fopen(argv[1], "rb")) == NULL){
//Error checking
fprintf(stdout, "Error occurred trying to open file :%s", argv[1]);
exit(EXIT_FAILURE);
}
if((fpcopy = fopen(argv[2], "wb")) == NULL){
fprintf(stdout, "Error occurred trying to open file :%s", argv[2]);
exit(EXIT_FAILURE);
}
long bytes;
fseek(fporgi, 0L, SEEK_END);
bytes = ftell(fporgi);
fprintf(stdout, "\n%ld\n", bytes);
unsigned char buffer[bytes];
fprintf(stdout, "\n%u\n", sizeof(buffer));
fread(buffer, sizeof(buffer), 1, fporgi);
fwrite(buffer, sizeof(buffer), 1, fpcopy);
fclose(fporgi);
fclose(fpcopy);
return 0;
}
Example if the original file contains "hej svej" the new file will have : "(œÌuR0#NUL"

You need to seek back to the start of the file after reading the length:
fseek(fporgi, 0L, SEEK_END);
bytes = ftell(fporgi);
fprintf(stdout, "\n%ld\n", bytes);
fseek(fporgi, 0L, SEEK_SET);

Related

fread and fwrite result file size are different

I am writing a program in Visual Studio.
I copied a file using fread and fwrite.
The output file size is bigger then input file.
Can you explain the reason?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main()
{
char *buffer;
int fsize;
FILE *fp = fopen("test.txt", "r");
FILE *ofp = fopen("out.txt", "w");
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
buffer = (char *)malloc(fsize);
memset(buffer, 0, fsize); // buffer를 0으로 초기화
fseek(fp, 0, SEEK_SET);
fread(buffer, fsize, 1, fp);
fwrite(buffer, fsize, 1, ofp);
fclose(fp);
fclose(ofp);
free(buffer);
}
You open the files in text mode, which on the Windows operating system using Visual Studio involves non trivial translation phases, including end of line conversion. If your files have binary contents, such as executable, image and document files, end of line conversion replaces '\n' bytes with CR LF pairs, thereby increasing the output size.
You can avoid this issue by opening the files in binary mode with "rb" and "wb" mode strings.
Also note that a stream must be open in binary mode for ftell() to reliably return the file size, assuming the file supports seeking and is not larger than LONG_MAX which is only 2GB on Windows. Using stat to retrieve the file size from the OS is a better approach for POSIX systems. Copying the file one block at a time is also more reliable: it works for streams that do not support seeking and allows for copying files larger than available memory.
Here is a modified version with error checking:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const char *inputfile = "test.txt";
const char *outputfile = "out.txt";
FILE *fp = fopen(inputfile, "rb");
if (fp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", inputfile, strerror(errno);
return 1;
}
FILE *ofp = fopen(outputfile, "wb");
if (ofp == NULL) {
fprintf(stderr, "cannot open %s: %s\n", outputfile, strerror(errno);
return 1;
}
if (fseek(fp, 0, SEEK_END)) {
fprintf(stderr, "%s: cannot seek to the end of file: %s\n",
inputfile, strerror(errno);
return 1;
}
size_t fsize = ftell(fp);
char *buffer = calloc(fsize, 1);
if (buffer == NULL) {
fprintf(stderr, "cannot allocate %zu bytes: %s\n",
fsize, strerror(errno);
return 1;
}
rewind(fp);
size_t nread = fread(buffer, fsize, 1, fp);
if (nread != fsize) {
fprintf(stderr, "%s: read %zu bytes, file size is %zu bytes\n".
inputfile, nread, fsize);
}
size_t nwritten = fwrite(buffer, nread, 1, ofp);
if (nwritten != nread) {
fprintf(stderr, "%s: wrote %zu bytes, write size is %zu bytes\n".
outputfile, nwritten, nread);
}
fclose(fp);
if (fclose(ofp)) {
fprintf(stderr, "%s: error closing file: %s\n".
outputfile, strerror(errno));
}
free(buffer);
return 0;
}

Reading a pdf file with fread in C does not end up as expected

I am trying to read from a pdf file and write into another file where I run to the problem.
In the while loop, fread reads only 589 bytes which is expected to be 1024 for the first time.
In the second loop, fread reads 0 bytes.
I am sure that the pdf file is beyond 1024 bytes.
Here is a similar problem. The phenomenon is the same. But I do not use strlen() which causes that problem.
So how can I resolve the problem?
My code is here:
#include <stdio.h>
#define MAXLINE 1024
int main() {
FILE *fp;
int read_len;
char buf2[MAXLINE];
FILE *fp2;
fp2 = fopen("test.pdf", "w");
if ((fp = fopen("LearningSpark.pdf", "r")) == NULL) {
printf("Open file failed\n");
}
while ((read_len = fread(buf2, sizeof(char), MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, sizeof(char), read_len, fp2);
if (write_length < read_len) {
printf("File write failed\n");
break;
}
}
return 0;
}
fopen(filename, "r") is system dependent. See this post on what may happen to the data you read if you are on Windows, for example. Basically it is related to how certain characters are translated on different systems in text mode, ie., \n is "End-of-Line" on Unix-type systems, but on Windows it is \r\n.
Important: On Windows, ASCII char 27 will result in End-Of-File, if reading in text mode, "r", causing the fread() to terminate prematurely.
To read a binary file, use the "rb" specifier. Similarly for "w", as mentioned here, you should use "wb" to write binary data.
Binary files such as pdf files must be open in binary mode to prevent end of line translation and other text mode handling on legacy systems such as Windows.
Also note that you should abort when fopen() fails and you should close the files.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXLINE 1024
int main() {
char buf2[MAXLINE];
int read_len;
FILE *fp;
FILE *fp2;
if ((fp = fopen("LearningSpark.pdf", "rb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "LearningSpark.pdf", strerror(errno));
return 1;
}
if ((fp2 = fopen("test.pdf", "wb")) == NULL) {
fprintf(stderr, "Open file failed for %s: %s\n", "test.pdf", strerror(errno));
fclose(fp);
return 1;
}
while ((read_len = fread(buf2, 1, MAXLINE, fp)) > 0) {
int write_length = fwrite(buf2, 1, read_len, fp2);
if (write_length < read_len) {
fprintf(stderr, "File write failed: %s\n", strerror(errno));
break;
}
}
fclose(fp);
fclose(fp2);
return 0;
}

memcpy returns junk data when copying from character buffer

I'm attempting to read 4 bytes from the start of a character buffer, but I'm having an issue. memcpy is returning junk.
buffer contains the contents of the file. Using breakpoints I see that the file starts with 41 53 45 46 or ASEF in ASCII. This is the file signature for an Adobe Swatch File.
But when I copy those 4 bytes from a character buffer, to a 4 byte array signature, I get random data.
Any idea what I'm doing wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main(int argc, char **argv)
{
errno_t err = NULL;
FILE *fptr = NULL;
long fileSize = 0;
unsigned char* buffer;
int i, bytesRead;
char signature[4] = { 0 };
err = fopen_s(&fptr, argv[1], "rb");
if (err || fptr == NULL) {
fprintf(stderr, "Could not open file: %s\n", argv[1]);
return 1;
}
// Get filesize
fseek(fptr, 0, SEEK_END);
fileSize = ftell(fptr);
rewind(fptr);
// Allocate memory to store file contents
buffer = malloc(fileSize);
if (buffer == NULL) {
fprintf(stderr, "Could not allocate %i bytes of memory\n", fileSize);
return 1;
}
// Read file contents into buffer
bytesRead = fread(buffer, 1, fileSize, fptr);
if (bytesRead == 0) {
fprintf(stderr, "Failed to read bytes from file: %s\n", argv[1]);
return 1;
}
// Read and check signature
memcpy(signature, &buffer, 4);
fclose(fptr);
return 0;
}
This line is wrong:
memcpy(signature, &buffer, 4);
You want to copy the data in your buffer, not the value of the buffer pointer itself. That means you want:
memcpy(signature, buffer, 4);

Storing .raw File Data as a Pointer Using C

I am attempting to read a '.raw' file which stores the contents of an image that was taken on a camera using C. I would like to store these contents into a uint16_t *.
In the following code I attempt to store this data into a pointer, using fread(), and then write this data into a test file, using fwrite(), to check if my data was correct.
However, when I write the file back it is completely black when I check it.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define MAX_ROW 2560
#define MAX_COL 2160
int main()
{
char filename[32] = "image1.raw";
FILE * image_raw = fopen(filename, "rb");
fseek(image_raw, 0, 2);
long filesize = ftell(image_raw);
/*READ IMAGE DATA*/
uint16_t * image_data_ptr;
image_data_ptr = (uint16_t *)malloc(sizeof(uint16_t)*MAX_ROW*MAX_COL);
fread(image_data_ptr, sizeof(uint16_t), filesize, image_raw);
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp;
fp = fopen("TEST.raw", "w");
fwrite(image_data_ptr, sizeof(uint16_t), filesize, fp);
fclose(fp);
return 0;
}
There are multiple issues with your code:
lack of error handling.
not seeking the input file back to offset 0 after seeking it to get its size. Consider using stat() or equivalent to get the file size without having to seek the file at all.
not dividing filesize by sizeof(uint16_t) when reading from the input file, or writing to the output file. filesize is expressed in bytes, but fread/fwrite are expressed in number of items of a given size instead, and your items are not 1 byte in size.
not opening the output file in binary mode.
leaking the buffer you allocate.
With that said, try something more like this instead:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
char filename[32] = "image1.raw";
FILE *image_raw = fopen(filename, "rb");
if (!image_raw) {
fprintf(stderr, "Can't open input file\n");
return -1;
}
if (fseek(image_raw, 0, SEEK_END) != 0) {
fprintf(stderr, "Can't seek input file\n");
fclose(image_raw);
return -1;
}
long filesize = ftell(image_raw);
if (filesize == -1L) {
fprintf(stderr, "Can't get input file size\n");
fclose(image_raw);
return -1;
}
rewind(image_raw);
long numSamples = filesize / sizeof(uint16_t);
/*READ IMAGE DATA*/
uint16_t *image_data_ptr = (uint16_t*) malloc(filesize);
if (!image_data_ptr) {
fprintf(stderr, "Can't allocate memory\n");
fclose(image_raw);
return -1;
}
size_t numRead = fread(image_data_ptr, sizeof(uint16_t), numSamples, image_raw);
if (numRead != numSamples) {
fprintf(stderr, "Can't read samples from file\n");
free(image_data_ptr);
fclose(image_raw);
return -1;
}
fclose(image_raw);
/*TEST WRITING THE SAME DATA BACK INTO TEST RAW FILE*/
FILE *fp = fopen("TEST.raw", "wb");
if (!fp) {
fprintf(stderr, "Can't open output file\n");
free(image_data_ptr);
return -1;
}
if (fwrite(image_data_ptr, sizeof(uint16_t), numSamples, fp) != numSamples) {
fprintf(stderr, "Can't write to output file\n");
fclose(fp);
free(image_data_ptr);
return -1;
}
fclose(fp);
free(image_data_ptr);
return 0;
}
You have already a great answer and useful comments
anyway, consider that if you want to iterate over your file, loaded in memory as a whole, as an array of unsigned words:
if the file size could be odd what to do at the last byte/word
you may read the file as a whole in a single call, after having the file size determined
fstat() is the normal way to get the file size
get the file name from the command line as an argument is much more flexible than recompile the program or change the file name in order to use the program
The code below does just that:
uses image.raw as a default for the file name, but allowing you to enter the file name on the command line
uses fstat() to get the file size
uses a single fread() call to read the entire file as a single record
A test using the original program file as input:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 20/07/2021 17:40 1067 main.c
PS > gcc -Wall -o tst main.c
PS > ./tst main.c
File is "main.c". Size is 1067 bytes
File "main.c" loaded in memory.
PS > ./tst xys
File is "xys". Could not open: No such file or directory
The C example
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char**argv)
{
const char* default_file = "image.raw";
char f_name[256];
if (argc < 2)
strcpy(f_name, default_file);
else
strcpy(f_name, argv[1]);
FILE* F = fopen(f_name, "rb");
if (F == NULL)
{
printf("File is \"%s\". ", f_name);
perror("Could not open");
return -1;
}
struct stat info;
fstat(_fileno(F),&info);
printf("File is \"%s\". Size is %lu bytes\n", f_name, info.st_size);
uint16_t* image = malloc(info.st_size);
if (image == NULL)
{ perror("malloc() error");
return -2;
};
if (fread(image, info.st_size, 1, F) != 1)
{ perror("read error");
free(image);
return -3;
};
// use 'image'
printf("File \"%s\" loaded in memory.\n", f_name);
free(image);
fclose(F);
return 0;
}

How does FILE stream buffer work?

I understand fopen() opens file and creates a buffer for read and write operations on that file. fopen() returns a pointer for that buffer.
So my question is, in the code below, the _copy function body has a temp matrix to transfer between the fread() and fwrite(). why cant I directly transfer from buffer to buffer?
/* example: copyfile.exe xxxxx.txt zzzzzz.txt */
#include <stdio.h>
#include <stdlib.h>
#define BUFF 8192
void _copy(FILE *source, FILE *destination);
int main(int argc, char *argv[])
{
FILE *fp1, *fp2; // fp1 source file pointer// fp2 copied file pointer
if (argc !=3 ) //command line must have 3 arguments
{
fprintf(stderr, "Usage: %s (source file) (copy file)\n", argv[0][0]);
exit(EXIT_FAILURE);
}
if ((fp1 = fopen(argv[1], "rb")) == NULL) //Opening source file
{
fprintf(stderr, "Could not open %s\n",argv[1]);
exit(EXIT_FAILURE);
}
if((fp2 = fopen(argv[2], "ab+")) == NULL) //Opening destination file
{
fprintf(stderr, "could not create %s \n",argv[2]);
exit(EXIT_FAILURE);
}
if( setvbuf(fp1,NULL, _IOFBF, BUFF) != 0) //Setting buffer for source file
{
fputs("Can't create output buffer\n", stderr);
exit(EXIT_FAILURE);
}
if( setvbuf(fp2,NULL, _IOFBF, BUFF) != 0) //Setting buffer for destination file
{
fputs("Can't create input buffer\n", stderr);
exit(EXIT_FAILURE);
}
_copy(fp1, fp2);
if (ferror(fp1)!=0)
fprintf(stderr, "Error reading file %s\n", argv[1]);
if(ferror(fp2)!=0)
fprintf(stderr, "Error writing file %s\n",argv[2]);
printf("Done coping %s (source) to %s (destination) \n",argv[1], argv[2]);
fclose(fp1);
fclose(fp2);
return (0);
}
void _copy(FILE *source, FILE *destination)
{
size_t bytes;
static char temp[BUFF];
while((bytes = fread(temp,sizeof(char),BUFF,source))>0)
fwrite(temp,sizeof(char),bytes,destination);
}
You cannot use the underlying buffer from a FILE * in another FILE *. As you were told in comment, FILE * is an opaque pointer. But you can avoid the overhead of copying data between buffers by forcing both files in non buffered mode:
setbuf(fp, NULL); // cause the stream to be unbuffered

Resources