How to output simultaneously onto console and a te

2019-09-06 18:09发布

问题:

The following creates and prints a table of random numbers onto the console. How can I modify the createtxt function I made, so that the output on the console is generated into a text file at the same time.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


FILE* createtxt(char* fnam){
    FILE* ofp;
    ofp = fopen(fnam, "w");
    if (ofp == NULL) {
        printf("Cannot open output file %s\n", fnam);
        exit(EXIT_FAILURE);
}

void closetxt(FILE* ofp){
    fclose(ofp);
}

int main (void){
    printf("Table of random numbers for drawing geometric shapes in different     colours, sizes and opacities\n");

int rn = 0;
unsigned int seed = (unsigned int)time(NULL);
srand(seed);

int k = 0;
printf("shape#\tRSCE\tx\ty\twidth\theight\tred\tgreen\tblue\tgreen\topacity\n");
while (k < NO_SHAPES){
    printf("%6d", k);
    rn = rand() % SHAPE_RANGE;
    printf( "\t%4d",rn);
    rn = rand() % X_RANGE;
    printf("\t%d",rn);
    rn = rand() % Y_RANGE;
    printf("\t%d",rn);
    rn = rand() % WIDTH_RANGE;
    printf("\t%5d",rn);
    rn = rand() % HEIGHT_RANGE;
    printf("\t%6d",rn);
    rn = rand() % RED_RANGE;
    printf("\t%3d",rn);
    rn = rand() % GREEN_RANGE;
    printf("\t%5d",rn);
    rn = rand() % BLUE_RANGE;
    printf("\t%4d",rn);
    rn = rand() % OPACITY_RANGE;
    printf("\t%.1f\n",rn/100.0);
    k++;
    }

    FILE* ofp = createtxt("myrandom.txt")
    closetxt(ofp);

    return EXIT_SUCCESS;
}

回答1:

This version is Done in-line with the printf() statements: (see below for in createtxt()
open the file before the printf statements:

FILE* ofp = createtxt("myrandom.txt");
char buf[20];


rn = rand() % SHAPE_RANGE;
sprintf(buf, "\t%4d",rn);//use sprintf() to put information into buf
printf(buf);             //output to stdout
fputs(buf, ofp );        //output to file
/// repeat lines for X_RANGE, Y_RANGE, etc.

fclose(ofp);     

If from within createtxt:

Change the prototype to int createtxt(char *fnam, char *buf)

rather than using

sprintf(buf, "\t%4d",rn);//use sprintf() to put information into buf
printf(buf);             //output to stdout  

Use:
//create and initialize a bigger buffer.

char buf[1000];  //or some other appropriately sized buffer

buf[0]=0;  //set NULL to first position of buf
//then, between all the printf statements in main, call this:      
sprintf(buf, %s\t%4d", buf, rn);//will concatenate all bufs until end  

Then pass buf as argument to createtxt().

void createtxt(char* fnam, char *buf)
{
    FILE* ofp;
    ofp = fopen(fnam, "w");
    if (ofp == NULL) {
        printf("Cannot open output file %s\n", fnam);
        exit(EXIT_FAILURE);
    {
    fputs(buf, ofp);
    fclose(ofp);
}


回答2:

I'd probably think about creating an ffprintf() function:

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>

extern int ffprintf(FILE *fp1, FILE *fp2, char const *fmt, ...);

int ffprintf(FILE *fp1, FILE *fp2, char const *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    int rc1 = vfprintf(fp1, fmt, args);
    va_end(args);
    va_start(args, fmt);
    int rc2 = vfprintf(fp2, fmt, args);
    va_end(args);
    assert(rc1 == rc2);
    return rc1;
}

Then the main code can be:

FILE* ofp = createtxt("myrandom.txt")

ffprintf(stdout, ofp, "shape#\tRSCE\tx\ty\twidth\theight\tred\tgreen\tblue\tgreen\topacity\n");
while (k < NO_SHAPES)
{
    ffprintf(stdout, ofp, "%6d", k);
    rn = rand() % SHAPE_RANGE;
    ffprintf(stdout, ofp, "\t%4d", rn);
    ...
}

closetxt(ofp);

If you don't feel comfortable using variable length argument lists, you can write a simpler version of the function:

extern int ffprintf(FILE *fp1, FILE *fp2, char const *fmt, int value);

int ffprintf(FILE *fp1, FILE *fp2, char const *fmt, value)
{
    int rc1 = fprintf(fp1, fmt, value);
    int rc2 = vfprintf(fp2, fmt, value);
    assert(rc1 == rc2);
    return rc1;
}

Now you have to write the header twice:

char const header[] =
     "shape#\tRSCE\tx\ty\twidth\theight\tred\tgreen\tblue\tgreen\topacity\n";

fputs(header, stdout);
fputs(header, ofp);

Most of the rest can stay unchanged, but the opacity (a float) needs to be handled specially as well as the header line.

Clearly, the function name is changeable if you don't like that it encroaches on the standard names for function. If you go with the simpler approach, the function name should be changed to something like ffprint_int() since it only prints one int at a time.

The use of assert() is lazy, but it does ensure that both print operations succeeded (or both failed). If you're worried about it, change that assertion into something like:

if (rc2 < rc1)
    rc1 = rc2;

This will return the smaller of the two values; if one is -1 (complete failure), that's the value that will be returned. Of course, since the code I wrote ignores the return value from ffprintf(), just as your code ignored the return value from printf(), this is a nuance that will go largely unnoticed.