Linux系统编程(一)文件操作


  

一、知识点

  1. 文件类型
    Linux 中一切皆文件,对目录和设备的操作都是文件操作。文件分为普通文件管道文件目录文件链接文件设备文件
      ●普通文件:也称磁盘文件,并且能够进行随机的数据存储(能够自由 seek 定位到某一个位置);
      ●管道文件:是一个从一端发送数据,另一端接收数据的数据通道;
      ●目录文件:它包含了保存在目录中文件列表的简单文件。
      ●设备文件:Linux 下各种硬件设备都是文件,该类型的文件提供了大多数物理设备的接口。它又分为两种类型:字符型设备和块设备。字符型设备一次只能读出和写入一个字节的数据,包括调制解调器、终端、打印机、声卡以及鼠标;块设备必须以一定大小的块来读出或者写入数据,块设备包括 CD-ROM、RAM 驱动器和磁盘驱动器等,一般而言,字符设备用于传输数据,块设备用于存储数据。
    三大设备文件:字符设备、块设备、网络设备。
      ●套接字文件:在 Linux 中,套接字也可以当作文件来进行处理。
    对文件进行的操作有打开文件,关闭文件,读写文件。其中打开文件是第一步,是为后续操作做准备的。

  2. 打开文件时,第一个文件描述符号为3。
       系统为每个进程预先打开了三个特殊的文件,对应的三个文件指针分别为:stdin(标准输入)、stdout(标准输出)、stderr(标准出错)。定义在头文件<stdio.h>中。在进程一开始运行,就自动打开了三个对应设备的文件,它们是标准输入、输出、错误流,分别用全局文件指针 stdin、stdout、stderr 表示,它们都是 FILE *类型。所以当我们打开我们自己的第一个文件时,会发现该文件的描述符号为3(系统自动打开的标准流文件描述符分别为0、1、2),在同一个进程中又打开一个文件时,文件描述符以此类推。

  3. 文件光标。
       一般在文件写入内容后紧接着再读取文件数据时,键盘光标处于文件最后的位置,会读不到任何数据,需要将光标移动到文件最前面。使用lseek(int fd, off_t offset, int whence);函数移动光标到文件开头。

lseek(int fd, off_t offset, int whence);
		//  fd:       文件描述符
	//	  offset:   偏移量(可正可负)
		//  whence : 开始偏移的起始位置。可选如下参数:
		//            SEEK_SET:文件开头位置
		    //        SEEK_CUR:当前位置
		    //        SEEK_CUR:最后位置
//如:lseek(fd, 0, SEEK_SET);  //光标移动到文件开头
  1. 文件信息结构体
    stat 函数用于获取文件的状态信息,并将信息存储在 struct stat 结构中。函数原型如下:
#include <sys/stat.h>  //包含文件信息结构体等
//int stat(const char *path, struct stat *buf);
/*
struct stat {
        mode_t     st_mode;       //文件对应的模式,文件,目录等
        ino_t      st_ino;       //inode节点号
        dev_t      st_dev;        //设备号码
        dev_t      st_rdev;       //特殊设备号码
        nlink_t    st_nlink;      //文件的连接数
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者对应的组
        off_t      st_size;       //普通文件,对应的文件字节数 
        time_t     st_atime;      //文件最后被访问的时间
        time_t     st_mtime;      //文件内容最后被修改的时间
        time_t     st_ctime;      //文件状态改变时间
        blksize_t st_blksize;    //文件内容对应的块大小
        blkcnt_t   st_blocks;     //伟建内容对应的块数量
*/

struct stat fileinfo; //定义结构体变量。 
stat("example.txt", &fileinfo) //将example.txt的文件信息存储到fileinfo结构体中。
printf("%d\n",fileinfo.st_size) //获取文件的字节大小。

一、标准IO(标准IO库)

主要用于高级文件操作,支持格式化 I/O 操作。

1. 头文件

#include <unistd.h>  //open、read、write、fopen、fread等函数
#include <sys/types.h>  //文件权限等
#include <sys/stat.h>  //包含文件信息结构体等

