3/25/14
Streams • In C, the term stream means any source of input or any destination for output. Input/Output • Accessing a stream is done through a file pointer, which has type . FILE * o A variable pointing to a file ⇒ FILE *fp; Based on slides from K. N. King and Dianna Xu fp Bryn Mawr College o The FILE type is declared in
Standard Streams and Redirection Standard Streams and Redirection •
Standard Streams and Redirection Text Files vs Binary Files • Input redirection and output redirection can be • • Output redirection: everything written to stdout '3' '2' '7' '6' '7' o Binary file: bytes don’t necessarily represent is put into a file. characters. • Writing error messages to stderr instead of • Groups of bytes might represent other types of data, stdout guarantees that they will appear on the such as integers and floating-point numbers. screen even when stdout has been redirected. • E.g., an executable C program. binary 01111111 11111111 1 3/25/14 Text Files vs Binary Files Text Files vs Binary Files • Text files have two characteristics that binary files • Text files may contain a special “end-of-file” don’t possess. marker. • Text files are divided into lines. Each line in a text o In Windows, the marker is '\x1a' (Ctrl-Z), but it file normally ends with one or two special is not required. characters. o Most other operating systems, including UNIX, o Windows: carriage-return character ('\x0d') have no special end-of-file character. followed by line-feed character ('\x0a') • In a binary file, there are no end-of-line or end-of- o UNIX and newer versions of Mac OS: line-feed file markers; all bytes are treated equally. character • In this lecture we cover text file I/O. o Older versions of Mac OS: carriage-return character Opening a File Opening a File • Opening a file for use as a stream requires a call of the • In Windows, be careful when the file name in a call of fopen function. fopen includes the \ character. • Prototype for fopen: • The call FILE *fopen(const char * filename, const char * mode); fopen("c:\project\test1.dat", "r") • filename is the name of the file to be opened. will fail, because \t is treated as a character escape. o may include information about the file’s location, such • One way to avoid the problem is to use \\ instead of \: as a drive specifier or path. fopen("c:\\project\\test1.dat", "r") • mode is a “mode string” that specifies what operations we intend to perform on the file. • An alternative is to use the / character instead of \: • Returns the null pointer NULL (zero) on error, i.e. fopen("c:/project/test1.dat", "r") trying to read a file that doesn’t exist. Opening a File Modes • fopen returns a file pointer that the program can • Factors that determine which mode string to pass to (and usually will) save in a variable: fopen: fp = fopen("in.dat", "r"); o Which operations are to be performed on the file /* opens in.dat for reading */ o Whether the file contains text or binary data • When it can’t open a file, fopen returns a null • Mode strings for text files: pointer. String Meaning "r" Open for reading "w" Open for writing (file need not exist) "a" Open for appending (file need not exist) "r+" Open for reading and writing, starting at beginning "w+" Open for reading and writing (truncate if file exists) "a+" Open for reading and writing (append if file exists) 2 3/25/14 Modes Closing a File • Special rules apply when a file is opened for both • The fclose function allows a program to close a reading and writing. file that it’s no longer using. o Can’t switch from reading to writing without first • The argument to fclose must be a file pointer calling a file-positioning function unless the reading obtained from a call of fopen or freopen. operation encountered the end of the file. • fclose returns zero if the file was closed o Can’t switch from writing to reading without either successfully. calling fflush or calling a file-positioning function. • Otherwise, it returns the error code EOF (a macro defined in Closing a File Closing a File • The outline of a program that opens a file for reading: • It’s not unusual to see the call of fopen combined #include int main(void) or the test against NULL: { FILE *fp; if ((fp = fopen(FILE_NAME, "r")) == NULL) … fp = fopen(FILE_NAME, "r"); if (fp == NULL) { printf("Can't open %s\n", FILE_NAME); exit(EXIT_FAILURE); } … fclose(fp); return 0; } Program: Checking Whether canopen.c a File Can Be Opened /* Checks whether a file can be opened for reading */ #include exists and can be opened for reading. int main(int argc, char *argv[]) { FILE *fp; • The user will give the program a file name to if (argc != 2) { check: printf("usage: canopen filename\n"); exit(EXIT_FAILURE); } canopen file if ((fp = fopen(argv[1], "r")) == NULL) { • The program will then print either file can be printf("%s can't be opened\n", argv[1]); exit(EXIT_FAILURE); } opened or file can't be opened. printf("%s can be opened\n", argv[1]); • If the user enters the wrong number of arguments fclose(fp); return 0; on the command line, the program will print the } message usage: canopen filename. 3 3/25/14 File Buffering Formatted I/O • It takes time to transfer the buffer contents to or • Reading – returns number of matches or EOF from disk, but one large “block move” is much int fscanf(FILE *fp, "...", variableList); faster than many tiny byte moves. • Writing – returns number of chars written • A call that flushes the buffer for the file associated int fprintf(FILE *fp, "...", with fp: variableList); fflush(fp); /* flushes buffer for fp */ • scanf is equivalent to fscanf with stdin • A call that flushes all output streams: • printf to fprintf with stdout fflush(NULL); /* flushes all buffers */ • fflush returns zero if it’s successful and EOF if an error occurs. The …printf Functions The …printf Functions • printf always writes to stdout, whereas • fprintf works with any output stream. fprintf writes to the stream indicated by its first • One of its most common uses is to write error argument: messages to stderr: printf("Total: %d\n", total); fprintf(stderr, "Error: data file can't be opened. /* writes to stdout */ \n"); fprintf(fp, "Total: %d\n", total); • Writing a message to stderr guarantees that it /* writes to fp */ will appear on the screen even if the user redirects • A call of printf is equivalent to a call of stdout. fprintf with stdout as the first argument. Examples of …printf Examples of …printf Conversion Specifications Conversion Specifications • Examples showing the effect of flags on the %d • Examples showing the effect of the minimum field conversion: width and precision on the %s conversion: Conversion Result of Applying Result of Applying Specification Conversion to 123 Conversion to –123 Result of Applying Result of Applying Conversion Conversion to Conversion to %8d •••••123 ••••-123 Specification "bogus" "buzzword" %-8d 123••••• -123•••• %+8d ••••+123 ••••-123 %6s •bogus buzzword % 8d •••••123 ••••-123 %-6s bogus• buzzword %08d 00000123 -0000123 %.4s bogu buzz %-+8d +123•••• -123•••• %6.4s ••bogu ••buzz %- 8d •123•••• -123•••• %-6.4s bogu•• buzz•• %+08d +0000123 -0000123 % 08d •0000123 -0000123 4 3/25/14 Examples of …printf Examples of …printf Conversion Specifications Conversion Specifications • The * character allows us to specify minimum field width • The %p conversion is used to print the value of a and/or precision as argument(s) after the format string. pointer: • A major advantage of is that it allows us to use a macro * printf("%p", (void *) ptr); to specify the width or precision: /* displays value of ptr */ printf("%*d", WIDTH, i); o The pointer is likely to be shown as an octal or • The width or precision can even be computed during hexadecimal number. program execution: printf("%*d", page_width / num_cols, i); • The %n conversion is used to find out how many • Calls of printf that produce the same output: characters have been printed so far by a call of printf("%6.4d", i); printf. printf("%*.4d", 6, i); o After the following call, the value of len will be 3: printf("%6.*d", 4, i); printf("%*.*d", 6, 4, i); printf("%d%n\n", 123, &len); The …scanf Functions The …scanf Functions • scanf always reads from stdin, whereas • The …scanf functions return the number of data fscanf reads from the stream indicated by its items that were read and assigned to objects. first argument: • They return EOF if no more input characters could scanf("%d%d", &i, &j); be read before any data items can be read. /* reads from stdin */ • Loops that test scanf’s return value are common. fscanf(fp, "%d%d", &i, &j); /* reads from fp */ • A loop that reads a series of integers one by one, stopping at the first sign of trouble: • A call of scanf is equivalent to a call of fscanf with as the first argument. while (scanf("%d", &i) == 1) { stdin … } …scanf Format Strings …scanf Format Strings • The format string represents a pattern that a … • The format string "ISBN %d-%d-%ld-%d" scanf function attempts to match as it reads specifies that the input will consist of: input. o the letters ISBN o If the input doesn’t match the format string, the o possibly some white-space characters function returns. o an integer o The input character that didn’t match is “pushed o the - character back” to be read in the future. o an integer (possibly preceded by white-space characters) o the - character o a long integer (possibly preceded by white-space characters) o the - character o an integer (possibly preceded by white-space characters) 5 3/25/14 scanf Examples scanf Examples • Examples that combine conversion specifications, white- • Examples showing the effect of assignment suppression and space characters, and non-white-space characters: specifying a field width: scanf Call Input Variables scanf Call Input Variables n = scanf("%d%d", &i, &j); 12•,•34¤ n: 1 n = scanf("%*d%d", &i); 12•34¤ n: 1 i: 12 i: 34 j: unchanged n = scanf("%*s%s", str); My•Fair•Lady¤ n: 1 n = scanf("%d,%d", &i, &j); 12•,•34¤ n: 1 str: "Fair" i: 12 n = scanf("%1d%2d%3d", 12345¤ n: 3 j: unchanged &i, &j, &k); i: 1 n = scanf("%d ,%d", &i, &j); 12•,•34¤ n: 2 j: 23 i: 12 k: 45 j: 34 n = scanf("%2d%2s%2d", 123456¤ n: 3 n = scanf("%d, %d", &i, &j); 12•,•34¤ n: 1 &i, str, &j); i: 12 i: 12 str: "34" j: unchanged j: 56 …scanf Conversion Specifications fscanf and fprintf • %[set] matches any sequence of characters in set (the • Reading – returns number of matches or EOF scanset) , where set can be any set of characters. • %[^set] matches any sequence of characters not in set. int fscanf(FILE *fp, "...", variableList); • Examples: • Writing – returns number of chars written %[abc] matches any string containing only a, b, and c. int fprintf(FILE *fp, "...", %[^abc] matches any string that doesn’t contain a, b, or c. variableList ); scanf Call Input Variables • scanf is equivalent to fscanf with stdin n = scanf("%[0123456789]", str); 123abc¤ n: 1 str: "123" • printf to fprintf with stdout n = scanf("%[0123456789]", str); abc123¤ n: 0 str: unchanged n = scanf("%[^0123456789]", str); abc123¤ n: 1 str: "abc” Character I/O Character I/O • Reading – returns char read or EOF • getchar reads a character from stdin: int fgetc(FILE *fp) ch = getchar(); int getc(FILE *fp) // macro • fgetc and getc read a character from an arbitrary int getchar() <==> int fgetc(stdin) stream: • Writing – returns char written ch = fgetc(fp); ch = getc(fp); int fputc(int c, FILE *fp) • All three functions treat the character as an int putc(int c, FILE *fp) // macro unsigned char value (which is then converted to int putchar(int c) <==> int fputc(…, int type before it’s returned). stdin) • As a result, they never return a negative value other int ungetc(int c, FILE *fp) than EOF. 6 3/25/14 Character I/O Character I/O • One of the most common uses of fgetc, getc, • The ungetc function “pushes back” a character and getchar is to read characters from a file. read from a stream and clears the stream’s end-of- • A typical while loop for that purpose: file indicator. while ((ch = getc(fp)) != EOF) { • A loop that reads a series of digits, stopping at the … first nondigit: } while (isdigit(ch = getc(fp))) { • Always store the return value in an int variable, … not a char variable. } • Testing a variable against may give the ungetc(ch, fp); char EOF /* pushes back last character read */ wrong result. Character I/O Line I/O • putchar writes one character to the stdout stream: • Reading – returns pointer to string read, NULL if putchar(ch); /* writes ch to stdout */ end of file • fputc and putc write a character to an arbitrary char* fgets(char *buf, int max, FILE *fp) stream: fputc(ch, fp); /* writes ch to fp */ • Strings are character arrays in C putc(ch, fp); /* writes ch to fp */ • max indicates the maximum number of characters • File copy by Char: to be read. FILE *in, *out; • max should be 1 less than the length of buf! // open both src and dest files as // in and out, respectively • gets is equivalent to fgets(…, stdin) while ((c = fgetc(in)) != EOF) { • Writing – returns number of chars written fputc(c, out); int fputs(char *buf, FILE *fp) } Example: File Copy by Line File Positioning int main() { char buf[BUFLEN], inFile[BUFLEN], outFile[BUFLEN]; • Each file has an associated file position FILE *in, *out; printf("Enter source filename: "); • When a file is opened, the file position is set either fgets(inFile,BUFLEN-1,stdin); at the beginning or the end inFile[strlen(inFile)-1] = '\0'; // get outFile as well from user SEEK_SET – beginning of file in = fopen(inFile, "r"); SEEK_CUR – current file position out = fopen(outFile, "w"); SEEK_END – end of file if ((in == NULL) || (out == NULL)) { printf("*** File open error\n"); int fseek(FILE *fp, long offset, int return; whence) } /* NULL returned at EOF */ void rewind(FILE *fp) while (fgets(buf, BUFLEN-1, in) != NULL) { fputs(buf, out); rewind(fp) <==> fseek(fp, 0L, } SEEK_SET) fclose(in); fclose(out); return 0; } 7 3/25/14 String I/O String I/O • Read and write data using a string as though it • sscanf reads characters from a string. were a stream. • An example that uses fgets to obtain a line of input, • The sprintf function writes output into a then passes the line to sscanf for further processing: character array (pointed to by its first argument) fgets(str, sizeof(str), stdin); instead of a stream. /* reads a line of input */ sscanf(str, "%d%d", &i, &j); • A call that writes "9/20/2010" into date: /* extracts two integers */ sprintf(date, "%d/%d/%d", 9, 20, 2010); • sscanf returns the number of data items successfully • sprintf adds a null character at the end of the read and stored. string. • sscanf returns EOF if it reaches the end of the string • It returns the number of characters stored (not (marked by a null character) before finding the first counting the null character). item. String I/O • One advantage of using sscanf is that we can examine an input line as many times as needed. • This makes it easier to recognize alternate input forms and to recover from errors. • Consider the problem of reading a date that’s written either in the form month/day/year or month-day- year: if (sscanf(str, "%d /%d /%d", &month, &day, &year) == 3) printf("Month: %d, day: %d, year: %d\n", month, day, year); else if (sscanf(str, "%d -%d -%d", &month, &day, &year) == 3) printf("Month: %d, day: %d, year: %d\n", month, day, year); else printf("Date not in the proper form\n"); 8