[Linux C编程]文件操作

文件操作

1.什么是系统调用?

  所谓系统调用是指操作系统提供给用户的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。

2.为什么用户程序不能直接访问系统内核提供的服务呢?

  由于在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。

  因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。

3.什么是文件?linux如何看待文件?

Linux一点哲学,“一切皆为文件”;在Linux中对目录和设备的操作都等同于对文件的操作,都是使用文件描述符来进行的。

Linux文件可分为:普通文件,目录文件,链接文件,设备文件

4.什么是文件描述符?Linux内核如何分配描述符?

  文件描述符是一个非负的整数,它是一个索引值,并指向内核中每个进程打开文件的记录表。

  当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符作为参数传递给相应的函数。

  一个进程启动时,都会打开3个文件:标准输入、标准输出和标准出错处理。

 

5.系统调用API

(1) creat

函数的作用: 创建一个文件;

函数的原型: int  creat(const char *pathname, mode_t mode);

filename:创建的文件名(包含路径,缺省为当前路径)

mode:创建模式:S_IRUSR   可读

          S_IWUSR   可写

          S_IXUSR    可执行

          S_IXRWU   可读可写可执行

(除用以上宏来选择创建模式,也可以用数字来表示,如0755)

文件头:  #include <sys/types.h>

       #include <sys/stat.h>

       #include <fcntl.h>

返回值:成功:新的文件描述符;

     出错:  -1

(2) open

函数的作用:打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数;

函数的原型:

int  open(const char *pahtname, int flags);

int  open(const char *pahtname, int flags, mode_t mode);

返回值:文件描述符---成功;出错:-1;

flags:

参数: O_RDONLY:只读打开

     O_WRONLY:只写打开

     O_RDWR:读、写打开

     O_CREAT:如果此文件不存在则创建它,使用此选项时,需同时说明第三个参数

mode,用其说明该新文件的存取权限;

O_NONBLOCK:如果path name指的是一个块特殊文件或一个字符特殊文件,则此选

择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。

      O_APPEND:原来有内容,则会自动保留文件内容,自动向下读写;

      O_TRUNC:  文件存在,有内容,文件清空;

(3)read

函数的作用:从打开的文件中读取count个字节数据到buf所指向的缓冲区中。

函数的原型:ssize_t  read(int fd, void *buf,  size_t count);

包含的头文件: #include  <unistd.h>

返回值:正常是实际读到的字节数;

     如果是在文件结束或者是无数据,返回0;

     出错,-1;

(4)write

函数的作用: 把count个字节从buf所指向的缓冲区中写到文件描述符fd所指向的文件中

函数的原型: ssize_t   write(int fd, const void *buf, size_t count);

头文件:  #include <unistd.h>    

返回值:  成功会返回实际写入的字节数;

       出错:-1;

(5)lseek

函数的功能:将文件读写指针相对whence移动offset个字节。

函数的原型:int lseek(int fd, offset_t  offset, int whence);

函数的参数:offset: 指针的微调,在指定的指针向前移动为负, 向后为正;

        whence:  SEEK_SET:放在文件头

               SEEK_CUR:当前的位置;

               SEEK_END:  文件尾;

返回值:返回文件当前指针到文件开始的地方有多少字节;

    出错-1;

6.标准库函数

C库函数的文件操作是独立于具体的操作系统平台的。

7.什么是不带缓存I/O操作?什么是带缓存I/O操作?

不带缓存的I/O是对文件描述符操作,带缓存的I/O是针对流的。

标准I/O库就是带缓存的I/O,它由ANSI C标准说明。当然,标准I/O最终都会调用上面的I/O例程。

标准I/O库代替用户处理很多细节,比如缓存分配、以优化长度执行I/O等。

标准I/O提供缓存的目的就是减少调用read和write的次数,它对每个I/O流自动进行缓存管理(标准I/O函数通常调用malloc来分配缓存)。

