ttoshiro
ttoshiro

Reputation: 526

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.

Upvotes: 0

Views: 517

Answers (3)

ubaid shaikh
ubaid shaikh

Reputation: 453

#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

Upvotes: 1

William Pursell
William Pursell

Reputation: 212268

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;                                                                  
}  

Upvotes: 1

Serge Ballesta
Serge Ballesta

Reputation: 148965

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;
}

Upvotes: 1

Related Questions