关于write和read以及文件读写位置

write

#include 
ssize_t write(int fd, const void *buf, size_t nbyte);

fd:文件描述符
buf:指定的缓冲区,即指针,指向一段内存单元
nbyte:要写入文件指定的字节数
返回值:写入文档的字节数(成功);-1(出错)
write函数把buf中nbyte写入文件描述符handle所指的文档,成功时返回写的字节数,错误时返回-1.

read

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

示例
const char * file = "hello,world\n";

int main()
{
    //int open(constchar*pathname,intflags);
    //int open(constchar*pathname,intflags,mode_tmode);
    //返回值:成功则返回文件描述符,否则返回-1
    int fd = open("myfile", O_RDWR | O_CREAT, 0664);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }


    char * msg = "world,hello\n";
    ssize_t sw = write(fd, msg, strlen(file));
    printf("sw = %d\n", sw);
    if(sw < 0)
    {
        perror("write");
        return -1;
    }
    printf("写入成功\n");

    char buf[13];
    ssize_t sr = read(fd, buf, 12);
    printf("sr = %d\n", sr);
    if( sr <= 0 )
    {
        perror("read error");
        return -1;
    }
    printf("读取成功\n");
    printf("buf = %s\n", buf);
    close(fd);
    return 0;
}

像这样, 在打开一个文件后, 用write写入, 然后立即用read读取, 此时read会返回0
因为此时文件的读取位置已经到了末尾
如何解决这个问题呢
有一个函数

lseek

#include
#include

off_t lseek(int filde,off_t offset ,int whence);

函数说明
每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。
当read()或write()时,读写位置会随之增加,lseek()便是用来控制文件读写位置的

  • 参数fildes 为已打开的文件描述词
  • 参数offset 为根据参数whence来移动读写位置的位移数

Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)

参数
whence为下列其中一种:(SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2).

  • SEEK_SET 将读写位置指向文件头后再增加offset个位移量。
  • SEEK_CUR 以目前的读写位置往后增加offset个位移量。
  • SEEK_END 将读写位置指向文件尾后再增加offset个位移量。

当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现。
下列是较特别的使用方式:

1) 欲将读写位置移到文件开头时: lseek(int fildes,0,SEEK_SET);
2) 欲将读写位置移到文件尾时: lseek(int fildes,0,SEEK_END);
3) 想要取得目前文件位置时: lseek(int fildes,0,SEEK_CUR);

返回值
当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。
若有错误则返回-1,errno 会存放错误代码。
可能设置erron的错误代码:

  • EBADF: fildes不是一个打开的文件描述符。
  • ESPIPE:文件描述符被分配到一个管道、套接字或FIFO。
  • EINVAL:whence取值不当。
#include
#include
#include
#include
#include
#include

ssize_t read(int fd, void * buf, size_t count);
//从fd里读取count大小的数据到buf中

//ssize_t write(int fd, const void *buf, size_t nbyte);
ssize_t write(int fd, const void * buf, size_t nbyte);
//把buf中的nbyte大小的数据写入fd

const char * file = "hello,world\n";

int main()
{
    //int open(constchar*pathname,intflags);
    //int open(constchar*pathname,intflags,mode_tmode);
    //返回值:成功则返回文件描述符,否则返回-1
    int fd = open("myfile", O_RDWR | O_CREAT, 0664);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }

    char * msg = "world,hello\n";
    ssize_t sw = write(fd, msg, strlen(file));
    printf("sw = %d\n", sw);
    if(sw < 0)
    {
        perror("write");
        return -1;
    }
    printf("写入成功\n");
    sleep(1);

    //off_t lseek(int filde,off_t offset ,int whence);
    //每一个已打开的文件都有一个读写位置,当打开文件时通常其读写位置是指向文件开头,
    //若是以附加的方式打开文件(如O_APPEND),则读写位置会指向文件尾。
    //当read()或write()时,读写位置会随之增加,lseek()便是用来控制该文件的读写位置。
    //参数fildes 为已打开的文件描述词,参数offset 为根据参数whence来移动读写位置的位移数。
    //Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)。
    lseek(fd, 0, SEEK_SET); //令读写位置指向开头

    char buf[13];
    //while(1)
    {
        ssize_t sr = read(fd, buf, 12);
        printf("sr = %d\n", sr);
        //ssize_t read(int handle, void *buf, int nbyte);
        if( sr <= 0 )
        {
            perror("read error");
            return -1;
        }
        printf("读取成功\n");
    }
    printf("buf = %s\n", buf);
    //close(fd);
    return 0;
}

关于write和read以及文件读写位置_第1张图片

你可能感兴趣的:(C,Linux)