Standard I/O libary
Streams and FILE Objects:流和FILE对象
When we open or create a file with the standard I/O library, we say that we have associated a stream with the file.
A stream’s orientation determines whether the characters that are read and written are single byte or
multibyte.
Initially ,when a stream is created, it has no orientation.一开始,文件被打开的时候,流是没有定向的!
The freopen function (discussed shortly) will clear a stream’s orientation; the fwide function can be used to set a stream’s orientation.
对流进行读取规则限定的函数fwide
#include <stdio.h> #include <wchar.h> int fwide(FILE *fp ,int mode);
Returns:
positive if stream is wide oriented,
negative if stream is byte oriented,
or 0 if stream has no orientation
The fwide function performs different tasks, depending on the value of the mode
argument.
?If the mode argument is negative, fwide will try to make the specified stream
byte oriented.
?If the mode argument is positive, fwide will try to make the specified stream
wide oriented.
?If the mode argument is zero, fwide will not try to set the orientation, but will
still return a value identifying the stream’s orientation.
The fwide function performs different tasks, depending on the value of the mode argument.
Note that fwide will not change the orientation of a stream that is already oriented. Also note that there is no error return.有点意思,没有错误返回的函数,我记得没有错误返回的函数还有标准库函数free。以后面试问起兴许还能说几个,嘿嘿。。。
Byte oriented 和 wide oriented是用来限制单次读写stream 的字节数的
如果不按照规则读写,则会发生读写失败
fwide(file_pointer,positive_number);
这样就可以把当前的file_pointer指向的流oriented 为widecharacter那么这个时候对这个流的每次读写操作都不能是以单个字节
test:
#include"stdio.h"
#include"string.h"
#defineBUFFSIZE 1024
#definePOSITIVE 1
intmain()
{
FILE* file_pointer = NULL;
char buffer[BUFFSIZE];
int byte = 0;
memset(buffer,0,BUFFSIZE*sizeof(char));
file_pointer =fopen("./test.txt","r+");
if(file_pointer == NULL)
{
printf("fopenerror\n");
return 0;
}
fwide(file_pointer,POSITIVE);
while((byte =fread(buffer,sizeof(char),BUFFSIZE,file_pointer)) > 0)
{
fwrite(buffer,sizeof(char),byte,stdout);
}
fclose(file_pointer);
return 0;
}
root@ubuntu:/Ad_Pro_in_Unix/chapter_5#gcc ./fwide_test.c -g -o ./a.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_5#./a.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_5#
可以看到,这样读写就是失败的,不能用单个字节的方式读写这个流
对fwrite和fread做修改,改为每次读取多个字节
#include"stdio.h"
#include"string.h"
#defineBUFFSIZE 1024
#definePOSITIVE 1
intmain()
{
FILE* file_pointer = NULL;
char buffer[BUFFSIZE];
int byte = 0;
memset(buffer,0,BUFFSIZE*sizeof(char));
file_pointer =fopen("./test.txt","r+");
if(file_pointer == NULL)
{
printf("fopenerror\n");
return 0;
}
fwide(file_pointer,POSITIVE);
while((byte =fread(buffer,4*sizeof(char),BUFFSIZE,file_pointer)) > 0)
{
fwrite(buffer,4*sizeof(char),byte,stdout);
}
printf("\n");
fclose(file_pointer);
return 0;
}
root@ubuntu:/Ad_Pro_in_Unix/chapter_5# ./a.out
hello world!
wakaka
file standard library IO
root@ubuntu:/Ad_Pro_in_Unix/chapter_5# vim ./fwide_test.c
读写正常!
标准输入流,标准输出流,标准错误流
Standard Input 0
Standard Output 1
Standard Error 2
Threestreams are predefined and automatically available to a process:
standardinput,standardoutput, and standarderror. These streams refer to the same files as the file descriptors STDIN_FILENO,STDOUT_FILENO ,and STDERR_FILENO ,respectively,
The filepointers are defined in the <stdio.h> header
Buffering :缓冲
The goal of the buffering provided by the standard I/O library is to use the minimum number of read and write calls.缓冲方式的分类:
1.Fully buffered. In this case, actual I/O takes place when the standardI/O buffer is filled. Files residing on disk are normally fully buffered by the standardI/O library.The buffer used is usually obtained by one of the standard I/O functions calling malloc (Section 7.8) the first time I/O is performed on a stream.
The term flush describes the writing of a standard I/O buffer. A buffer can be flushed automatically by the standardI/O routines, such as when a buffer fills, or we can call the function fflush to flush a stream.
Unfortunately, in the UNIX environment, flush means two different things. In terms of the standard
I/O library ,it means writing out the contents of a buffer ,which may be partially filled. In terms of the terminal driver,such as the tcflush function in Chapter 18, it means to discard the data that’s already stored in a buffer.
2. Line buffered.
In this case, the standardI/O library performs I/O when a newline character is encountered on
input or output. This allows us to output a single character at a time (with the standard I/O fputc function), knowing
that actual I/O will take place only when we finish writing each line. Line buffering is typically used on a stream
when it refers to a terminal —standard input and standard output, for example. Line buffering comes with two
caveats. First, the size of the buffer that the standardI/O library uses to collect each line is fixed, so I/O might
take place if we fill this buffer before writing a newline. Second, whenever input is requested through the
standardI/O library from either (a) an unbuffered stream or (b) a line-buffered stream (that requires data to be
requested from the kernel), all line-buffered output streams are flushed. The reason for the qualifier on (b)
is that the requested data may already be in the buffer,which doesn’t require data to be read from the
kernel. Obviously ,any input from an unbuffered stream, item (a), requires data to be obtained from the kernel.
3. Unbuffered. The standardI/O library does not buffer the characters. If we write 15 characters with the standard I/O fputs function, for example, we expect these 15 characters to be output as soon as possible, probably with the write function. The standarderror stream, for example, is normally unbuffered so that any error
messages are displayed as quickly as possible, regardless of whether they contain a newline.ISO是ISO的一套,很多事说了又不严格
大多数的具体实现都遵循下面的规则:
? Standarderror is always unbuffered.
? All other streams are line buffered if they refer to a terminal device; otherwise, they are fully buffered.
setbuf function:
如果我们不想按照defualt的方式来buffer,我们可以自己设置打开stream的buffer方式,调用下面这个API
#include <stdio.h>
void setbuf(FILE *restrict fp ,char *restrict buf );
int setvbuf(FILE *restrict fp ,char *restrict buf,int mode, size_t size );
Returns: 0 if OK, nonzero on error
个人建议,一般不要自己重新reset标准流的buffer。。。
原因有三点
1.今天整天的时间砸在buffer上面了。。。
2.标准流的buffer都是被设计的很好的。。。
3.如果buffer用数组实现的话有溢出的可能性,亲测 core dump;如果用malloc出来的话,要管理内存,比较麻烦。malloc稍微“溢出”都不会有问题。亲测,malloc出来的内存都是连续的
可以参考 http://blog.csdn.net/cinmyheart/article/details/21949219
APUE也说了:
Ingeneral, we should let the system choose the buffer size and automatically allocate the buffer.When we do this, the standardI/O library automatically releases the buffer when we close the stream.
继续我的笔记。。。
fllush function:
#include <stdio.h>
int fflush(FILE *fp );
Returns: 0 if OK,EOF on error
The fflush function causes any unwritten data for the stream to be passed to the kernel. As aspecial case, if fp is NULL, fflush causes all output streams to be flushed.
Opening a Stream
The fopen, freopen,and fdopen functions open a standard I/O stream.#include <stdio.h>
FILE *fopen(const char *restrict pathname ,const char *restrict type );
FILE *freopen(const char *restrict pathname ,const char *restrict type ,
FILE *restrict fp );
FILE *fdopen(int fd ,const char *type );
All three return: file pointer if OK,NULL on error
The differences in these three functions are as follows:
1.The fopen function opens a specified file.
2.The freopen function opens a specified file on a specified stream, closing the stream first if it is already open. If the stream previously had an orientation, freopen
clears it. This function is typically used to open a specified file as one of the predefined streams: standardinput, standar doutput, or standarderror.
3.The fdopen function takes an existing file descriptor,which we could obtain from the open, dup, dup2, fcntl, pipe, socket, socket pair,or accept functions,
and associates a standard I/O stream with the descriptor.This
function is often used with descriptors that are returned by the functions that create pipes and network communication channels.Because these special types of
files cannot be opened with the standard I/O fopen function, we have to call the device-specific function to obtain a file descriptor ,and then associate this
descriptor with a standardI/O stream using fdopen.
test code:
#include "stdio.h" #include "string.h" #define BUFFSIZE 1024 int main() { FILE* file_pointer = NULL; char buffer[BUFFSIZE]; memset(buffer,0,sizeof(char)*BUFFSIZE); if((file_pointer = fopen("test.txt","r")) == NULL) { printf("fopen error\n"); } if((file_pointer = freopen("test.txt","r+",file_pointer)) == NULL) { printf("freopen error\n"); } if(fread(buffer,sizeof(char),BUFFSIZE,file_pointer) < 0) { printf("fread error\n"); } if(fwrite(buffer,sizeof(char),BUFFSIZE,stdout) != BUFFSIZE) { printf("fwrite error\n"); } //fflush(stdout); fclose(file_pointer); return 0; }
Reading and Writing a Stream 流的读写
三种非格式化I/O
1. Character-at-a-time I/O.
2. Line-at-a-time I/O.
3. Direct I/O.
Input Functions
Three functions allow us to read one character at a time.
#include <stdio.h> int getc(FILE *fp ); int fgetc(FILE *fp ); int getchar(void);// == getc(stdin) All three return: next character if OK,EOF on end of file or error
The difference between getc and fgetc is that getc can be implemented as a macro, where as fgetc cannot be implemented as a macro.
This means three things:
1. The argument to getc should not be an expression with side effects, because it could be evaluated more than once.
2. Since fgetc is guaranteed to be a function, we can take its address. This allows us to pass the address of fgetc as an argument to another function.
3. Calls to fgetc probably take longer than calls to getc, as it usually takes more time to call a function.
These three functions return the next character as an unsigned char converted to an int
注意函数的返回值,是由unsigned char 强制类型转换到 int类型的
应为经常会有
#include<stdio.h> int main() { int character = 0; while((character = getchar()) != EOF) { putchar(character); } return 0; }
如果character是char类型的话,由于和EOF的类型不匹配所以。。。表达式一直为真。。。以前忽视的bug
ungetc function:
After reading from a stream, we can push back characters by calling ungetc.
#include <stdio.h>
int ungetc(int c,FILE *fp );
Returns: c if OK, EOF on error
The characters that are pushed back are returned by subsequent reads on the stream in reverse order of their
pushing.
test code:
/***********************************************************/ code writer : EOF code date : 2014.03.25 e-mail : jasonleaster@gmail.com ***********************************************************/ #include "stdio.h" int main() { int counter = 0; int character = 0; int temp = 0; while((character = getchar()) != EOF) { counter++; if(counter == 3) { if(ungetc(character,stdin) == EOF) { printf("ungetc error\n"); } else { temp = character; } } if(counter == 4) { if(character == temp) { printf("\nungec success\n"); putchar(character); printf("\n"); continue; } } putchar(character); } return 0; }
root@ubuntu:/Ad_Pro_in_Unix/chapter_5# ./a.out
abcdefg
abc
ungec success
c
defg
Output Functions:输出函数
Output functions areavailable that correspond to each of the input functions we’ve already described.#include <stdio.h> int putc(int c,FILE *fp ); int fputc(int c,FILE *fp ); int putchar(intc); All three return:c if OK, EOF on error
As with the input functions, putchar(c) is equivalent to putc(c, stdout) ,and putc can be implemented as a macro, whereas fputc cannot be implemented as a macro.
Line-at-a-Time I/O
Line-at-a-time input is provided by the two functions, fgets and gets.#include <stdio.h> char *fgets(char *restrict buf,int n,FILE *restrict fp ); char *gets(char *buf );Both return:buf if OK, NULL on end of file or error
注意:With fgets, we have to specify the size of the buffer, n.This function reads up through and including the next newline, but no more than n ? 1 characters, into the buffer .
Standard I/O Efficiency
Using the functions from the previous section, we can get an idea of the efficiency of the standardI/O system.其实我也布吉岛这一节有什么用,唯一让我觉得有点用的就这句话:
Instead, we know that the exit function will flush any unwritten data and then close all open streams.
Binary I/O 二进制I/O
用的很多的
#include <stdio.h>
size_t fread(void *restrict ptr,size_tsize ,size_tnobj ,
FILE *restrict fp );
size_t fwrite(const void *restrict ptr,size_tsize ,size_tnobj ,
FILE *restrict fp );
Both return: number of objects read or written
还是看代码吧。。这是最一目了然的方式
float data[10]; if (fwrite(&data[2], sizeof(float), 4, fp) != 4) err_sys("fwrite error");
struct { short count; long total; char name[NAMESIZE]; }item; if (fwrite(&item, sizeof(item), 1, fp) != 1) err_sys("fwrite error");
Both fread and fwrite return the number of objects read or written. For theread case, this number can be less than nobj if an error occurs or if the end of file is encountered. In this situation,ferror or feof must be called. For the write case, if the return value is less than the requested nobj , anerror has occurred.
Positioning a Stream 定位流
#include <stdio.h> long ftell(FILE *fp ); Returns: current file position indicator if OK, ?1L on error int fseek(FILE *fp ,long offset,int whence ); Returns: 0 if OK,?1 on error void rewind(FILE * fp );The values for whence are SEEK_SET means from the beginning of the file,SEEK_CUR means from the
current file position, and SEEK_END means from the end of file.
A stream can also be set to the beginning of the file with the rewind function
Formatted I/O 格式化I/O
用到烂的API。。。。
格式化输出
#include <stdio.h> int printf(const char *restrict format ,...); int fprintf(FILE *restrict fp ,const char *restrict format ,...); int dprintf(int fd ,const char *restrict format ,...); All three return: number of characters output if OK, negative value if output error
int sprintf(char *restrict buf,const char *restrict format ,...);
Returns: number of characters stored in array if OK, negative value if encoding error
int snprintf(char *restrict buf,size_tn, const char *restrict format ,...);
Returns: number of characters that would have been stored in array if buffer was large enough, negative value if encoding error
The following five variants of the printf family aresimilar to the previous five,
but the variable argument list ( ... ) is replaced with arg.
#include <stdarg.h>
#include <stdio.h>
int vprintf(const char *restrict format ,va_list arg);
int vfprintf(FILE *restrict fp ,const char *restrict format ,va_list arg);
int vdprintf(int fd ,const char *restrict format ,va_list arg);
All three return: number of characters output if OK, negative value if output error
int vsprintf(char *restrict buf,const char *restrict format , va_list arg);
Returns: number of characters stored in array if OK, negative value if encoding error
int vsnprintf(char *restrict buf,size_tn,const char *restrictformat ,va_list arg);
Returns: number of characters that would have been stored in array if buffer was large enough, negative value if encoding error
格式化输入
#include <stdio.h>
int scanf(const char *restrictformat ,...);
int fscanf(FILE *restrictfp ,const char *restrict format ,...);
int sscanf(const char *restrict buf,const char *restrict format ,...);
All three return: number of input items assigned,
EOF if input error or end of file beforeany conversion
#include <stdarg.h> #include <stdio.h> int vscanf(const char *restrict format ,va_list arg); int vfscanf(FILE *restrict fp ,const char *restrict format ,va_list arg); int vsscanf(const char *restrict buf,const char *restrict format ,va_list arg);
All three return: number of input items assigned, EOF if input error or end of file before any conversion
将流关联的文件file descriptor 返回的函数:fileno
#include <stdio.h> int fileno(FILE *fp ); Returns: the file descriptor associated with the stream
Temporar y Files
The ISO C standard defines two functions that arepro vided by the standard I/O library to assist in creating temporary files.
#include <stdio.h> char *tmpnam(char *ptr); Returns: pointer to unique pathname
FILE *tmpfile(void); Returns: file pointer if OK, NULL on error
test code:
#include"apue.h" #include"myerr.h" #include"stdio.h" int main() { char name[L_tmpnam],line[MAXLINE]; FILE *fp; printf("%s\n",tmpnam(NULL)); tmpnam(name); printf("%s\n",name); if((fp = tmpfile()) == NULL) { err_sys("tmpfile error"); } fputs("one line of output\n",fp); rewind(fp); if(fgets(line,sizeof(line),fp) == NULL) { err_sys("fgets error"); } fputs(line,stdout); exit(0); }
Be aware of the buffering that takes place with this library, as this is the area that generates the most problems and confusion.
其实没上面这句话还好,有这句话反而开始有问号了????呵呵。。:-)