前言
在linux系统编程中,我们经常会使用到输入和输出函数,其中涉及带缓冲区的输入输出和不带缓冲区的输出输出函数,他们的作用各不相同,本文主要讨论不带缓冲区的输入输出函数,并介绍他们在读取文件的过程中,文件的偏移量是如何进行变化的。
一、不带缓冲区的输入输出函数是指什么?
不带缓冲区的输入函数是指read函数,不带缓冲区的输出函数是指write函数,当文件被open函数打开时,我们如果需要从该文件中读取数据则可以使用read函数,如果需要写入数据到该文件中,我们可以使用write函数,具体的函数原型如下。
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
//注:成功返回值为读到的字节数,如果到了文件末尾则返回0;出错返回-1
ssize_t write(int fd, const void *buf, size_t count);
//注:成功返回值为已写的字节数;出错返回-1
ssize_t为带符号的整形数据。
二、read函数的读取机制是什么?
当某个文件被open打开时,我们使用read函数从该文件中读取一段小于文件长度的数据时,read函数将从当前文件的偏移量处开始进行读取数据,在read函数成功返回前,该文件的偏移量被操作,偏移量会增加实际已被读取到的字节数,随后read返回实际读取到的字节数。
三、write函数的写入机制是什么?
同理,当某个文件被open打开时,我们使用write函数将一段数据从当前文件偏移量开始写入,随后write返回实际写入的字节数;当使用open函数指定从文件尾开始追加时,则在每次写入之前,先操作文件的偏移量至文件末尾,再从当前文件偏移量出写入该数据,随后write返回实际写入的字节数。
四、如何连续使用read函数?
当使用read函数当作通信类读取接口时,假设本地设备为主机,远程设备为从机,此时从机连续不间断地向主机发送数据,作为主机,需源源不断地被动从从机读取数据,
while(有数据到来时)
{
实际的字节数= read(设备的文件描述符,读数据缓存区+累计字节数,预计单次能读取的字节数);
if(实际的字节数 == 0||实际的字节数 == -1)
break;
累加的字节数+=实际的字节数;
}
当有数据到来时,初始的累计字节数和实际的字节数被清零处理,第一次调用read函数时,将读取到的实际数据存储到缓存区中,由于初始时累计字节数为0,所以读到的数据从存储区初始位置开始填充;当一段数据被分成多次发送时,第二次调用read函数则会将读到的实际数据存储到存储区,且存储的位置为存储区向后偏移累加的字节数的位置开始存储数据,以此完成第二段数据的拼接过程,之后的第三段、第四段数据因此能够顺利的全部存储在指定的存储区中;当读取到的数据返回值为0时,表明数据已被读取完毕,此次结束并退出循环操作。
这样就可以完整的获取一段分散发送的数据了。
五、如何连续使用write函数?
当使用write函数写入通信类接口时,假设本地设备为主机,远程设备为从机,此时主机主动向从机发送数据:
while(剩余缓存区的长度大于0)
{
if(剩余缓存区的长度小于预计单次能发送的字节数)
{
实际写入的字节数= write(设备的文件描述符,待发送缓冲区+累计字节数,剩余缓存区的长度);
}
else
{
实际写入的字节数= write(设备的文件描述符,待发送缓冲区+累计字节数,预计单次能发送的字节数);
}
if(实际写入的字节数 == -1)
break;
累加的字节数+=实际写入的字节数;
剩余缓存区的长度 = 缓存区的长度 - 累加的字节数;
}
当缓存区的长度大于0时,初始的累计字节数和实际写入的字节数被清零处理,剩余缓存区长度为缓存区的实际数据长度,假设剩余缓存区长度大于预计单次能发送的字节数,第一次调用write函数时,将缓存区预计单次能发送的字节数发送出去,由于初始时累计字节数为0,所以发送的数据从存储区初始位置开始发送;当一段数据被分成多次发送时,且此时剩余缓存区的长度小于单次预计能发送的字节数。则第二次调用write函数会发送剩余缓存区的长度,当剩余缓存区的长度为0时,表明数据已被发送完毕,此次结束并退出循环操作。
这样就可以完整的发送一段分散发送的数据了。
总结
例如:以上就是今天要讲的内容,本文仅仅简单介绍了read和write函数的一些使用机制,涉及偏移量移动的一些细节知识以及连续使用的一些知识对其作了一番简单介绍和引用。