0

my C program does 3 things:

  1. reads from a text file
  2. converts all letters into upper-case
  3. prints the converted text into the console.

Here are how many times I'm opening and closing those 2 files in my program:
Original => 1 for "r"
New => 2 first for "w+" and last for "r"

Is there a better way to write to a file and read from it without opening and closing a multiple times? (even though I only opened and closed twice, I wanna build a good practice)

#include <stdio.h>
#include <ctype.h>

int main()
{
    const char ORIGINAL[] = "challenge2.txt";
    FILE *fp = NULL;
    FILE *fpNew = NULL;
    char ch, ch2;

    ///////////// open the original txt file to read /////////////
    fp = fopen(ORIGINAL, "r");

    if (fp == NULL)
    {
        perror("Error opening the file");
        return (-1);
    }

    ///////////// create and write on a new file /////////////
    fpNew = fopen("challenge2_copy.txt", "w+");

    printf("\n============== Original text ==============\n");
    while ((ch = fgetc(fp)) != EOF)
    {
        printf("%c", ch);
        ch = toupper(ch);
        fputc(ch, fpNew);
    }

    fclose(fp);
    fp = NULL;

    fclose(fpNew);
    fpNew = NULL;

    ///////////// call the new file to print the converted text /////////////
    fpNew = fopen("challenge2_copy.txt", "r");

    if (fpNew == NULL)
    {
        perror("Error opening the file");
        return (-1);
    }
    
    printf("\n============== Converted to Uppercase ==============\n");
    while ((ch2 = fgetc(fpNew)) != EOF)
    {
        printf("%c", ch2);
    }

    fclose(fpNew);
    fpNew = NULL;

    return 0;
}

Here's the console output:

============== Original text ==============
hello I AM JACK
I AM TESTING lowerCASE
GONNA convert THIS into
UPPERcase
i hope THIS works
============== Converted to Uppercase ==============
HELLO I AM JACK
I AM TESTING LOWERCASE
GONNA CONVERT THIS INTO
UPPERCASE
I HOPE THIS WORKS
mushjoon
  • 11
  • 3
  • If you want to examine the file you created, it is *safer* to close it and reopen. It also means it will be available for multi-use. There is no need to open as "+" in this case. – Weather Vane Feb 28 '22 at 08:38
  • 5
    **MUST CHANGE**: `int ch, ch2;`, otherwise you have no guarantee you can identify `EOF`. – pmg Feb 28 '22 at 08:39
  • 1
    Look in to `fseek()` & `rewind()` calls. – जलजनक Feb 28 '22 at 08:41
  • You could write to the file and to stdout in the same loop. THen you would not need to read the output file. – Bodo Feb 28 '22 at 09:15

1 Answers1

0

Good practices, performance, dangers.

  • MS Visual Studio suggest using fopen_s as good practise :)
  • Sometimes reopening file sometimes makes code more clear to read in big projects.
  • As for performance, it will take some time for processor to make new FILE instance and fill it with all file properties.
  • There can also be some interrupts eg. after releasing ownership for a while cloud sync. tools may want to back up newly created file and will block accessing it for other apps. (your program).

Performance solution.

So as to reuse a FILE instance you need only to jump into different place in FILE buffer (eg. start of the file). You can achieve it with fsetpos or fseek functions from stdio.h.
https://www.cplusplus.com/reference/cstdio/fsetpos/
https://www.cplusplus.com/reference/cstdio/fseek/

Example FILE instance reusage.

/* fsetpos example */
#include <stdio.h>

int main ()
{
  FILE * pFile; fpos_t position;
  #define buffSize 1024 //1KB
  char s[buffSize];
  
  //Write
  pFile = fopen ("myfile.txt","w+");
  fgetpos (pFile, &position);
  fputs ("That is a sample",pFile);
  
  //Reuse for reading
  fsetpos (pFile, &position);
  puts (fgets(s,buffSize, pFile));

  //Next reuse for reading
  fsetpos (pFile, &position);
  puts (fgets(s,buffSize, pFile));
  
  fclose (pFile);
  return 0;
}

The above code produces the following result:

That is a sample
That is a sample
Sir
  • 337
  • 1
  • 7
  • 1
    *MS Visual Studio suggest using `fopen_s` as good practise* [Don't](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm): "Microsoft Visual Studio implements an early version of the APIs. However, the implementation is incomplete and conforms neither to C11 nor to the original TR 24731-1. ... As a result of the numerous deviations from the specification the Microsoft implementation cannot be considered conforming or portable." Nor is it any "safer". – Andrew Henle Feb 28 '22 at 12:06