本章将学习如何创建、打开、读写和关闭文件,还将学习程序是如何处理目录的。现在开始用C语言进行编程。
本章涵盖:
1. 文件和设备 2. 系统调用 3. 库函数 4. 底层文件访问 5. 管理文件 6. 标准I/O 7. 格式化输入和输出 8. 文件和目录的维护
9. 扫描目录 10. 错误及其处理 11. /proc文件系统 12. 高级主题:fcntl和mmap
重点学会5个基本的函数 -- open、close、read、write、ioctl。
open:打开文件或设备
read:从打开的文件或设备里读数据
write:向文件或设备写数据
close:关闭文件或设备
ioctl:把控制信息传递给设备驱动程序
当程序运行时,一般有3个已经打开的文件描叙符:
0:标准输入
1:标准输出
2:标准错误
1.write 系统调用
原型:
#include <unistd.h>
size_t write (int fildes,const void *buf,size_t nbytes);
系统调用的作用:把缓冲区buf的前nbytes个字节写入与文件描叙符fildes关联的文件中。它返回实际写入的字节数。如果返回0,表示未写入任何数据;如果它返回的是-1,就表示在write调用中出现了错误,错误代码保存在全局变量errno里。
第一个程序write.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
if((write(1,"here is some data\n",18))!=18)
write(2,"a write error has occurred on file descriptor 1\n",46);
exit(0);
}
程序运行:
zhangxm@zhangxm:~/c_programmer$ gcc write.c -o write
zhangxm@zhangxm:~/c_programmer$ ./write
here is some data
2.read系统调用
原型:
#include<unistd.h>
size_t read(int fildes,void *buf,size_t nbytes);
系统调用read的作用:从与文件描叙符fildes相关的文件里读入nbytes个字节的数据,并把它们放到数据去buf中。它返回实际读入的字节数。如果read调用返回0,表示未读入任何数据,已达到文件尾。返回-1表示read调用出现了错误。
第一个程序read.c
#include <unistd.h>
#include <stdlib.h>
int main()
{
char buffer[128];
int nread;
nread = read(0,buffer,128);
if(nread == -1)
write(2,"a write error has occurred\n",26);
if((write(1,buffer,nread))!=nread)
write(2,"a write error has occurred\n",27);
exit(0);
}
程序运行:
zhangxm@zhangxm:~/c_programmer$ ./read
zhangxm
zhangxm
zhangxm@zhangxm:~/c_programmer$
3.open系统调用
原型:
#include <fcntl.h>
#include <sys/types.h>
#include <sys.stat.h>
int open(const char *path,int oflags);
int open(const char *path,int oflags,mode_t mode);
open系统调用的作用:open建立了一条到文件或设备的访问路径。如果调用成功,它将返回一个可以被read、write和其他系统调用使用的文件描叙符。open调用在成功时返回一个新的文件描述符,失败时返回-1。准备打开的文件或设备名字作为参数path传递给函数,oflags参数用于指定打开文件所采取的动作。oflags参数是通过必须文件访问模式与其他可选模式相结合的方式来指定的。可选模式如下:
O_RDONLY 以只读方式打开
O_WRINLY 以只写方式打开
O_RDWR 以读写方式打开
还有如下组合(可“按位或”操作):
O_APPEND:将写入数据追加在文件的末尾
O_TRUNC: 把文件长度设置为零,丢弃已有的内容
O_EXCL: 与O_CREAT一起使用,确保调用者创建文件
O_CREAT: 如果需要,就按参数mode中给出的访问模式创建文件
当你使用带有O_CREAT标志的open调用来创建文件时,你必须使用有3个参数格式的open调用。第三个参数mode是几个标志按位或后得到的,这些标志在头文件sys.stat.h中定义,如下所示:
S_IRUSR:读权限,文件属主。
S_IWUSR:写权限,文件属主。
S_IXUSR:执行权限,文件属主。
S_IRGRP:读权限,文件属组。
S_IWGRP:写权限,文件属组。
S_IXGRP:执行权限,文件属组。
S_IROTH:读权限,其他用户。
S_IWOTH:写权限,其他用户。
S_IXOTH:执行权限,其他用户。
第一个程序open.c
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int n,m;
char buffer[100];
if((n = open("./test",O_RDWR|O_APPEND)) != -1)
write(1,"right!\n",7); //打开成功
else
{
write(0,"error!\n",7);
exit(0);
}
write(n,"right!\n",7); //将right写在./test文件的末尾
m = read(0,buffer,100); //将标准输入读入buf中
write(n,buffer,100); //将buffer中的内容写入文件描叙符为n的文件中
exit(0);
}
程序结果:
zhangxm@zhangxm:~/c_programmer$ gcc open.c -o open
zhangxm@zhangxm:~/c_programmer$ ./open
right!
zhangxm
zhangxm@zhangxm:~/c_programmer$ vi test
test文件之前内容:
nihao woshi test
test文件操作之后内容:
nihao woshi test
right!
zhangxm
u<82>^D^H^@^@^@^@ÿÿÿÿ^A^@^@^@<98>+W·Xèr·ýó¯¿^@`q·<90><85>^D^H°<83>^D^H^@^@^@^@^Y<83>^D^Häcq·^A^@^@^@^@ ^D^Hâ<85>^D^H^A^@^@^@D毿L毿U<9a>Y·ðõs·^@^@^@^@<9b><85>^D^H
注:后面的乱码是因为buffer有100个字节而只读了7个字节,后面的字节就成了乱码(我猜的)。可以将最后第二句write()内的100改为m。
4.close系统调用
原型:
#include <unistd.h>
int close(int fildes);
close系统调用作用:使用close调用终止文件描述符fildes与其对应文件之间的关联。文件描述符被释放并能够重新使用。调用成功时返回0,出错时返回-1.
5.ioctl系统调用
原型:
#include <unistd.h>
int ioctl(int fildes,int cmd,...);
ioctl系统调用的作用:它提供了一个用于控制设备及其描述符行为和配置底层服务的借口。终端、套接甚至磁带机都可以有为它们定义的ioctl。ioctl对描述符fildes引用的对象执行cmd参数中给出的操作。
6.其它与文件管理相关的系统调用
lseek系统调用 fstat、stat、lstat系统调用 dup和dup2系统调用