文件操作
文件系统简介
基于文件描述符的I/O操作是通过文件描述符对一个文件执行I/O操作的。通常外存中的数据都是以文件的形式保存的。
文件描述符是用于描述被打开文件的索引值。通常,是通过文件描述符打开一个文件执行I/O操作的;
文件
每个文件都有特定的属性,Linux系统文件属性比较复杂,主要包括文件类型和文件权限;
文件类型
Linux下文件可分为5中类型:普通、目录、链接、设备、管道文件;
普通文件按内部结构细分文本文件如图形、数据、文档等和二进制文件;
目录文件用于存放文件名及其相关信息的文件,是内核组织文件系统的基本结点,其包含下一级目录文件或普通文件;
链接文件是一种特殊的文件,实际上是指向一个真实存在的文件的链接。如用户需要在一目录下使用其他目录的文件,不需要复制过来,只需建立一个链接文件指向所调用的文件;细分为硬链接文件和符号链接文件,使用命令In创建链接文件;
设备文件是Linux中最特殊的文件,使得Linux系统可很方便的访问外部设备,系统为外部设备提供一种标准接口,将外部设别视为一种特殊的文件,可像访问普通文件一样访问设备文件,一般访问/dev目录下;使用设备的主设备号和次设备号来指定某外部设备;前者说明设备类型后者说明具体设备。
管道文件用于不同进程间的信息传递。当两个进程间需要数据或信息传递时,可通过管道文件;一个进程将需要传递的数据或信息写入管道的一端,另一进程则从管道的另一端取得所需的数据或信息,通常管道是建立在高速缓存中的,可细分为有名管道和匿名管道。
文件权限
Linux是一个多用户系统,不同的用户处于不同的地位,保护系统安全,系统对不同用户访问同一文件的权限做了不同的规定。
文件权限分为3种:读的权限、写的权限和执行的权限,分别用r、w、x表示;其中管理员root用户对系统具有最高的控制权。
文件的相关信息
相关信息是文件的目录结构、索引节点和文件数据本身;
文件目录结构
系统每一个目录都处于一定的目录结构中,该结构含有目录中所有的目录项的列表,每一个目录项都包含有一个名称和索引节点。应用程序根据名称访问目录项的内容,而索引节点则提供了所需引用文件自身的信息。
索引节点
所有文件都有一个与之相连的索引节点(inode)。索引节点用来保存文件信息,索引节点信息如下:
文件设备号、索引节点号、文件访问权限、文件连接的数量、所有者用户识别号、组识别号、以字节为单位的文件容量、文件的磁盘块的大小、文件所占的磁盘块、访问、修改文件的时间;
系统中使用stat结构体来存放这些信息。
struct stat
{
dev_t st_dev; /*device*/
ino_t st_in1; /*inode*/
mode_t st_mode; /*projection*/
nlink_t st_nlink; /*numbers of hard links*/
uid_t st_uid; /*user ID of owner*/
gid_t st_gid; /*group ID of owner*/
dev_t st_rdevl /*device type (if inode device)*/
off_t st_size; /*total size,in bytes*/
unsigned long st_blksize; /*blocksize for filesystem*/
unsigned long st_blocks; /*number of blocks allocated*/
time_t st_atime; /*time of last access*/
time_t st_mtime; /*time of last modification*/
time_t st_ctime; /*time of last change*/
};
可通过系统调用访问stat结构来获取索引节点的相关信息;
st_dev:对应每一文件名,代表包含该文件名和相应的索引节点的文件系统的设备号。
st_rdev:对应字符设备文件或块设备文件,表示实际设备的设备号;
数据
普通文件和目录文件都有相应的硬盘区域存储数据,该数据是存储有索引节点指定的位置上,而一些特殊文件如设备文件,不具有这样的在硬盘上的存储区域。
文件系统
指按一定规律组织起来的有序的文件组织结构,是构成系统中所有数据的基础。Linux系统提供的文件系统是树形的层次结构系统,所有文件最终都归结到根目录"/"上。linux支持多种文件系统,最通用的是ext3系统,根据需要自行选择。
基于文件描述符的I/O操作
它是Linux系统I/O操作的一种,在进行I/O操作时使用文件描述符与文件建立连接。文件描述符是一个整数,是用于描述符被打开文件索引值的;指向该文件的相关信息记录表;
文件创建、打开、关闭
对一个文件操作时,要求该文件存在,齐次要将文件打开;操作完成后,则必须将文件关闭;
1、文件创建
使用系统调用create创建文件,
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int create(const char *pathname, mode_t mode)
其中,参数pathname是一个字符串指针,用于表示需要打开文件的绝对路径名或相对路径名。参数mode用于指定所创建文件的权限,取值即含义见下表,可按位逻辑加方法组合使用
mode取值 | 含义asdfasdfasdf |
S_IRUSR | 文件所有者读权限位 |
S_IWUSR | 文件所有者写权限位 |
S_IXUSR | 文件所有者执行权限位 |
S_IRGRP | 所有者同组用户读权限位 |
S_IWGRP | 所有者同组用户写权限位 |
S_IXGRP | 所有者同组用户执行权限位 |
S_IROTH | 其他用户读权限位 |
S_IWOTH | 其他用户写权限位 |
S_IXOTH | 其他用户执行权限位 |
定了常用的逻辑组合
S_IRWXU:(S_RUSER|S_WUSER|S_XUSER)
文件打开
系统调用open用于打开文件,
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags,mode_t mode);
参数flags用于描述文件打开的参数,见表所示,也可按位逻辑加方法组合
flags取值 | 含义 |
O_RDONLY | 以只读方法打开文件 |
O_WDONLY | 以只写方法打开文件 |
O_RDWR | 以读写方法打开文件 |
O_CREAT | 若文件不存在则创建 |
O_EXCL | 打开文件设置O_CREAT且文件存在则调用失败 |
O_NOCTTY | 打开tty时进程没有控制tty则不控制终端 |
O_TRUNC | 以只写或读写方式打开一个已存在文件时,文件截止0 |
O_APPEND | 向文件添加内容时将指针置于文件末尾 |
O_NOBLOCK | 用于非阻塞套接口I/O,操作不能无延迟完成则操作前返回 |
O_NODELAY | 同O_NOBLOCK |
O_SYNC | 只在数据被写入外存或其他设别后操作才返回 |
调试成功时,系统调用open的返回值为所打开文件的描述符,调用失败则返回-1,并置errno为相应错误编号。
注:在执行文件操作时,不能保证调用总是成功返回的,所以在调用create函数,open函数以及其他用于文件操作的函数时,都需要检测是否发生错误,并在发生错误时终止程序。
文件打开操作示例
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unsitd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int write_open(const char *pathname, mode_t mode){
int retval;
if((retval = open(pathname,O_WRONLY|O_CREAT|O_TRUNC,mode) == -1)){
printf("ERRPR,OPEN FILE FAILED!\n");
exit(254);
}
return retval;
}
int main(){
return write_open("test.txt",0600);
}
以只读方式打开某个文件的函数,若该文件不存在,则创建次文件,若存在,则将文件长度截至0。
文件关闭
使用系统调用close,具体如下
#include <unistd.h>
int close(int fd);
参数fd是虚关闭文件的描述符;
调用成功时,返回值为0;调用失败时,返回值为-1,并设置errno为EBADF。表示关闭的不是一个有效、已打开的文件描述符;
打开文件,该文件描述符的引用计数器被加1,关闭时减1;当引用计数器的值减至0,close释放该文件的描述符和改文件所占的描述符表项;
注:当关闭的不是一个普通文件时,会产生其他影响,如在关闭管道文件的一端时,将影响到管道的另一端;
文件读写
文件读写是I/O操作的核心内容,使用系统调用read、write实现文件的I/O操作。
#include <unistd.h>
ssize_t write(int fd,void fd,void *buf,size_t count);
其中参数fd表示需要进行写操作的文件被打开时返回文件描述符。buf是一个指向缓冲区的指针,该指针在指向存放将写入文件的数据的缓冲区。count表示本次操作所要写入文件的数据的字节数;调用成功时返回值为所写入的字节数,失败返回-1,同时将errno设置为相应值。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unsitd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NEWFILE (O_WRONLY|O_CREAT|O_TRUNC)
#define SIZE 80
#define BUFSIZE 50
int my_write(int fd,char *buf,size_t count);
char write_buf[BUFSIZE];
int write_offset = 0;
int main(void){
int outfile;
char filename[] = {"test.dat"};
char buffer[SIZE];
if((outfile = open(filename,NEFILE,0640))== -1 )
{
printf("ERROR,OPEN FILE FAILED!\n");
exit(255);
}
gets(buffer);
while(strcmp(buffer,"quit")){
if(my_write(outfile,buffer,strlen(buffer))== -1){
printf("ERROR,OPEN FILE FAILED:!\n",sys_errlist[errno]);
exit(255);
}
gets(buffer);
}
close(outfile);
return 0;
}
int my_write(int fd,char *buf,size_t count)
{
int i,n;
for(i=0;i<count;i++){
write_buf[write_offset] = *buf++;
/*按*/
if(write_offset == BUFSIZE)
{
write_offset = 0;
n = write(fd,write_buf,sizeof(write_buf));
if(n!= BUFSIZE)
return -1;
}
}
return 0;
}
创建test.dat文件,从终端输入若干字符串写入文件,直至输入字符串“quit”时结束。
读文件系统调用
#include <unistd.h>
ssize_t read(int fd,void fd,void *buf,size_t count);
count表示本次操作希望读取的字节数0,注意:count代表希望读取的字节数,实际读取的可能小于count;
示例
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unsitd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define NEWFILE (O_WRONLY|O_CREAT|O_TRUNC)
#define BUFSIZE 1024
#define size 1
int my_read(int fd,char *buf,size_t count);
int my_write(int fd,char *buf,size_t count);
static char read_buf[BUFSIZE];
static int read_offset = BUFSIZE;
static int read_max = BUFSIZE;
static char write_buf[BUFSIZE];
static int write_offset = 0;
int main(void){
/*初始化变量:文件名、文件描述符,计数*/
char infile[] = {"test.dat"};
char outfile[] = {"backup.dat"};
char buf[size];
int infd,outfd,count;
/*==运算符的优先级高于=,所以fd=open("test.hole",NEWFILE,0600)一定要加圆括号,否则fd=0,会输出到标准输出设备上*/
if((fd = open(outfile,NEWFILE,0600))== -1){
printf("ERROR,OPEN READ FILE FAILED: \n",sys_errlist[errno]);
exit(255);
}
if((outfd=open(outfile,NEWFILE,0600))== -1){
printf("ERROR,OPEN READ FILE FAILED: \n",sys_errlist[errno]);
exit(255);
}
while(count = read(infd,buf,sizeof(buf))>0){
if(write(outfd,buf,count)!=count){
printf("ERROR,OPEN READ FILE FAILED: \n",sys_errlist[errno]);
exit(255);
}
}
if(count == -1){
printf("ERROR,OPEN READ FILE FAILED: \n",sys_errlist[errno]);
exit(255);
}
close(infd);
if(write_offset >0){
write(outfd,write_buf,write_offset);
write_offset = 0;
}
close(outfd);
}
int my_read(int fd,char *buf,size_t count){
int i;
for(i = 0;i<count;++i){
if(read_offset == read_max){
read_offset = 0;
read_max = read(fd,read_buf,sizeof(read_buf));
if(!read_max)
return i;
}
*buf++ = read_buf[read_offset++];
}
return i;
}
int my_write(int fd,char *buf,size_t count){
int i,n;
for(i = 0;i<count;++i){
write_buf[write_offset++]=*buf++;
if(write_offset == BUFSIZE){
write_offset = 0;
n = write(fd,write_buf,sizeof(write_buf));
if(n!=BUFSIZE)
return i;
}
}
return -1;
}
将文件test.dat中内容复制到backup.dat文件中,程序中使用了1024字节的缓冲区,以减少系统调用的次数。
sdf