2. 相关函数

(1)fopen:打开文件

  fopen 以 mode 的方式打开或创建文件,如果成功,将返回一个文件指针,失败则返回 NULL。

//pathname: 文件路径
/* mode: 
	r 打开只读文件,该文件必须存在。
	r+ 打开可读写的文件,该文件必须存在。
	w 打开只写文件,若文件存在则文件长度清为 0,即该文件内容会消失。若文件不存在则建立该文件。
	w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
	a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
	a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到
	文件尾后,即文件原先的内容会被保留。
*/
FILE *fopen(const char *path,const char *mode); 

(2)fread:读取文件

  成功时返回:大于 0,返回真实读取的元素数
  异常时返回:小于 nmemb,此时可以用 feof()和 ferror()来判定到底出现了什么情况。

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//ptr:这是一个 void 型指针,指出要将读入数据存放在其中的存储区首地址
//size:指出一个数据块的字节数,即一个数据块的大小尺寸
//nmemb:指出一次读入多少个数据块(size)
//stream:输入数据流指针

(3)fwrite:写入文件

  以二进制形式对文件进行操作,从 ptr 指向的内存中读取 nmemb 个元素,每个元素 size 个字节,写到文件流 stream 中。
  成功时返回:实际写入数据块的个数,即 nmemb 。
  异常时返回:如果文件中剩下的数据块个数少于参数中 size 指出的个数,或者发生了错误,返回 0 值。此时可以用feof()和 ferror()来判定到底出现了什么情况。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
//ptr:这是一个 void 型指针,指出要将写入数据存放在其中的存储区首地址
//size:指出一个数据块的字节数,即一个数据块的大小尺寸
//nmemb:指出一次写入多少个数据块(size)
//stream:输出数据流指针

(4)fclose:关闭文件

int fclose(FILE *stream);

3. 使用标准IO实现拷贝文件。

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

#define Maxsize 1024

//argc表示传递给程序的命令行参数的数量。argv[0] 通常是程序的名称。argv[1]:表示运行可执行程序时传入的第一个参数。
int main(int argc,char **argv)
{
   char data[Maxsize]={0};
   FILE *file1,*file2; 
   size_t size;        
   struct stat info;  //用于存储文件信息。
   if(argc<3){      
     perror("error");      //printf 和perror区别:  perror会打印出错信息
   }
   
   file1=fopen(argv[1],"r"); //只读方式打开
   if(file1==NULL){
      perror("error");
   }
   
   file2=fopen(argv[2],"w"); //只写方式打开
   if(file2==NULL){
      printf("error\n");
   }
   
  stat(argv[1],&info);   //查看文件信息
     
   while(1)
   	{
       size=fread(data,Maxsize,1,file1);  //一次读够Maxsize大小字节数返回1,否则返回0
       
	   if(info.st_size>Maxsize) fwrite(data,Maxsize,1,file2);  
	   else  fwrite(data,info.st_size,1,file2);
	   
	   info.st_size-=Maxsize;
	   if(info.st_size<0) break;  
    }
   
   fclose(file1);
   fclose(file2);
}

二、系统IO(标准C库)

使用场景:主要用于系统级的文件操作。

1. 包含头文件

#include <fcntl.h>  //O_RDONLY, O_WRONLY, O_RDWR等权限宏定义
#include <unistd.h> //open、read、write、fopen、fread等函数
#include <sys/types.h>  //文件权限等
#include <sys/stat.h>  //包含文件信息结构体等

2. 相关函数

(1)open:打开文件

   成功时,返回文件描述符。 失败时,返回 -1,并设置 errno 来指示错误。
   open函数默认是以阻塞模式打开的。

//pathname: 文件路径
//flags: 文件访问模式(如 O_RDONLY, O_WRONLY, O_RDWR)和其他选项(如 O_CREAT, O_EXCL, O_TRUNC 等)。
       // O_EXCL :和O_CREAT一起使用,如果文件存在则open调用失败。

