difference in copying a .exe file and text file in c - c

I wrote the following code to copy the text file to another:
FILE *fpr, *fpw;
int ch;
fpr = fopen("M.txt","r");
fpw = fopen("P.txt","w");
if(fpr == NULL)
printf("File open failed!");
else
{
while(1)
{
ch = fgetc(fpr);
if(ch == EOF)
break;
fputc(ch, fpw);
}
fclose(fpr);
fclose(fpw);
printf("Successfully copied!");
}
It worked perfectly. Then I changed int ch to char ch it also worked for me. But when i used the following code for copying a .exe file, file copying is not working correctly.
FILE *fpr, *fpw;
char ch;
fpr = fopen("M.exe","rb");
fpw = fopen("P.exe","wb");
if(fpr == NULL)
printf("File open failed!");
else
{
while(1)
{
ch = fgetc(fpr);
if(ch == EOF)
break;
fputc(ch, fpw);
}
fclose(fpr);
fclose(fpw);
printf("Successfully copied!");
}
I changed char ch to int ch then it's working fine! Why this happens with binary files not with text file? What happens when char ch was used in the case of binary?
Please help...
Thank you for your feed back in advance.

It's because EOF is probably 0 or 255 for char which can show up in middle of binary file but can't in text file(that's why only text file work for char). However EOF is -1 for int which can't show up in middle of a file no matter what(only 0-255 inclusive can).

Since fgetc() can return the integer corresponding to any character plus a distinct value EOF, you cannot store its result in a char and then test for EOF reliably. You must use an int as you did originally.

fgetc() and fputc() are designed for handling textual data, not binary data. Use fread() and fwrite() instead.
FILE *fpr, *fpw;
unsigned char b[1024];
bool ok = false;
fpr = fopen("M.exe","rb");
if (fpr == NULL)
printf("File open M.exe failed!");
else
{
fpw = fopen("P.exe","wb");
if (fpw == NULL)
printf("File open P.exe failed!");
else
{
int read;
while(1)
{
read = fread(b, 1, 1024, fpr);
if (read < 1)
{
if (read == 0)
ok = true;
break;
}
if (fwrite(b, read, 1, fpw) != 1)
break;
}
fclose(fpw);
}
fclose(fpr);
}
if (ok)
printf("Successfully copied!");

Related

I can't print output in another text file

int main()
{
char ch;
int word_count = 0, in_word = 0;
char file_name[MAX_LEN];
/* Pointer for both the file*/
FILE *fpr, *fpw;
/* Opening file INPUT.txt in “r” mode for reading */
start:
printf("Enter a file name: ");
scanf("%s", file_name);
fpr = fopen(file_name, "r");
/* Ensure INPUT.txt opened successfully*/
if (fpr == NULL)
{
system("cls");
printf("Could not open the file %s\n", file_name);
goto start;
}
while ((ch = fgetc(fpr)) != EOF) {
{
printf("%c",ch);
}
if(ch == ' ' || ch == '\t' || ch == '\0' || ch == '\n') {
if (in_word) {
in_word = 0;
word_count++;
}
} else {
in_word = 1;
}
}
printf("In the file %s:\n", file_name);
printf("Number of words: %d.\n", word_count);
/* Opening file OUTPUT.txt in “w” mode for writing*/
fpw= fopen("OUTPUT.txt", "w");
/* Ensure OUTPUT.txt opened successfully*/
if (fpw == NULL)
{
puts("Output file cannot be opened");
}
/*Read & Write Logic*/
while ((ch = fgetc(fpr)) != EOF)
{
fputc(ch, fpw);
}
/* Closing both the files */
fclose(fpr);
fclose(fpw);
return 0;
}
Why is it not printing in the output.txt file? And how can I also print the words in the output file?
There must be a conflict between the while function before printing the input. Or maybe there is something reading before the output then having conflict with another one, when I remove the while function (count words) it shows the product in the output.
You read from fpr until you reach EOF, then try to read from it again.
You need to rewind the file to the beginning for the second fgetc() loop to produce anything.

How to convert a text file from DOS format to UNIX format

I am trying to make a program in C, that reads a text file and replace \r\n with \n to the same file converting the line ending from DOS to UNIX. I use fgetc and treat the file as a binary file. Thanks in advance.
#include <stdio.h>
int main()
{
FILE *fptr = fopen("textfile.txt", "rb+");
if (fptr == NULL)
{
printf("erro ficheiro \n");
return 0;
}
while((ch = fgetc(fptr)) != EOF) {
if(ch == '\r') {
fprintf(fptr,"%c", '\n');
} else {
fprintf(fptr,"%c", ch);
}
}
fclose(fptr);
}
If we assume the file uses a single byte character set, we just need to ignore all the '\r' characters when converting a text file form DOS to UNIX.
We also assume that the size of the file is less than the highest unsigned integer.
The reason we do these assumptions, is to keep the example short.
Be aware that the example below overwrites the original file, as you asked. Normally you shouldn't do this, as you can lose the contents of the original file, if an error occurs.
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
// Return a negative number on failure and 0 on success.
int main()
{
const char* filename = "textfile.txt";
// Get the file size. We assume the filesize is not bigger than UINT_MAX.
struct stat info;
if (stat(filename, &info) != 0)
return -1;
size_t filesize = (size_t)info.st_size;
// Allocate memory for reading the file
char* content = (char*)malloc(filesize);
if (content == NULL)
return -2;
// Open the file for reading
FILE* fptr = fopen(filename, "rb");
if (fptr == NULL)
return -3;
// Read the file and close it - we assume the filesize is not bigger than UINT_MAX.
size_t count = fread(content, filesize, 1, fptr);
fclose(fptr);
if (count != 1)
return -4;
// Remove all '\r' characters
size_t newsize = 0;
for (long i = 0; i < filesize; ++i) {
char ch = content[i];
if (ch != '\r') {
content[newsize] = ch;
++newsize;
}
}
// Test if we found any
if (newsize != filesize) {
// Open the file for writing and truncate it.
FILE* fptr = fopen(filename, "wb");
if (fptr == NULL)
return -5;
// Write the new output to the file. Note that if an error occurs,
// then we will lose the original contents of the file.
if (newsize > 0)
count = fwrite(content, newsize, 1, fptr);
fclose(fptr);
if (newsize > 0 && count != 1)
return -6;
}
// For a console application, we don't need to free the memory allocated
// with malloc(), but normally we should free it.
// Success
return 0;
} // main()
To only remove '\r' followed by '\n' replace the loop with this loop:
// Remove all '\r' characters followed by a '\n' character
size_t newsize = 0;
for (long i = 0; i < filesize; ++i) {
char ch = content[i];
char ch2 = (i < filesize - 1) ? content[i + 1] : 0;
if (ch == '\r' && ch2 == '\n') {
ch = '\n';
++i;
}
content[newsize++] = ch;
}

How to merge the contents of two files into a new file, appearing side by side by line?

I've been trying to merge the contents of two .txt files into a third .txt file that combines the output. All I know how to do (and all I have been able to find answers for), however, is to merge them by putting the contents of the first file first, and the second file second. However, I would prefer the output to list the first line of the first file, then the first line of the second file -- followed on a new line by the second line of the first file and the second line of the second file.
To make this clearer visually, the code is currently appearing as:
file1-line1
file1-line2
file1-line3
file2-line1
file2-line2
file2-line3
... When I'd like it to appear as:
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3
The code I have is very basic and executes the first example fine:
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
int ch;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
while ((ch = fgetc(pointer1)) != EOF)
fputc(ch, pointer3);
while ((ch = fgetc(pointer2)) != EOF)
fputc(ch, pointer3);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
Is there a way to output the described situation? I am aware that E0F refers to the end of a file, and is likely causing an issue. Is there a similar condition for an end of a line (like E0L)?
Edit: Changed char ch to int ch.
First, if you have a Unix-like system, the paste command already does that. Next as you want to process lines, you should use fgets. Here you have to loop over input files one line at a time, copy the lines to the output file without the newline, and add the new line after copying everything.
As the processing for both input files is the same, and as I am lazy, I wrote a function to only write it once. In the end code could be:
FILE *copyline(FILE *in, FILE *out) {
char line[256];
if (in != NULL) {
for (;;) { // loop if the line is larger that sizeof(line)
if (NULL == fgets(line, sizeof(line), in)) { // EOF on file1
fclose(in);
in = NULL;
break;
}
size_t end = strcspn(line, "\n");
if (end != 0) fwrite(line, 1, end, out); // smth to write
if (end != strlen(line)) break; // \n found: exit loop
}
}
return in;
}
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
const char sep[] = " "; // a separator between lines of both file
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
exit(0);
}
for (;;) {
pointer1 = copyline(pointer1, pointer3);
fwrite(sep, strlen(sep), 1, pointer3);
pointer2 = copyline(pointer2, pointer3);
if (pointer1 == NULL && pointer2 == NULL) break;
fputc('\n', pointer3); // if smth was written, add a newline
printf(".");
}
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer3);
return 0;
}
Here's one way to approach it:
#include <err.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
*mode == 'r' ? stdin : stdout;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}
int
main(int argc, char **argv)
{
if( argc < 3 ) {
printf("usage: %s file1 file2\n", basename(argv[0]));
}
FILE *pointer1 = xfopen(argv[1], "r");
FILE *pointer2 = xfopen(argv[2], "r");
FILE *current = pointer1;
int ch;
while( ( ch = fgetc(current)) != EOF ) {
if( ch == '\n' ) {
if( current == pointer1 ) {
int k;
current = pointer2;
if( (k = fgetc(current)) != EOF ) {
ungetc(k, current);
ch = ' ';
}
} else {
current = pointer1;
}
}
putchar(ch);
}
if( ferror(current) ) {
err(EXIT_FAILURE, "Error reading %s",
current == pointer1 ? argv[1] : argv[2]);
}
current = current == pointer1 ? pointer2 : pointer1;
while( (ch = fgetc(current)) != EOF) {
putchar(ch);
}
fclose(pointer1);
fclose(pointer2);
return 0;
}
#include <stdio.h>
int main()
{
FILE *pointer1 = fopen("file1.txt", "r");
FILE *pointer2 = fopen("file2.txt", "r");
FILE *pointer3 = fopen("combined.txt", "w");
char ch1, ch2;
if (pointer1 == NULL || pointer2 == NULL || pointer3 == NULL)
{
puts("Could not open files");
return 0;
}
do
{
char c1 = fgetc(pointer1);
char c2 = fgetc(pointer2);
if (feof(pointer1) || feof(pointer2))
break;
while(c1!='\n')
{
fputc(c1,pointer3);
c1=fgetc(pointer1);
if(feof(pointer1)) break;
}
fputc(' ',pointer3);
while(c2!='\n')
{
fputc(c2,pointer3);
c2=fgetc(pointer2);
if(feof(pointer2)) break;
}
fputc('\n',pointer3);
} while (1);
printf("Merged file1.txt and file2.txt into combined.txt");
fclose(pointer1);
fclose(pointer2);
fclose(pointer3);
return 0;
}
This works like you want.
Output: Combined file.txt
file1-line1 file2-line1
file1-line2 file2-line2
file1-line3 file2-line3