它提供了三种类型的缓存:
1) 全缓存。当填满标准I/O缓存后才执行I/O操作。磁盘上的文件通常是全缓存的。
2) 行缓存。当输入输出遇到新行符或缓存满时,才由标准I/O库执行实际I/O操作。stdin、stdout通常是行缓存的。

3) 无缓存。相当于read、write了。stderr通常是无缓存的,因为它必须尽快输出。

一般而言,由系统选择缓存的长度,并自动分配。标准I/O库在关闭流的时候自动释放缓存。

在标准I/O库中,一个效率不高的不足之处是需要复制的数据量。

当使用每次一行函数fgets和fputs时,通常需要复制两次数据:

第一次是在内核和标准I/O缓存之间(当调用read和write时),

第二次是在标准I/O缓存(通常系统分配和管理)和用户程序中的行缓存(fgets的参数就需要一个用户行缓存指针)之间。

8.库函数

(1)fopen

函数的作用: 打开文件

函数的原型: FILE *fopen(const char *pth, const char *mode)

mode:  r:读,文件必须存在;

     r+:打开可读写,文件必须存在;

     w:打开只写文件,文件不存在就会创建文件; 文件清0;

     w+:打开可读写的文件,

     a:附加的形式打开只写文件,不存在就创建,存在就写到原来的文件尾。

     a+:以附加的形式打开可读写的文件,不存在就创建,存在就写到原来的文件尾。

     b:二进制文件

 头文件: #include <stdio.h>

 返回值: 成功是指向=文件流的指针;

       出错返回NULL;     

(2)fclose

函数的作用:关闭先前fopen()打开的文件,会将缓冲区内的数据写入文件中,并释放系统所提供的文件资源返回值。

函数的原型:int fclose(FILE * stream);

头文件:#include<stdio.h>

返回值:若关动作成功则返回0

     出错返回EOF并把错误代码存到errno.

 

注:对文件的读和写是最常用的文件操作。在Linux C中提供了多种文件读写的函数

字符读写函数:fgetc和fputc

字符串读写函数:fgets和fputs

数据块读写函数:fread和fwrite

格式化读写函数:fscanf和fprintf

(3)fputc

函数的作用:  将一个指定的字符写入到文件流中;

函数的原型:  int fputc(int c, FILE *stream);

返回值:   返回写入成功的字符,c;  EOF则表示失败。

(4)fgetc

函数的作用:从文件流中读取一个字符

函数原型: int fgetc(FILE *stream)

返回值:返回值正常的是读取的字符;EOF表示到了文件尾;

(5)fputs

函数的作用:将一个字符串写入到文件内

函数的原型: int fputs(const char *s, FILE *stream)

返回值:成功返回写成字符数; EOF表示出错

(6)fgets

函数的作用:从文件中读取一个字符串;

函数的原型:char *fgets(char *s, int size,  FILE *steam)

函数的说明:fgets()用来从参数stream所指的文件内读入字符并存到参数s所指的内存空间中,知道出现换行字符、读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束。

返回值: 成功返回s, 出错NULL。

(7)fread

函数的作用:从文件流中读取数据块

函数原型:size_t  fread(void *ptr,  size_t size, size_t  nmemb, FILE * stream);

函数参数:stream为已打开的文件指针

      ptr:指向欲存放读取进来的数据空间

      读取的字符数以参数nmemb来觉得

返回值:返回实际读到数据块的数目

     比nmember小的话,可能是到了文件尾,或者错误发生。

     feof() :到文件尾;

     ferror():判断错误的

(8) fwrite

函数的作用:将数据块写到文件流中:

函数原型: size_t  fwrite(const void * ptr,  size_t size,  size_t nmemb,  FILE *stream);

函数参数:stream为已打开的文件指针,

       ptr:指向欲写入的数据地址,总共写入的字符数以参数nmemb来决定

返回值: 实际写入的nmemb数目;

(9)fprintf

函数的作用:格式化数据到文件

函数的原型: int fprintf(FILE *stream, const char *format, ....);

返回值:成功返回实际输入的字符数,失败-1;

(10)fscanf