//mode: (可选)创建文件时的权限位,仅在使用 O_CREAT 标志时需要。
int fd = open(const char *pathname, int flags, mode_t mode);

   对于open函数,我们需要详细的讲一下它的第二个参数。这里除了必选访问模式只读只写可读可写外,还可以使用‘|’符号选择多个模式。
O_CREAT:如果文件不存在则创建文件。这里后面需要加上文件的权限,如0777,0666等。
O_EXCL:如果文件已经存在,调用 open 会失败(与 O_CREAT 一起使用时)。
O_TRUNC :表示将文件原本内容全部丢弃,从头开始写新内容。
O_NONBLOCK :非阻塞模式打开文件。
O_APPEND:以追加模式打开文件。每次写操作都会从文件末尾开始。
O_NOCTTY:如果文件是一个终端设备,不将其分配为控制终端。这样可以避免对控制字符和信号的特殊处理,保持与设备的纯粹数据通信。(在串口通信中配置使用)

●阻塞模式和非阻塞模式区别:
   阻塞模式:假设调用read时,当没有数据可读时会阻塞进程,不会执行read函数后面的程序,直至有数据可读。write同理,没有数据可写时,阻塞。
   非阻塞模式:如果对文件描述符的操作不能立即完成,系统调用会立即返回,而不是挂起进程。即当设置为非阻塞模式时,使用read读取数据,当没有数据可读直接返回-1,而不是阻塞进程。write函数同理。

(2)read:读取文件

   成功时,返回实际读取的字节数(可能小于请求读取的字节数)。
   如果在读取时到达文件末尾(没有数据可读时),返回值为 0。
   失败时,返回 -1,并设置 errno 来指示错误。

ssize_t read(int fd, void *buf, size_t count);
//fd:文件描述符,是一个整数,指定从哪个文件中读取数据。
//buf:指向存储读取数据的缓冲区的指针。
//count:要读取的字节数。如读取1024个字节就是1kb。

举例:
读数据时,buff的大小要用sizeof求。

char buff[128];
int ret;
ret=read(fd, buff, sizeof(buff)-1)
if(ret>0){
       buff[ret]='\0';
       printf("Receive: %s\n", buff);
}

(3)write:写入文件

   成功时,返回实际写入的字节数(可能小于请求写入的字节数)。
   失败时,返回 -1,并设置 errno 来指示错误。

ssize_t write(int fd, const void *buf, size_t count);
//fd:文件描述符,是一个整数,指定向哪个文件写入数据。
//buf:指向包含要写入数据的缓冲区的指针。
//count:要写入的字节数。

举例:
写数据时,buff的大小要用strlen求。

char buff[128];
fgets(buff,sizeof(buff),stdin);
write(fd, buff ,strlen(buff));

(4)close:关闭文件

   close 函数是很重要的,因为操作系统有时候会限制同时打开的文件数量,如果不再使用的文件描述符不及时关闭,可能会导致资源泄露或者资源耗尽的问题。
   成功时,返回 0。
   失败时,返回 -1,并设置 errno 来指示错误。

int  close(int fd); //这里的fd为文件描述符

3. 使用系统IO实现拷贝文件。

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

#define Maxsize 1024  //每次读取的大小 
int main(int argc,char **argv)
{
   char data[Maxsize]={0};
   int file1,file2; 
   size_t size;       


   if(argc<3){     
    perror("error\n");       
   }
   
   file1=open(argv[1],O_RDONLY); //只读方式打开
   if(file1 < 0){
      perror("file1 error\n");
   }
   //    O_TRUNC:将文件原本内容全部丢弃,文件大小变为0 
   //    O_CREAT:创建
   file2=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0777);
   if(file2 < 0){
      perror("file2 error\n");
   }
      
   while(1)
   	{
   	//read返回值: 如果读取成功,则返回实际读到的字节数
     size=read(file1,data,Maxsize);     
	 if(size>0)
	 	write(file2,data,size);
	 else  break;
    }
   
   close(file1);
   close(file2);

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值