reading a file one character at a time with spaces

I'm trying to convert the case from a file and write into another. The file I'm trying to convert has spaces and a few lines. The converted form is written with no spaces and no line breaks. Does anyone know how I can alter my code, so that it includes the spaces and line breaks from the original file?
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(void)
{
FILE *fp1, *fp2;
fp1 = fopen("exercise2.txt", "r");
fp2 = fopen("exercise2_converted.txt", "w");
int singleline;
if (fp1 == NULL)
{
printf("Error opening fp1!\n");
return 0;
}
if (fp2 == NULL)
{
printf("Error opening fp2!\n");
fclose(fp1);
return 0;
}
do
{
singleline = fgetc(fp1);
if (islower(singleline))
{
singleline = toupper(singleline);
fputc(singleline, fp2);
}
else if (isupper(singleline))
{
singleline = tolower(singleline);
fputc(singleline, fp2);
}
} while (singleline != EOF);
fclose(fp1);
fclose(fp2);
return 0;
}
Overall beginner's solution:
...
do
{
singleline = fgetc(fp1);
if (singleline == EOF)
break; // end of file => game over quit loop immediately
// convert char if neessary
if (islower(singleline))
{
singleline = toupper(singleline);
}
else if (isupper(singleline))
{
singleline = tolower(singleline);
}
// output the char
fputc(singleline, fp2);
} while (1);
...
There are shorter solutions, but these are harder to read and to understand for beginners.