函数的作用: 格式化字符串输入

函数的原型: int fscanf(FILE *strem, const char *fromat,....)

返回值:成功返回参数数目,出错-1

(11)fseek

函数的作用:移动文件流的读写位置

函数的原型: int fseek(FILE * stream, long offset, int whence)

返回值:成功返回0, 出错-1;

(12)ftell

函数的作用:读取文件流的读写位置;

函数的原型:long ftell(FILE * stream)

返回值: 成功返回当前的读写位置;

      出错-1;

(13)feof

函数的作用: 检测文件流是否到了文件尾

函数的原型:int feof(FILE *steam)

返回值:  非零代表到了文件尾,其他是0;

 

9.带缓存的I/O操作如何完成文件的复制?

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> 

#define BUFFER_SIZE 1024 

int main(int argc,char *argv[]) 
{ 
		int from_fd,to_fd; 
		int bytes_read,	bytes_write; 
		char buffer[BUFFER_SIZE]; 
		char *ptr; 

		if(argc!=3) 
		{ 
			fprintf(stderr,"Usage:%s fromfile tofile/n/a",argv[0]); 
			exit(1); 
		} 
		if((from_fd=open(argv[1],O_RDONLY))==-1) 
		{ 
			fprintf(stderr,"Open %s Error:%s/n",argv[1], strerror(errno)); 
			exit(1); 
		} 
		if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1) 
		{ 
				fprintf(stderr,"Open %s Error:%s/n",argv[2],strerror(errno)); 
				exit(1); 
		} 
		while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)) 
		{ 
	
			if((bytes_read==-1)&&(errno!=EINTR))  	/* 一个致命的错误发生了 */ 
				break; 
			else if(bytes_read>0) 
			{ 
				ptr=buffer; 
				while(bytes_write=write(to_fd,ptr,bytes_read)) 
				{ 
					if((bytes_write==-1)&&(errno!=EINTR))      /* 一个致命错误发生了 */ 
						break; 
					else if(bytes_write==bytes_read)           /* 写完了所有读的字节 */ 
					        break; 
					/* 只写了一部分,继续写 */ 
		 			else if(bytes_write>0) 
					{ 
						ptr+=bytes_write; 
						bytes_read-=bytes_write; 
					} 
				} 
				/* 写的时候发生的致命错误 */ 
				if(bytes_write==-1)
					break; 

			} 
		} 

		close(from_fd); 
		close(to_fd); 
		exit(0); 
} 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
//1.创建文件file1,写入字符串“abcdefghijklmn”; //2.创建文件file2,写入字符串“ABCDEFGHIJKLMN”; //3.读取file1中的内容,写入file2,使file2中的字符串内容为“abcdefghijklmn ABCDEFGHIJKLMN” 创建新文件,该文件具有用户读写权限。 //2.采用dup/dup2/fcntl复制一个新的文件描述符,通过新文件描述符向文件写入“class_name”字符串; //3.通过原有的文件描述符读取文件中的内容,并且打印显示; 1.输入文件名称,能够判断文件类型,判断实际用户对该文件具有哪些存取权限; ?2.要求打印出文件类型信息,inode节点编号,链接数目,用户id,组id,文件大小信息; ?3.修改文件的权限为当前用户读写,组内用户读写,组外用户无权限 新建文件,设置文件权限屏蔽字为0; 2.建立该文件的硬链接文件,打印硬链接文件的inode节点号和文件大小; ? 3.建立该文件的软链接文件,打印软链接文件的inode节点号和文件大小;打印软链接文件中的内容; 4.打印源文件的inode节点号,文件大小和链接数目; ? 5.调用unlink对源文件进行操作,打印源文件链接数目; .新建/home/user目录; 2.把当前工作路径移至/home/user目录; 3.打印当前工作路径; ?编写程序完成以下功能: ?1.递归遍历/home目录,打印出所有文件和子目录名称及节点号。 ?2.判断文件类型,如果是子目录,继续进行递归遍历,直到遍历完所有子目录为止

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值