Fifth. Standard I/O

Source: Internet
Author: User
Tags fread rewind

5.1 Introduction

This chapter describes the standard I/O libraries. Because this library is implemented not only on UNIX, but also on many operating systems, it is illustrated by the ISO C standard.

The standard I/O library handles many details, such as buffer allocations, to optimize the length of I/O, and so on. These treatments leave the user without worrying about how to choose to use the correct block length, as described in section 3.9. This makes it easy for users to use, but it also poses some problems if you do not call deep understanding of the operations of the I/O library functions.

The standard I/O library was written by Dennis Ritchie in about 1975 years. Surprisingly, after 30 years, the standard I/O library was only minimally modified.

5.2 Stream and file object

In the 3rd chapter, all I/O functions are for file descriptors. When a file is opened, a file descriptor is returned, and the file descriptor is used for subsequent I/O operations. For standard I/O libraries, they operate around streams. When the standard I/O library opens or creates a file, we have associated a stream with a file.

For the ASCII character set, a character is represented by one byte. For international character sets, a character can be represented in multiple bytes. Standard I/O file streams are available for single-byte or multibyte character sets. The stream's orientation (stream's orientation) determines whether the read, write characters are single-byte or multibyte. When a stream is initially created, it is not directed. If a multibyte I/O function (minus <wchar.h>) is used on an non-directed stream, the orientation of the stream is set to wide orientation. If a single-byte I/O function is used on an non-directed stream, the orientation of the stream is set to byte-oriented. Only two functions can change the orientation of a stream. The Freopen function (see section 5.5) clears the orientation of a stream; the Fwide function sets the orientation of the stream.

int int mode);

Depending on the different values of the mode parameter, the Fwide function performs different tasks:

(1) If the mode parameter value is negative, Fwide will attempt to make the specified stream a byte-oriented.

(2) If the mode parameter value is positive, Fwide will attempt to specify that the stream is wide-oriented.

(3) If the mode parameter value is 0,fwide, no attempt is made to set the direction of the stream, but returns a value that identifies the flow orientation.

Note that Fwide does not change the orientation of the directed stream. It should also be noted that the Fwide returns without error. Imagine if the flow is not valid, then what will happen? The only thing we can rely on is to clear errno before calling Fwide, and check the value of errno when returning from Fwide. In the remainder of this book, we only deal with byte-directed streams.

When a stream is opened, the standard I/O function fopen Returns a pointer to the FILE object. This object is typically a structure that contains all the information that the standard I/O library needs to manage the flow, including: The file descriptor for the actual I/O, the pointer to the stream buffer, the length of the buffer, the number of bytes in the current buffer, the error standard, and so on.

The application does not need to check the FILE object. To reference a stream, you pass the FILE pointer as a parameter to each standard I/O function. In the entire book, we call a pointer to a file object (type file *) as a document pointer.

5.3 Standard input, standard output, standard error

Three streams are pre-defined for a process, and these three streams can be automatically used by processes: standard input, standard output, and standard error. These stream-referenced files are the same as those referenced by the file descriptors Stdin_fileno, Stdout_fileno, and Stderr_fileno referred to in section 3.2.

These three standard I/O flows through predefined file pointers stdin, stdout, and stderr to be referenced. These three file pointers are also defined in the header file <stdio.h>.

5.4 Buffering

The standard I/O library provides buffering to minimize the number of read and write calls that are used. It also automatically buffers each I/O stream, avoiding the hassle of applications needing to consider this. Unfortunately, the standard I/O library is the most puzzling and it buffers.

Standard I/O provides three types of buffering:

(1) Full buffer. In this case, the actual I/O operation is not performed until the standard I/O buffers are filled. For files residing on disk, they are usually fully buffered by the standard I/O library. When performing the first I/O operation on a stream, the relevant standard I/O functions typically call malloc (see section 7.8) to get the buffers that need to be used.

The term flushing (flush) describes the write operation of the standard I/O buffers. Buffers can be flushed automatically by standard I/O routines (such as when filling a buffer), or you can call the function fflush to flush a stream. It is worth noting that flush has two meanings in a UNIX environment. In the case of standard I/O libraries, flush means that the contents of the buffer are written to disk (the buffer may be only partially filled in). In terms of terminal drivers, flush means discarding data that has been stored in the buffer.

(2) Row buffer. In this case, the standard I/O library performs I/O operations when a newline character is encountered in the input and output. This allows us to output one character at a time (with the standard I/O FPUTC function), but only after writing a line for actual I/O operations. Row buffering is typically used when a stream involves a terminal (for example, standard input and standard errors).