C program complies but screen on console remains black

I was writing a C program that would read and merge 3 files together (program not complete yet), however, as I was testing I realized the program compiles but the screen on the console remains blank!
Any help is appreciated, especially why is it blank?
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("test");
//open three files for merging
FILE *fp1 = fopen("american0.txt","r");
FILE *fp2 = fopen("american1.txt","r");
FILE *fp3 = fopen("american2.txt","r");
printf("test");
//open file to store the result
FILE *fpm = fopen("words.txt", "w");
//creating an array to save the files data
char c;
char mergedFile[50];
//checking to make sure files are being read
if(fp1 == NULL && fp2 == NULL && fp3 == NULL && fpm == NULL)
{
printf("Could not open one or all of the files.\n");
printf("Exiting program!");
exit(0);
}
printf("test");
//initializing counter values
//inserting data from file into an array
while ((c = fgetc(fp1)) != EOF)
{
fputc(c, mergedFile);
}
while ((c = fgetc(fp2)) != EOF)
{
fputc(c, mergedFile);
}
while ((c = fgetc(fp3)) != EOF)
{
fputc(c, mergedFile);
}
printf("%s",mergedFile[0]);
printf("test");
return 0;
}
Error --> fputc requires a file pointer as it's second argument rather than an array: int fputc ( int character, FILE * stream );
Points to be taken care of:
The size of array should be large enough to contain all the data from these files.
Take care of the format specifier and what it requires in a char array.
What if size of array is less than total size of all files? - Error handling
What if files to be read/written into are in some other directory?
Here is a minimal corrected version:
#include <stdio.h>
#include <stdlib.h>
#define MAX 1000 //ADDED NEW
int main()
{
//open three files for merging
FILE *fp1 = fopen("american0.txt","r");
FILE *fp2 = fopen("american1.txt","r");
FILE *fp3 = fopen("american2.txt","r");
//open file to store the result
FILE *fpm = fopen("words.txt", "w");
//creating an array to save the files data
int c;
int i=0;
char mergedFile[MAX]={0}; //MODIFIED & INITIALIZED
//checking to make sure files are being read
if(fp1 == NULL && fp2 == NULL && fp3 == NULL && fpm == NULL)
{
printf("Could not open one or all of the files.\n");
printf("Exiting program!");
exit(0);
}
//initializing counter values
//inserting data from file into an array
while (((c = fgetc(fp1)) != EOF)&&(i<MAX)) //MODIFIED
{
mergedFile[i++]=c; //MODIFIED
}
while (((c = fgetc(fp2)) != EOF)&&(i<MAX)) //MODIFIED
{
mergedFile[i++]=c; //MODIFIED
}
while (((c = fgetc(fp3)) != EOF)&&(i<MAX)) //MODIFIED
{
mergedFile[i++]=c; //MODIFIED
}
printf("%s",mergedFile); //MODIFIED
return 0;
}

Resources