文件操作

文件操作

文件系统简介

基于文件描述符的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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值