今天来继续学习文件操作的相关API。早上查了下资料,发现现在学的这些API隶属于POSIX标准,POSIX翻译过来就是可移植操作系统接口,在UNIX类系统中应用的十分广泛。处理文件的API还有很多别的标准,比如ANSI C标准,它应该是标准C语言提供的库函数。在别人的文章中看到,这二者比较起来的话,POSIX应该是更底层的代码,而ANSI C是较为上层的代码。换言之,你在Linux中使用后者的某个函数来操作文件,极有可能就是间接或者直接调用了前者中的对应函数。
1. read函数
这个函数与write函数的功能正好相反,各参数的功能也可以类比来记忆:
A)返回值是有符号整型,代表实际读取到了几个字符
B)第一个参数是目标文件的句柄
C)第二个参数是未指定类型的指针,其实就是某个缓冲区域的首地址,将来用来存放读取的数据
D)第三个参数是希望读取的字节数
2. read函数使用体验
A)与write函数类似,read函数也存在对同一个文件多次读取的情况。经过测试,确实还是像前者一样,一旦打开了一个文件。只要不关闭它,并且使用相同的文件句柄,本次读取就会在上一次末尾的地方自动接续。
B)确实像教材中说的那样,如果文本中有6个字符,而你却一次性要求读取10个,那么返回值会告诉你,只能读出6个。
C)如果经过上次读取操作,已经读完了文本中的内容,你却还要继续读取,那么返回值会告诉你,已经见底了。
D)在测试中发现一个有趣的现象,用write函数手写的文件,和自己用vi编辑器手写的文件有区别。同样都是输入abcdef这6个字符,用write函数写入什么就是什么;用vi编辑器写入,看起来好像也只有这6个字符。再用read函数去读取并且用printf函数打印出来的时候就能看到,后者还多了个空格:
注:上图中printf函数通过参数配置为右对齐显示10个字符。
3. 贴上这部分的测试代码
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdio.h> //为了能运行printf函数所添加的头文件
int main(int argc, char* argv[])
{
int fd1=-1;
int fd2=-1;
int res=0;
char buf1[10];
char buf2[10];
char buf3[10];
/************************打开文件file1,获取句柄****************************/
fd1 = open("file1.txt", O_RDWR);
if (fd1 < 0)
printf("open file1 failed!\n");
else
{
printf("open file1 success!\n");
printf("file1 's fd is %d\n",fd1);
}
/******************从文件file1读取数据到buf1*******************/
res = read(fd1, buf1, 10);
if (res == 0)
printf("read file1 to the end!\n");
else if (res <= -1)
printf("read file1 failed!\n");
else
{
printf("read %d bytes form file1 !\n",res);
printf("%10s\n\n",buf1);
}
/************************打开文件file2,获取句柄****************************/
fd2 = open("file2.txt", O_RDWR);
if (fd2 < 0)
printf("open file2 failed!\n");
else
{
printf("open file2 success!\n");
printf("file2 's fd is %d\n",fd2);
}
/******************从文件file2读取数据到buf2*******************/
res = read(fd2, buf2, 10);
if (res == 0)
printf("read file2 to the end!\n");
else if (res <= -1)
printf("read file2 failed!\n");
else
{
printf("read %d bytes form file2 !\n",res);
printf("%10s\n",buf2);
}
close(fd1);
close(fd2);
return 0;
}
4. close函数
这个函数与open相对应,用法十分简单。
A)返回值是有符号整型数据,只有两种可能:0代表正常关闭,-1代表失败
B)只有一个参数,文件句柄
5. 一些有意思的细节
当我们对文件进行读操作的时候,往往一次不会全部读出来。比如一个文件中有10个字符,我一次只读5个字符。完事以后还想把它打印出来显示一下。我采用的方法是:
printf("They are %5s",buf);
这种方法指定打印缓冲区5个字符,并且右对齐。我在教材上看到另一种做法:
res = read(fd, buf, 5);
buf[res]='\0';
在read之后,立即给buf手动加上一个字符串结束标志的'\0',这样再用printf的时候就不用指定显示几个字符了。碰到字符串结束标志的时候,printf知道见好就收~
这种方法的好处在于,有时候你根本不知道能读出几个字符,,这时候还怎么指定?另外,而res能够忠实的反馈到底读出来几个字符。因此buf[res]='\0'; 这种方法能保证'\0'正好加在最后一个有效字符的后面。