There are two restrictions for row buffering. First, because the length of the buffer used by the standard I/O library to collect each row is fixed, so long as the buffer is filled, the I/O operation is done even if a newline character has not been written. Second, any time a standard I/O library is required to obtain input data from (a) a non-buffered stream, or (b) a row-buffered stream (which requires data from the kernel), it causes flushing of all rows to buffer the output stream. In (b) There is a note in parentheses, on the grounds that the required data may already be in the buffer, and it does not require data to be read from the kernel when it is needed. It is obvious that input from a stream that is never buffered is required to get data from the kernel at that time.

(3) without buffering. The standard I/O library does not buffer characters for storage. For example, if you write 15 characters with a standard I/O function fputs to a stream without buffering, it is likely that the function will immediately write these characters to the associated open file using the Write system call function.

For any given stream, call the following function to change the buffer type:

void Char *restrict buf); int Char int mode,                 size_t size);

At any time, we can force flushing a stream.

int fflush (FILE *FP);

function to send all of the data that is not written to the stream to the kernel. As a special case, this function causes all output streams to be flushed if the FP causes NULL.

5.5 Open stream

The following three functions open a standard I/O stream.

FILE *fopen (const charconst char **freopen (constChar  ConstChar *restrict type,                     **fdopen (intconst  Char *type);

The differences between the three functions are:

(1) fopen open a specified file.

(2) Freopen open a specified file on a specified stream, and if the stream is already open, close the stream first. If the stream is already directed, Freopen clears the orientation. This function is typically used to open a specified file as a predefined stream: standard input, standard error, standard error.

(3) Fdopen Gets an existing file descriptor and combines a standard I/O stream with the descriptor. This function is commonly used for descriptors that are returned by creating pipelines and network communication functions. Because these special types of files cannot be opened with the standard I/O fopen function, we must first call the device specialized function to obtain a file descriptor, and then use Fdopen to associate a standard I/O stream with the description typeface.

The type parameter specifies how the I/O stream is read and written, and ISO C stipulates that the type parameter can have 15 different values, which are shown in the following table:

Use character B as part of the type, which enables standard I/O to differentiate between text files and binaries. Because the Unix kernel does not differentiate between the two files, specifying character B as part of the type in a UNIX system environment does not actually do so.

The meaning of the Fdopen,type parameter is slightly different. Because the descriptor has been opened, Fdopen is open for writing and does not truncate the file (for example, if the descriptor was originally created by the Open function and the file already existed at that time, its O_TRUNC flag will determine whether to truncate the file.) The Fdopen function cannot truncate any file it has opened for writing. In addition, the flag I/O Write method cannot be used to create the file (because if a descriptor references a file, the file must already exist).

When a file is opened with the add-on type, the data is written to the end of the file each time it is written. If more than one process opens the same file with the flag I/O, the data from each process is correctly written to the file.

Note that when a new file is created with the specified w or a type, we cannot describe the file access permission bit (the Open function and the creat function can do that).

Unless the stream refers to an end device, by default the stream is fully buffered when it is opened. If the stream references an end device, the stream is buffered. Once the stream has been opened, the buffer type can be changed using the Setbuf and setvbuf described in the previous section, if desired, before any operations are performed on the convection.

Call Fclose to close an open stream

int fclose (FILE *FP);

Flush the output data in the buffer before the file is closed. Discards any input data in the buffer. If the flag I/O library has automatically allocated a buffer for the stream, this buffer is freed.

When a process terminates normally (calling the Exit function directly, or returning from the main function), all flag I/O streams with write buffered data will be flushed and all open flag I/O streams will be closed.

5.6 Read and Write streams

Once the stream is turned on, you can select it in three different types of unformatted I/O to read and write:

(1) I/O for one character at a time. Read or write one character at a time, and if the stream is buffered, the standard I/O function handles all buffers.

(2) I/O for each line. If you want to read or write one line at a time, use Fgets and fputs. Each line terminates with a newline character. When calling fgets, you should indicate the maximum number of presidents that can be processed.

(3) Direct I/O. The fread and Fwrite functions support this type of I/O. Each I/O operation reads or writes a number of objects, and each object has a specified length. These two functions are commonly used to read or write a structure from a binary file each time.

1. Input function

int getc (FILE *fp); int fgetc (FILE *fp); int getchar (void);

The function GetChar is equivalent to GETC (stdin). The difference between the previous two functions is that GETC can be implemented as a macro, and FGETC cannot be implemented as a macro. This means that:

(1) The GETC parameter should not be an expression with side effects

(2) Because fgetc must be a function, it can get its address. This allows the address of the fgetc to be passed as one parameter to another function.

(3) The time required to call fgetc is likely to be longer than calling Getc, because calling a function typically takes longer than calling a macro.

These three functions convert their unsigned char type to an int type when the next character is returned. The reason for the non-conformance is that if the highest bit is 1, the return value will not be negative. The reason for requiring the shaping of the return value is to return all possible character values plus an indication that an error has occurred or that the end of the file has been reached. The constant EOF in <stdio.h> is required to be a negative value, which is often 1. This means that the return values of these three functions cannot be stored in a single character variable, and the return values of these functions will be compared to the constant EOF in the future.

Note that all three functions return the same value, either in error or at the end of the file. In order to differentiate between these two different situations, you must call ferror or feof

int ferror (FILE *fp); int feof (FILE *fp); void clearerr (FILE *FP);

In most implementations, two flags are maintained for each stream in the file object:

(1) Error mark.

(2) End of document sign.

Calling Clearerr clears both flags.

After reading the data from the stream, you can call ungetc to press the character back into the reflow.

int ungetc (int c, FILE *FP);

The characters in the pressure return can then be read from the stream, but the order of the read out characters is reversed from the order of the pressure feed back. It should be understood that although ISO C allows implementations to support any number of loopback, it requires that the implementation provide only one character at a time. We cannot expect to return multiple characters at once.

The loopback character does not necessarily have to be the last read character. Cannot echo EOF. However, a character can still be echoed when the end of the file has been reached. The next read returns the character, and the re-read returns EOF. The reason this is possible is that a successful ungetc call clears the end-of-file flag for the stream.

The loopback character operation is often used when an input stream is being read and some form of word or tick operation is performed. Sometimes you need to look at the next character to decide how to handle the current character. You then need to conveniently return the newly-viewed characters so that the character is returned the next time you call getc. If the flag I/O library does not provide loopback capability, it is necessary to store the character in one of our own variables and set a flag to determine whether to call getc or to take it from our own variables the next time a character is required.

When you use UNGETC to send back characters, they are not written to the file or the device, but they are written back into the stream buffer of the flag I/O library.

2. Output function

int putc (int c, FILE *FP); int FPUTC (int c, FILE *FP); int putchar (int c);

As with input functions, Putchar (c) is equivalent to PUTC (c, stdout), PUTC can be implemented as a macro, and FPUTC cannot be implemented as a macro.

5.7 I/O per line

The following two functions provide the ability to enter one line at a time

Char *fgets (charint N, FILE *restrict FP); Char *gets (char *buf);

Both functions specify the address of the buffer, and the rows that are read into it. Gets is read from the standard input, while fgets is read from the specified stream.

For fgets, you must specify the length of the buffer n, which reads until the next newline character, but not more than n-1 characters, and the read-in character is fed into a buffer. The buffer ends with a null character. If the number of characters for a row (including the last newline character) exceeds n-1, Fgets returns only an incomplete row, but the buffer always ends with a null character. The next call to Fgets will continue to read the row.

The gets is a deprecated function. The problem is that the caller cannot specify the length of the buffer when using the gets. This can result in a buffer overflow (if the line is longer than the buffer length) and write to the storage space after the buffer, resulting in unpredictable consequences. This flaw has been exploited, resulting in 1988 of years of Internet worm events. Another difference between get and fgets is that gets does not store newline characters in buffers.

Even if ISO C requires that you provide a GET, use fgets instead of get.

Fputs and puts provide the ability to output one line at a time.

int fputs (constchar *restrict str, FILE *restrict FP); int puts (constchar *str);

The function fputs writes a null-terminated string to the specified stream, terminating at the end of null without writing. Note that this does not necessarily have to be one line at a time, because it does not require a newline character before the null character. Typically, a newline character precedes a null character, but it is not always required.

Puts writes a null-terminated string to standard output, and the Terminator is not written out. However, puts then writes a newline character to standard output.

The puts is not as insecure as the corresponding gets. However, we should avoid using it, lest we need to remember whether it will add a newline character at the end of the line. If you always use Fgets and fputs, then you'll know that at the end of each line we have to handle the line break ourselves.

5.8 Efficiency of standard I/O

Using the functions described in the previous section, we can understand the efficiency of a standard I/O system.

Do not explain why and explore details in this article.

5.9 Binary I/O

The functions in sections 5.6 and 5.7 operate in a single character or one line at a time. If you do binary I/O, then we prefer to read or write the entire structure at once. If you use GETC or PUTC to read and write a structure, you must loop through the entire structure, processing one byte at a time, reading or writing a byte at once, which can be cumbersome and lengthy. If you use Fputs and fgets, you cannot use it to implement the read structure requirement because the fputs stops when it encounters a null byte and may contain a null byte in the struct. Similarly, if the input data contains null bytes or line breaks, fgets does not work correctly. Therefore, the following two functions are provided to perform binary I/O operations.

size_t fread (void *restrict ptr, size_t size, size_t nobj,                  *restrict FP); size_t fwrite ( C4>constvoid *restrict ptr, size_t size, size_t nobj,                   *restrict FP);

These functions are used in two common ways:

(1) Read or write a binary array. For example, in order to write the 2nd to 5th element of a floating-point array to a file, you can write the following program:

float data[]; if (Fwrite (&data[2sizeof(float44)   Err_sys ("  fwrite error");

Where the size of the array element is specified, Nobj is the number of elements to write.

(2) Read or write a structure, for example, the following programs can be written:

struct {   short  count;    Long Total ;    Char name[namesize];} item; if sizeof 1 1 )   Err_sys ("fwrite error");

Combine these two examples to read or write an array of structures. In order to do this, size should be the sizeof,nobj of the structure should be the number of elements in the array.

Fread and Fwrite return the number of objects read or written. For read, this number can be less than nobj if an error occurs or reaches the end of the file. In this case, you should call ferror or feof to determine exactly which case it belongs to. For write, an error occurs if the return value is less than the requested nobj.

The basic problem with binary I/O is that he can only be used to read data that has been written on the same system. Therefore, in heterogeneous systems (multiple hosts connected to each other through the network to form a system), the data written on one system, to be processed on another system, can be faulted because:

(1) In one structure, the offset of the same member may vary depending on the compiler or system (due to different alignment requirements).

(2) used to store multiple byte integers and floating-point worthy binary formats may also differ between different machine architectures.

5.10 Locating the Stream

There are three ways to locate standard I/O streams.

(1) Ftell and fseek functions. They all assume that the location of the file can be stored in a long integer type.

(2) Ftello and Fseeko functions. You can make the file offset unnecessary to use long integers. They use the off_t data type instead of the long integer type.

(3) Fgetpos and Fsetpos functions. They use an abstract data type fpos_t record file location. This data type can be defined as the length required to record a file location.

long ftell (FILE *fp); int Long int whence); void Rewind (FILE *FP);

For a binary file, its file position indicator is measured from the beginning of the file and measured in bytes. When the Ftell is used for a binary file, its return value is the byte position. In order to locate a binary file with fseek, you must specify a byte offset and how to interpret the offset. The value of whence is the same as the Lseek function in section 3.6: Seek_set means starting from the beginning of the file, seek_cur means starting at the current file location, and seek_end means starting at the end of the file.

You can also set a stream to the beginning of a file by using the Rewind function.

Except that the type of offset is off_t and not long, the Ftello function is the same as Ftell, and the Fseeko function is the same as fseek.

off_t Ftello (FILE *fp); int int whence);

The two functions of Fgetpos and Fsetpos are introduced by the C standard.

int fgetpos (FILE *restrict FP, fpos_t *restrict POS); int Const fpos_t *pos);

Fgetpos the current value of the location indicator of the file into the object pointed to by the Pos. You can use this value to relocate a stream to that location when you call Fsetpos later.

5.11 Formatting I/O

1. Formatted output

There are 4 printf functions that perform the formatting process

 int  printf (const  char  *restrict format, ...);  int  fprintf (FILE *restrict FP, const  char  *restrict format, ...);  int  sprintf (char  *restrict buf, const  char  *restrict Format, ...);  int  sprintf (char  * restrict buf, size_t N,  const  char  *restrict format, ...); 

printf writes the formatted data to the standard output, fprintf writes to the specified stream, sprintf the formatted character into the array buf. sprintf automatically adds a null byte to the end of the array, but the byte is not included in the return value.

The sprintf function may cause a buffer overflow, the snprintf function solves the problem, the length of the buffer is a display parameter, and the number of characters exceeding the buffer is discarded. The snprintf function returns the number of characters written to the buffer, the same as sprintf, which does not include the trailing null byte. If the snprintf function returns a positive value that is less than the buffer length n, then there is no truncated output. If an encoding error occurs, SNPRINTF returns a negative value.

2. Format Input

There are three scanf functions that perform formatted input processing

int scanf (constChar *restrict format, ...); int Const Char *restrict format, ...); int sscanf (constcharconstChar *restrict format,               ...);

5.12 Implementation Details

As mentioned earlier, in UNIX systems, the standard I/O library ultimately calls the I/O routines described in Chapter 3rd. Each standard I/O stream has a file descriptor associated with it, and you can call the Fileno function on a stream to get its descriptor.

int Fileno (FILE *FP);

This function is required if you want to invoke a function such as DUP or FCNTL.

5.13 Temporary files

The ISO C standard I/O library provides two functions to help create temporary files.

Char *tmpnam (char **tmpfile (void);

Fifth. Standard I/O

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.