《APUE》chapter 5 Standard I/O libary 学习笔记(加上自己的代码)

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  se
t  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  standard I/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.


《APUE》chapter 5 Standard I/O libary 学习笔记(加上自己的代码)_第1张图片


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  function getchar is  defined  to  be  equivalent  to getc(stdin).

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 : [email protected]

***********************************************************/
#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


Note  that  it’s  possible  for sprintf to overflow  the  buffer  pointed  to  by buf. The caller  is  responsible  for ensuring  that  the  buffer  is  large  enough. 

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.

其实没上面这句话还好,有这句话反而开始有问号了????呵呵。。:-)


《APUE》chapter 5 Standard I/O libary 学习笔记(加上自己的代码)_第2张图片









你可能感兴趣的:(linux,api,streams,库)