fread函数和fwrite函数,read,write

fread函数和fwrite函数

 1.函数功能

  用来读写一个数据块

2.一般调用形式

  fread(buffer,size,count,fp);

  fwrite(buffer,size,count,fp);

3.说明

  (1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址

  (2)size:要读写的字节数

  (3)count:要进行读写多少个size字节的数据项;// 1代表二进制

  (4)fp:文件型指针。

 注意:

          1 完成次写操(fwrite())作后必须关闭流(fclose());

           2 完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;

           3 fprintf() : 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。注意的是返回值为此次操作写入到文件的字节数。如int c = fprintf(fp, "%s %s %d %f", str1,str2, a, b) ;str1:10字节;str2: 10字节;a:2字节;b:8字节,c为33,因为写入时不同的数据间自动加入一个空格。

文件使用之后一定要关闭,否则将不能正确显示内容.fwrite:读入两个学生信息然后用fwrite存入文件

fread:用fread从文件中读出学生信息。

fwrite.c

#include <stdio.h>
#define SIZE 2
struct student_type
{
 char name[10];
 int num;
 int age;
 char addr[10];
}stud[SIZE];
void save()
{
 FILE *fp;
 int i;
 if((fp=fopen("stu_list","wb"))==NULL)
 {
  printf("cant open the file");
  exit(0);
 }
 for(i=0;i<SIZE;i++)
 {
   if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
    printf("file write error\n");
 }
 fclose(fp);
}
main()
{
 int i;
 for(i=0;i<SIZE;i++)
 {
   scanf("%s%d%d%s",&stud[i].name,&stud[i].num,&stud[i].age,&stud[i].addr);
   save();
 }
 for(i=0;i<SIZE;i++)
 {
   printf("%s,%d,%d",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
 }
}

fread.c

#include <stdio.h>
#define SIZE 2
struct student_type
{
 char name[10];
 int num;
 int age;
 char addr[10];
}stud[SIZE];
void read()
{
 FILE *fp;
 int i;
 if((fp=fopen("stu_list","rb"))==NULL)
 {
  printf("cant open the file");
  exit(0);
 }
 for(i=0;i<SIZE;i++)
 {
   if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)
    printf("file write error\n");
 }
 fclose(fp);
}
main()
{

 int i;
 read();
 for(i=0;i<SIZE;i++)
 {
   printf("%s,%d,%d,%s",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
   printf("\n");
 }
}

在C语言中进行文件操作时,我们经常用到fread()和fwrite(),用它们来对文件进行读写操作。下面详细绍一下这两个函数的用法。

  我们在用C语言编写程序时,一般使用标准文件系统,即缓冲文件系统。系统在内存中为每个正在读写的文件开辟“文件缓冲区”,在对文件进行读写时数据都经过缓冲区。要对文件进行读写,系统首先开辟一块内存区来保存文件信息,保存这些信息用的是一个结构体,将这个结构体typedef为FILE类型。我们首先要定义一个指向这个结构体的指针,当程序打开一个文件时,我们获得指向FILE结构的指针,通过这个指针,我们就可以对文件进行操作。例如:

#i nclude <stdio.h>

#i nclude <string.h>

int main()

{

   FILE *fp;

   char buffer[100] = "This is a test";

   if((fp = fopen("c:\\example.txt", "w")) == 0)

    {

       printf("open failed!");

       exit(1);

    }

   fwrite(buffer, 1, strlen("This is a test"), fp);

   fclose(fp);

   return 0;

}

  通过以上代码,我们就在c盘的根目录下建立了一个名为example扩展名为.txt的文件,我们打开可以看到上面写上了This is a test。当我们对它将它读出时,用如下代码:

#i nclude <stdio.h>

#i nclude <mem.h>

int main()

{

   FILE *fp;   int len;

   char buffer[100];

   /*memset(buffer, 1, 100); */

   if((fp = fopen("c:\\example.txt", "r")) == 0)

    {

       printf("open failed!");

       exit(1);

    }

   fseek(fp, 0L, SEEK_END);

   len = ftell(fp);

   rewind(fp);

   fread(buffer, 1, len , fp);

   printf("%s",buffer);

   fclose(fp);

   getch();

   return 0;

}

 可以看到,当我们使用memset了以后,读出了一大堆乱码,这是为什么呢?原因是我们在fwrite函数时写入的字节数是用strlen求得的,也就是说字符串最后的'\0'并没有写到文件中去。所以我们从文件中读到buffer中时也自然没有'\0',因为buffer中的数是随机的,除非buffer中最后一个字符的下一个数恰好随机到0(可能性很小,这里用memset将它排除),否则以%s将buffer中的字符输出时遇不到0,所以乱码产生。解决的办法有很多,你可以在向文件写数据时多写入一个字节,系统会自动写入0,fwrite(buffer, 1, strlen("This is a test")+1, fp);这样读出时最后就有一个0了。或者读出操作完成后,在最后一个字符后面补上一个0:buffer[len] = 0;这样问题也可得到解决。
 
fread函数和fwrite函数 1.函数功能

  用来读写一个数据块。

2.一般调用形式

  fread(buffer,size,count,fp);

  fwrite(buffer,size,count,fp);

3.说明

  (1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。

  (2)size:要读写的字节数;

  (3)count:要进行读写多少个size字节的数据项;

  (4)fp:文件型指针。

 注意:1 完成次写操(fwrite())作后必须关闭流(fclose());

           2 完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;

           3 fprintf() : 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。注意的是返回值为此次操作写入到文件的字节数。如int c = fprintf(fp, "%s %s %d %f", str1,str2, a, b) ;str1:10字节;str2: 10字节;a:2字节;b:8字节,c为33,因为写入时不同的数据间自动加入一个空格。

文件使用之后一定要关闭,否则将不能正确显示内容.fwrite:读入两个学生信息然后用fwrite存入文件

fread:用fread从文件中读出学生信息。

fwrite.c

#include <stdio.h>
#define SIZE 2
struct student_type
{
 char name[10];
 int num;
 int age;
 char addr[10];
}stud[SIZE];
void save()
{
 FILE *fp;
 int i;
 if((fp=fopen("stu_list","wb"))==NULL)
 {
  printf("cant open the file");
  exit(0);
 }
 for(i=0;i<SIZE;i++)
 {
   if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
    printf("file write error\n");
 }
 fclose(fp);
}
main()
{
 int i;
 for(i=0;i<SIZE;i++)
 {
   scanf("%s%d%d%s",&stud[i].name,&stud[i].num,&stud[i].age,&stud[i].addr);
   save();
 }
 for(i=0;i<SIZE;i++)
 {
   printf("%s,%d,%d",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
 }
}

fread.c

#include <stdio.h>
#define SIZE 2
struct student_type
{
 char name[10];
 int num;
 int age;
 char addr[10];
}stud[SIZE];
void read()
{
 FILE *fp;
 int i;
 if((fp=fopen("stu_list","rb"))==NULL)
 {
  printf("cant open the file");
  exit(0);
 }
 for(i=0;i<SIZE;i++)
 {
   if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)
    printf("file write error\n");
 }
 fclose(fp);
}
main()
{

 int i;
 read();
 for(i=0;i<SIZE;i++)
 {
   printf("%s,%d,%d,%s",stud[i].name,stud[i].num,stud[i].age,stud[i].addr);
   printf("\n");
 }
}

在C语言中进行文件操作时,我们经常用到fread()和fwrite(),用它们来对文件进行读写操作。下面详细绍一下这两个函数的用法。

  我们在用C语言编写程序时,一般使用标准文件系统,即缓冲文件系统。系统在内存中为每个正在读写的文件开辟“文件缓冲区”,在对文件进行读写时数据都经过缓冲区。要对文件进行读写,系统首先开辟一块内存区来保存文件信息,保存这些信息用的是一个结构体,将这个结构体typedef为FILE类型。我们首先要定义一个指向这个结构体的指针,当程序打开一个文件时,我们获得指向FILE结构的指针,通过这个指针,我们就可以对文件进行操作。例如:

#i nclude <stdio.h>

#i nclude <string.h>

int main()

{

   FILE *fp;

   char buffer[100] = "This is a test";

   if((fp = fopen("c:\\example.txt", "w")) == 0)

    {

       printf("open failed!");

       exit(1);

    }

   fwrite(buffer, 1, strlen("This is a test"), fp);

   fclose(fp);

   return 0;

}

  通过以上代码,我们就在c盘的根目录下建立了一个名为example扩展名为.txt的文件,我们打开可以看到上面写上了This is a test。当我们对它将它读出时,用如下代码:

#i nclude <stdio.h>

#i nclude <mem.h>

int main()

{

   FILE *fp;   int len;

   char buffer[100];

   /*memset(buffer, 1, 100); */

   if((fp = fopen("c:\\example.txt", "r")) == 0)

    {

       printf("open failed!");

       exit(1);

    }

   fseek(fp, 0L, SEEK_END);

   len = ftell(fp);

   rewind(fp);

   fread(buffer, 1, len , fp);

   printf("%s",buffer);

   fclose(fp);

   getch();

   return 0;

}

 可以看到,当我们使用memset了以后,读出了一大堆乱码,这是为什么呢?原因是我们在fwrite函数时写入的字节数是用strlen求得的,也就是说字符串最后的'\0'并没有写到文件中去。所以我们从文件中读到buffer中时也自然没有'\0',因为buffer中的数是随机的,除非buffer中最后一个字符的下一个数恰好随机到0(可能性很小,这里用memset将它排除),否则以%s将buffer中的字符输出时遇不到0,所以乱码产生。解决的办法有很多,你可以在向文件写数据时多写入一个字节,系统会自动写入0,fwrite(buffer, 1, strlen("This is a test")+1, fp);这样读出时最后就有一个0了。或者读出操作完成后,在最后一个字符后面补上一个0:buffer[len] = 0;这样问题也可得到解决。
 

 
 
 
 
/***
*fwrite.c - read from a stream
*
*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       Write to the specified stream from the user's buffer.
*
*******************************************************************************/

#include <cruntime.h>
#include <stdio.h>
#include <mtdll.h>
#include <io.h>
#include <string.h>
#include <file2.h>
#include <internal.h>

/***
*size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream) -
*       write to the specified stream from the specified buffer.
*
*Purpose:
*       Write 'count' items of size 'size' to the specified stream from
*       the specified buffer. Return when 'count' items have been written
*       or no more items can be written to the stream.
*
*Entry:
*       buffer  - pointer to user's buffer
*       size    - size of the item to write
*       count   - number of items to write
*       stream  - stream to write to
*
*Exit:
*       Returns the number of (whole) items that were written to the stream.
*       This may be less than 'count' if an error or eof occurred. In this
*       case, ferror() or feof() should be used to distinguish between the
*       two conditions.
*
*Notes:
*       fwrite will attempt to buffer the stream (side effect of the _flsbuf
*       call) if necessary.
*
*       No more than 0xFFFE bytes may be written out at a time by a call to
*       write(). Further, write() does not handle huge buffers. Therefore,
*       in large data models, the write request is broken down into chunks
*       that do not violate these considerations. Each of these chunks is
*       processed much like an fwrite() call in a small data model (by a
*       call to _nfwrite()).
*
*       This code depends on _iob[] being a near array.
*
*       MTHREAD/DLL - Handled in just two layers since it is small data
*       model. The outer layer, fwrite(), handles stream locking/unlocking
*       and calls _fwrite_lk() to do the work. _fwrite_lk() is the same as
*       the single-thread, small data model version of fwrite().
*
*******************************************************************************/


#ifdef _MT
/* define locking/unlocking version */
size_t __cdecl fwrite (
        const void *buffer,
        size_t size,
        size_t count,
        FILE *stream
        )
{
        size_t retval;

        _lock_str(stream);                      /* lock stream */
        retval = _fwrite_lk(buffer, size, count, stream);  /* do the read */
        _unlock_str(stream);                    /* unlock stream */
        return retval;
}
#endif  /* _MT */

/* define the normal version */
#ifdef _MT
size_t __cdecl _fwrite_lk (
#else  /* _MT */
size_t __cdecl fwrite (
#endif  /* _MT */
        const void *buffer,
        size_t size,
        size_t num,
        FILE *stream
        )
{
        const char *data;               /* point to where data comes from next */
        unsigned total;                 /* total bytes to write */
        unsigned count;                 /* num bytes left to write */
        unsigned bufsize;               /* size of stream buffer */
        unsigned nbytes;                /* number of bytes to write now */
        unsigned nwritten;              /* number of bytes written */
        int c;                          /* a temp char */

        /* initialize local vars */
        data = buffer;
        count = total = size * num;
        if (0 == count)
            return 0;

        if (anybuf(stream))
                /* already has buffer, use its size */
                bufsize = stream->_bufsiz;
        else
#if defined (_M_M68K) || defined (_M_MPPC)
                /* assume will get BUFSIZ buffer */
                bufsize = BUFSIZ;
#else  /* defined (_M_M68K) || defined (_M_MPPC) */
                /* assume will get _INTERNAL_BUFSIZ buffer */
                bufsize = _INTERNAL_BUFSIZ;
#endif  /* defined (_M_M68K) || defined (_M_MPPC) */

        /* here is the main loop -- we go through here until we're done */
        while (count != 0) {
                /* if the buffer is big and has room, copy data to buffer */
                if (bigbuf(stream) && stream->_cnt != 0) {
                        /* how much do we want? */
                        nbytes = (count < (unsigned)stream->_cnt) ? count : stream->_cnt;
                        memcpy(stream->_ptr, data, nbytes);

                        /* update stream and amt of data written */
                        count -= nbytes;
                        stream->_cnt -= nbytes;
                        stream->_ptr += nbytes;
                        data += nbytes;
                }
                else if (count >= bufsize) {
                        /* If we have more than bufsize chars to write, write
                           data by calling write with an integral number of
                           bufsiz blocks.  If we reach here and we have a big
                           buffer, it must be full so _flush it. */

                        if (bigbuf(stream)) {
                                if (_flush(stream)) {
                                        /* error, stream flags set -- we're out
                                           of here */
                                        return (total - count) / size;
                                }
                        }

                        /* calc chars to read -- (count/bufsize) * bufsize */
                        nbytes = ( bufsize ? (count - count % bufsize) :
                                   count );

                        nwritten = _write(_fileno(stream), data, nbytes);
                        if (nwritten == (unsigned)EOF) {
                                /* error -- out of here */
                                stream->_flag |= _IOERR;
                                return (total - count) / size;
                        }

                        /* update count and data to reflect write */

                        count -= nwritten;
                        data += nwritten;

                        if (nwritten < nbytes) {
                                /* error -- out of here */
                                stream->_flag |= _IOERR;
                                return (total - count) / size;
                        }
                }
                else {
                        /* buffer full and not enough chars to do direct write,
                           so do a _flsbuf. */
                        c = *data;  /* _flsbuf write one char, this is it */
                        if (_flsbuf(c, stream) == EOF) {
                                /* error or eof, stream flags set by _flsbuf */
                                return (total - count) / size;
                        }

                        /* _flsbuf wrote a char -- update count */
                        ++data;
                        --count;

                        /* update buffer size */
                        bufsize = stream->_bufsiz > 0 ? stream->_bufsiz : 1;
                }
        }

        /* we finished successfully, so just return num */
        return num;
}


这是fread的源文件

/***
*fread.c - read from a stream
*
*       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
*       Read from the specified stream into the user's buffer.
*
*******************************************************************************/

#include <cruntime.h>
#include <stdio.h>
#include <mtdll.h>
#include <io.h>
#include <string.h>
#include <file2.h>

/***
*size_t fread(void *buffer, size_t size, size_t count, FILE *stream) -
*       read from specified stream into the specified buffer.
*
*Purpose:
*       Read 'count' items of size 'size' from the specified stream into
*       the specified buffer. Return when 'count' items have been read in
*       or no more items can be read from the stream.
*
*Entry:
*       buffer  - pointer to user's buffer
*       size    - size of the item to read in
*       count   - number of items to read
*       stream  - stream to read from
*
*Exit:
*       Returns the number of (whole) items that were read into the buffer.
*       This may be less than 'count' if an error or eof occurred. In this
*       case, ferror() or feof() should be used to distinguish between the
*       two conditions.
*
*Notes:
*       fread will attempt to buffer the stream (side effect of the _filbuf
*       call) if necessary.
*
*       No more than 0xFFFE bytes may be read in at a time by a call to
*       read(). Further, read() does not handle huge buffers. Therefore,
*       in large data models, the read request is broken down into chunks
*       that do not violate these considerations. Each of these chunks is
*       processed much like an fread() call in a small data model (by a
*       call to _nfread()).
*
*       MTHREAD/DLL - Handled in three layers. fread() handles the locking
*       and DS saving/loading/restoring (if required) and calls _fread_lk()
*       to do the work. _fread_lk() is the same as the single-thread,
*       large data model version of fread(). It breaks up the read request
*       into digestible chunks and calls _nfread() to do the actual work.
*
*       386/MTHREAD/DLL - Handled in just the two layers since it is small
*       data model. The outer layer, fread(), takes care of the stream locking
*       and calls _fread_lk() to do the actual work. _fread_lk() is the same
*       as the single-thread version of fread().
*
*******************************************************************************/


#ifdef _MT
/* define locking/unlocking version */
size_t __cdecl fread (
        void *buffer,
        size_t size,
        size_t count,
        FILE *stream
        )
{
        size_t retval;

        _lock_str(stream);                                /* lock stream */
        retval = _fread_lk(buffer, size, count, stream);  /* do the read */
        _unlock_str(stream);                              /* unlock stream */
        return retval;
}
#endif  /* _MT */

/* define the normal version */
#ifdef _MT
size_t __cdecl _fread_lk (
#else  /* _MT */
size_t __cdecl fread (
#endif  /* _MT */
        void *buffer,
        size_t size,
        size_t num,
        FILE *stream
        )
{
        char *data;                     /* point to where should be read next */
        unsigned total;                 /* total bytes to read */
        unsigned count;                 /* num bytes left to read */
        unsigned bufsize;               /* size of stream buffer */
        unsigned nbytes;                /* how much to read now */
        unsigned nread;                 /* how much we did read */
        int c;                          /* a temp char */

        /* initialize local vars */
        data = buffer;

        if ( (count = total = size * num) == 0 )
                return 0;

        if (anybuf(stream))
                /* already has buffer, use its size */
                bufsize = stream->_bufsiz;
        else
#if defined (_M_M68K) || defined (_M_MPPC)
                /* assume will get BUFSIZ buffer */
                bufsize = BUFSIZ;
#else  /* defined (_M_M68K) || defined (_M_MPPC) */
                /* assume will get _INTERNAL_BUFSIZ buffer */
                bufsize = _INTERNAL_BUFSIZ;
#endif  /* defined (_M_M68K) || defined (_M_MPPC) */

        /* here is the main loop -- we go through here until we're done */
        while (count != 0) {
                /* if the buffer exists and has characters, copy them to user
                   buffer */
                if (anybuf(stream) && stream->_cnt != 0) {
                        /* how much do we want? */
                        nbytes = (count < (unsigned)stream->_cnt) ? count : stream->_cnt;
                        memcpy(data, stream->_ptr, nbytes);

                        /* update stream and amt of data read */
                        count -= nbytes;
                        stream->_cnt -= nbytes;
                        stream->_ptr += nbytes;
                        data += nbytes;
                }
                else if (count >= bufsize) {
                        /* If we have more than bufsize chars to read, get data
                           by calling read with an integral number of bufsiz
                           blocks.  Note that if the stream is text mode, read
                           will return less chars than we ordered. */

                        /* calc chars to read -- (count/bufsize) * bufsize */
                        nbytes = ( bufsize ? (count - count % bufsize) :
                                   count );

                        nread = _read(_fileno(stream), data, nbytes);
                        if (nread == 0) {
                                /* end of file -- out of here */
                                stream->_flag |= _IOEOF;
                                return (total - count) / size;
                        }
                        else if (nread == (unsigned)-1) {
                                /* error -- out of here */
                                stream->_flag |= _IOERR;
                                return (total - count) / size;
                        }

                        /* update count and data to reflect read */
                        count -= nread;
                        data += nread;
                }
                else {
                        /* less than bufsize chars to read, so call _filbuf to
                           fill buffer */
                        if ((c = _filbuf(stream)) == EOF) {
                                /* error or eof, stream flags set by _filbuf */
                                return (total - count) / size;
                        }

                        /* _filbuf returned a char -- store it */
                        *data++ = (char) c;
                        --count;

                        /* update buffer size */
                        bufsize = stream->_bufsiz;
                }
        }

        /* we finished successfully, so just return num */
        return num;
} 赞同0| 评论              2009-7-29 20:06 zawdd | 七级
stdio.h
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
把数据写入一个数据流
这个例子中实现了把从A到Z的26个字符写入文件sample.txt:    
FILE *Stream;
int Count; 
char Buffer[30];  
Stream=fopen("sample.txt","w+t");  
Buffer[0]='A'; 
for(I=1; I<=25;I++) {
  Buffer[I]=Buffer[I-1]+1;
}
  Count= fwrite(Buffer,sizeof(char),26,Stream); 
  cout<<Count;
  fclose(Stream);

fread
stdio.h
从一个数据流中读取数据
使用实例:请参看feof函数
feof
stdio.h
int feof( FILE *stream );
测试文件指针是否指向数据流的尾部,若是则返回0,否则返回-1
这个例子中打开文件sample.txt,每次读取10个字节,直到所以的字节被读完为止:
    FILE  *p;
    int count,Size=0;
    char Buffer[10];
    if((p = fopen("sample.txt","r"))==NULL) exit(1);
    while(!feof(p)) {
        count =fread (Buffer,sizeof(char),10,p);
        if(ferror(p)) {
            perror("出错!");
            break;
        }
        Size = Size + count;
    }
    fclose(p);

 

 

 

 

read函数从打开的设备或文件中读取数据。

#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);

返回值:成功返回读取的字节数,出错返回-1并设置errno如果在调read之前已到达文件末尾,则这次read返回0
 

参数count是请求读取的字节数,读上来的数据保存在缓冲区buf,同时文件的当前读写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。比如用fgetc读一个字节,fgetc有可能从内核中预读1024个字节到I/O缓冲区中,再返回第一个字节,这时该文件在内核中记录的读写位置是1024,而在FILE结构体中记录的读写位置是1。注意返回值类型是ssize_t,表示有符号的size_t,这样既可以返回正的字节数、0(表示到达文件末尾)也可以返回负值-1(表示出错)。read函数返回时,返回值说明了buf中前多少个字节是刚读上来的。有些情况下,实际读到的字节数(返回值)会小于请求读的字节数count,例如:

读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有30个字节而请求读100个字节,则read返回30,下次read将返回0。

从终端设备读,通常以行为单位,读到换行符就返回了。

从网络读,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数,后面socket编程部分会详细讲解。

write函数向打开的设备或文件中写数据

#include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 返回值:成功返回写入的字节数,出错返回-1并设置errno
写常规文件时,write的返回值通常等于请求写的字节数count,而向终端设备或网络写则不一定。

读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。

现在明确一下阻塞(Block)这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行(Running)状态,在Linux内核中,处于运行状态的进程分为两种情况:

正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。

就绪状态。该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。系统中可能同时有多个就绪的进程,那么该调度谁执行呢?内核的调度算法是基于优先级和时间片的,而且会根据每个进程的运行情况动态调整它的优先级和时间片,让每个进程都能比较公平地得到机会执行,同时要兼顾用户体验,不能让和用户交互的进程响应太慢。

下面这个小程序从终端读数据再写回终端。

例 28.2. 阻塞读终端

#include <unistd.h>
#include <stdlib.h>
 int main(void)
 {
 char buf[10];
 int n;
 n = read(STDIN_FILENO, buf, 10);
 if (n < 0)
 {
 perror("read STDIN_FILENO");
 exit(1);
 }
 write(STDOUT_FILENO, buf, n);
 return 0;
 }


执行结果如下:

$ ./a.out hello(回车) hello $ ./a.out hello world(回车) hello worl$ d bash: d: command not found
第一次执行a.out的结果很正常,而第二次执行的过程有点特殊,现在分析一下:

Shell进程创建a.out进程,a.out进程开始执行,而Shell进程睡眠等待a.out进程退出。

a.out调用read时睡眠等待,直到终端设备输入了换行符才从read返回,read只读走10个字符,剩下的字符仍然保存在内核的终端设备输入缓冲区中。

a.out进程打印并退出,这时Shell进程恢复运行,Shell继续从终端读取用户输入的命令,于是读走了终端设备输入缓冲区中剩下的字符d和换行符,把它当成一条命令解释执行,结果发现执行不了,没有d这个命令。

如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。以read为例,如果设备暂时没有数据可读就返回-1,同时置errno为EWOULDBLOCK(或者EAGAIN,这两个宏定义的值相同),表示本来应该阻塞在这里(would block,虚拟语气),事实上并没有阻塞而是直接返回错误,调用者应该试着再读一次(again)。这种行为方式称为轮询(Poll),调用者只是查询一下,而不是阻塞在这里死等,这样可以同时监视多个设备:

while(1) { 非阻塞read(设备1); if(设备1有数据到达) 处理数据; 非阻塞read(设备2); if(设备2有数据到达) 处理数据; ... }
如果read(设备1)是阻塞的,那么只要设备1没有数据到达就会一直阻塞在设备1的read调用上,即使设备2有数据到达也不能处理,使用非阻塞I/O就可以避免设备2得不到及时处理。

非阻塞I/O有一个缺点,如果所有设备都一直没有数据到达,调用者需要反复查询做无用功,如果阻塞在那里,操作系统可以调度别的进程执行,就不会做无用功了。在使用非阻塞I/O时,通常不会在一个while循环中一直不停地查询(这称为Tight Loop),而是每延迟等待一会儿来查询一下,以免做太多无用功,在延迟等待的时候可以调度其它进程执行。

while(1) { 非阻塞read(设备1); if(设备1有数据到达) 处理数据; 非阻塞read(设备2); if(设备2有数据到达) 处理数据; ... sleep(n); }
这样做的问题是,设备1有数据到达时可能不能及时处理,最长需延迟n秒才能处理,而且反复查询还是做了很多无用功。以后要学习的select(2)函数可以阻塞地同时监视多个设备,还可以设定阻塞等待的超时时间,从而圆满地解决了这个问题。

以下是一个非阻塞I/O的例子。目前我们学过的可能引起阻塞的设备只有终端,所以我们用终端来做这个实验。程序开始执行时在0、1、2文件描述符上自动打开的文件就是终端,但是没有O_NONBLOCK标志。所以就像例 28.2 “阻塞读终端”一样,读标准输入是阻塞的。我们可以重新打开一遍设备文件/dev/tty(表示当前终端),在打开时指定O_NONBLOCK标志。

例 28.3. 非阻塞读终端

#include <unistd.h>
#include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
 #define MSG_TRY "try again\n"
 int main(void)
 {
 char buf[10];
 int fd, n;
 fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
 if(fd<0) { perror("open /dev/tty"); exit(1); }
 tryagain: n = read(fd, buf, 10); if (n < 0)
 {
 if (errno == EAGAIN)
 {
 sleep(1);
 write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
 goto tryagain;
 }
 perror("read /dev/tty");
 exit(1);
 }
 write(STDOUT_FILENO, buf, n);
 close(fd);
 return 0;
 }


以下是用非阻塞I/O实现等待超时的例子。既保证了超时退出的逻辑又保证了有数据到达时处理延迟较小。

例 28.4. 非阻塞读终端和等待超时

#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
 #include <stdlib.h>
 #define MSG_TRY "try again\n"
 #define MSG_TIMEOUT "timeout\n"
 int main(void)
 {
 char buf[10];
 int fd, n, i;
 fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
 if(fd<0) { perror("open /dev/tty"); exit(1); }
 for(i=0; i<5; i++)
 {
 n = read(fd, buf, 10);
 if(n>=0) break;
 if(errno!=EAGAIN) {
 perror("read /dev/tty"); exit(1);
 }
 sleep(1);
 write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
 }
 if(i==5)
 write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));
 else write(STDOUT_FILENO, buf, n); close(fd); return 0;
 }


 


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/254173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信小程序 CSS filter(滤镜)的使用示例

前言 之前在看七月老师的视频的时候&#xff0c;看到了有一个样式是-webkit-filter&#xff0c;不知道是什么&#xff08;我没咋学过CSS&#xff0c;嘿嘿&#xff0c;所以不知道是啥&#xff09;&#xff0c;于是查了一下&#xff0c;原来是滤镜吖。但是在微信小程序里使用的时…

vmware ubuntu重置root密码

1.重启ubuntu&#xff0c;按住shift&#xff08;开机启动时&#xff09; 2.选择recovery mode,enter 3.root选择root drop to root shell prompt 4.进入shell界面设置密码 (1)mount -rw -o remount / (2)passwd username(设置root用户的密码) 完成以上修改后&#xff0c;重启就…

halcon使用直线标定板,标定相机内参代码

read_image (Image, 直线标定板图片/Left201118140641772.bmp) get_image_size (Image, Width, Height) dev_close_window () dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle) dev_display (Image) * Image Acquisition 01: Code generated by Image Acquisiti…

dyld: Library not loaded: @rpath/libswiftCore.dylib 解决方法

解决&#xff1a; 设置Build Setting - > 搜索 embe关键字 -> 修改属性 见如下图&#xff1a; 如果更新了Xcode 8 这里变成&#xff1a; 转载于:https://www.cnblogs.com/yajunLi/p/5979621.html

Bootloader及u-boot简介/u-boot系统启动流程

Bootloader及u-boot简介Bootloader代码是芯片复位后进入操作系统之前执行的一段代码&#xff0c;主要用于完成由硬件启动到操作系统启动的过渡&#xff0c;从而为操作系统提供基本的运行环境&#xff0c;如初始化CPU、堆栈、存储器系统等。Bootloader 代码与CPU 芯片的内核结构…

Dubbo之RPC架构

为什么会有dubbo的出现: 随着互联网的发展&#xff0c;网站应用的规模不断扩大&#xff0c;常规的垂直应用架构已无法应对&#xff0c;分布式服务架构以及流动计算架构势在必行&#xff0c;亟需一个治理系统确保架构有条不紊的演进。 单一应用架构 当网站流量很小时&#xff0c…

区域路由的注册机制

AreaRegistration.RegisterAllAreas() 我们新建一个名称为Admin的Area&#xff0c;VS生成下面的代码。 { action , id 我们先来看AreaRegistration这个抽象类&#xff0c;实际上&#xff0c;它只有一个核心功能&#xff0c;就是RegisterAllAreas&#xff0c;获取所有继承它的…

Unix/Linux IPC及线程间通信总结

一、互斥与同步 1.互斥&#xff1a;是指某一资源同时只允许一个访问者对其进行访问&#xff0c;具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序&#xff0c;即访问是无序的。 2.同步&#xff1a;是指在互斥的基础上&#xff08;大多数情况&#xff09;&#xff0…

CSS样式的插入方式

1.外部样式&#xff1a; 当样式需要应用于很多页面时&#xff0c;外部样式表将是理想的选择。<head><link rel"stylesheet" type"text/css" href"mystyle.css" /> </head> 2.内部样式 当单个文档需要特殊的样式时&#…

嵌入式Linux系统基础知识

一、嵌入式Linux系统的构成 1、硬件 2、内核 3、应用程序&#xff08;形成根文件系统&#xff09; 二、构建嵌入式Linux系统的主要任务 1、内核部分 2、应用程序部分 嵌入式Linux的开发大致可分为三个层次&#xff1a;引导装载内核、构造文件系统和图形用户界面。作为操作系统…

win10系统javac不是内部或外部命令,也不是可运行的程序 或批处理文件。

按照下面的步骤设置环境变量 说明&#xff1a; 1. 如果编辑的是系统环境变量&#xff0c;命令提示符需要以管理员权限运行&#xff1b;如果在用户环境变量中编辑&#xff0c;则当前用可直接运行命令提示符。 2. win10中的路径相对于win7要设置成绝对路径。 1&#xff0e;打开…

两个bat文件

1、修改后缀名 ren *.cs *.txt ren *.txt *.zip2、修改文件名称 echo offset a00setlocal EnableDelayedExpansionfor %%n in (*.txt) do (set /A a1ren "%%n" "!a!.txt")

各种排序笔记---基于比较排序部分

1. 选择排序 selection sort 大循环 从左到右每次以一个点开始扫描array 小循环 找到从当前起始点开始的最小值 时间复杂度为O(N^2) //selection sort an array array[] public class Solution {public int[] solve(int[] array) {if (array null || array.length 0) {return…

是什么让深度学习再次崛起并超越人类?

作者潘争&#xff0c;格灵深瞳计算机视觉工程师&#xff0c;清华大学自动化系博士&#xff0c;师从智能技术与系统国家重点实验室副主任张长水。深度学习(Deep Learning)这个词最近借着AlphaGO与李世石的人机大战又火了一把。深度学习其实是机器学习(Machine Learning)的一个分…

常见的流量问题

常见的流量问题 冗余内容同类请求被间隔执行&#xff0c;请求的内容包含一些相对静态的信息&#xff0c;正确的处理是第一次请求包括静态信息就好&#xff0c;后面的同类请求只包含必要的即时变化信息即可。错误的处理方式是每次请求服务器都返回一次静态信息。 冗余请求有的时…

halcon使用点拟合圆形时候,点集顺序紊乱,不影响圆形拟合效果

read_image (Image, 截图20201226094342972.bmp) * Matching 01: BEGIN of generated code for model initialization set_system (border_shape_models, false) * Matching 01: Obtain the model image * Matching 01: The image is assumed to be made available in the * Ma…

Socket理解。

其他大部分系统&#xff0c;例如CRM/CMS/权限框架/MIS之类的&#xff0c;无论怎么复杂&#xff0c;基本上都能够本地代码本地调试&#xff0c;性能也不太重要。&#xff08;也许这个就是.net的企业级开发的战略吧&#xff09; 可是来到通讯系统&#xff0c;一切变得困难复杂。原…

多元化时代敏捷软件开发的崛起与传统软件工程的延续

多元化时代敏捷软件开发的崛起与传统软件工程的延续 1.传统软件开发模式 1.1瀑布模型 1.1.1概念 瀑布模型&#xff0c;顾名思义&#xff0c;软件开发的过程如同瀑布飞流一般&#xff0c;自上而下&#xff0c;逐级下落。瀑布模型的核心思想是将问题按照工序进行简化&#xff0c;…

Linux中的cron计划任务配置详解

cron来源于希腊单词chronos&#xff08;意为“时间”&#xff09;&#xff0c;指Linux系统下一个自动执行指定任务的程序&#xff08;计划任务&#xff09; ####1. crontab命令选项代码如下: #crontab -u <-l, -r, -e> -u指定一个用户 -l列出某个用户的任务计划 -r删除某…

new和delete

和 sizeof 类似&#xff0c;sizeof不是函数&#xff0c;它是一个操作符&#xff0c;它在编译期就完成了计算&#xff0c;在函数运行期间它已经是一个常数值了。 int a;sizeof(int) 4;sizeof(a) 4;sizeof a ——也是4 不需要括号&#xff01;此时要注意&#xff1a;sizeof in…