文件IO与可变参函数

标准IO:

只能操作普通文件和管道文件

拥有缓存区

属于库函数调用

可移植性不同,可以移植到windows或者其他支持c语言的系统中使用

使用场景不同,有缓存区,运行效率高,使用在需要高效率运行的场景(针对数据库的大量访问)

句柄不同,使用的FILE*的文件流指针来指向文件

文件IO:

可以操作绝大部分文件

没有缓存区

属于系统调用

可移植性不同,只能在类unix系统中使用

使用场景不同,没有缓存区,运行效率低,但是实时性高,使用在实时性高的场景(网络通信)

句柄不同,使用的int类型的文件描述符来指向文件

缓存区

为了提高IO的运行效率,将多次准备写入文件中的数据,先统一的写入一段内存进行打包,然后将这段内存统一写入文件中,这样可以大量的减少文件的打开和关闭操作。

缓存区刷新(缓存区打包完成开始执行写入操作)

缓存区有三个不同的类型:行缓存,全缓存,无缓存

行缓存(printf):一定是指向终端的stdout,就是行缓存

行缓存大小为1024字节

  1. 遇到回车(\n)刷新
  2. 缓存区满刷新
  3. 程序结束刷新
  4. 文件关闭缓存刷新
  5. IO切换缓存刷新
  6. fflush(stdout)手动缓存

全缓存:通过fopen打开的指向文件的FILE*指针,都是全缓存

全缓存大小为4096字节

  1. 缓存区满刷新
  2. 程序结束刷新
  3. 文件关闭缓存刷新
  4. IO切换缓存刷新
  5. fflush(stdout)手动缓存

无缓存:标准错误流都是无缓存

scanf的缓存区

scanf实际上是从缓存区读取数据

每个scanf后面跟一个while(getchar!=10);

FILE结构体

结构体中一些关键数据如下
 struct _IO_FILE {

   char* _IO_read_ptr;   /* Current read pointer */
   char* _IO_read_end;   /* End of get area. */
   char* _IO_read_base;  /* Start of putback+get area. */
   char* _IO_write_base; /* Start of put area. */
   char* _IO_write_ptr;  /* Current put pointer. */
   char* _IO_write_end;  /* End of put area. */                                   
   char* _IO_buf_base;   /* Start of reserve area.缓存区的首地址 */
   char* _IO_buf_end;    /* End of reserve area.缓存区的尾地址 */

   int _fileno;          //文件描述符
};
我们可以使用缓存区的尾地址 - 缓存区的首地址 得到 缓存区的大小
注意,在计算缓存区大小之前,需要使用一下

系统调用函数

man手册中系统调用函数都是在2中(man 2 需要查找的系统函数)

man手册中库函数都是在3中(man 3 需要查找的库函数)

linux系统提供给用户的一种函数

功能:能够让用户调用用户无法直接调用的系统底层函数

为什么printf不是系统调用

printf只是c语言库提供的函数

printf能在支持c语言语法的windows系统中使用

write是linux系统提供的函数

write函数绝对不能在windows系统中运行

int类型的描述符是如何与文件地址相关联的

获取int类型的描述符

open:

open产生的描述符最小值为三(0,1,2分别被标准输入流,标准输出流,标准错误流占用了)

描述符产设的规则为最小未使用

函数原型:

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

调用形式:

int fd =open(“文件,名字”,O_RDONLY | O_TRUNC | O_CREAT,0666);//以只读形式打开

int fd =open(“文件,名字”,O_WRONLY | O_TRUNC | O_CREAT,0666);//以只读形式打开

功能:

打开pathname文件,以falgs属性打开,文件成功打开,返回文件描述符

参数pathname:准备打开的文件的路径

参数flags:文件打开的属性集合,主要有以下几种常用属性

O_RDONLY:以只读形式打开文件

O_WRONLY:以只写形式打开文件

O_RDWR:以读写形式打开文件

O_TRUNC:如果文件存在,则清空文件内容后打开

O_CREAT:如果文件不存在,则创建文件打开

O_APPEND:以追加写的形式打开

O_EXCL:如果文件存在,则打开失败,一般配合O_CREAT使用,表示如果文件不存在创建文件,如果文件存在则啥也不干,主要为了确保文件存在

O_NONBLOCK:以非阻塞的形式打开文件(阻塞:条件不满足则不打开(scanf:若缓存区没有数据读取则挂起等待输入数据))

fopen(“文件名”,“w”)---> open ("文件名",O_WRONLY | O_TRUNC | O_CREAT)

属性的叠加需要用“|”而不是“+”

属性的去除,用“&”(~想要去除的数据)

参数mode:仅当第二个参数flags里存在O_CREAT的时候,才需要传入参数mode

用来表示:以mode权限来创建文件,所以一般mode会写成0664或者0666

close

函数原型

int close(int fd);

write和read函数

write:数据流

函数原型:

ssize_t write(int fd, const void *buf, size_t count);

调用形式:

write(fd,任意数据的地址,数据大小)

功能:

将buf指向的数据中,最多count个字节的数据,写入fd所表示的文件中去。

  • 最多count个字节是因为:write不仅仅能够将数据写入普通文件,还能写入套接字文件,套接字文件有大小限制,如果文件剩余内存大小小于想要写入的数据大小,则多余数据丢失

参数fd:文件描述符

参数buf:任意类型的数据的地址

参数count:想要发送的数据大小

返回值:成功写入返回写入的字节的字节数,返回0表示没有数据写入,写入失败返回-1(一般因为设备本身的原因)

read:

函数原型:

ssize_t read(int fd, void *buf, size_t count);

调用形式:

int a=read)(描述符,存放数据的地址,最多读取数据的数量);

功能:

从fd描述的文件,读取最多count个字节的数据,然后将数据写入到buf指向的内存中

参数fd:文件描述符

参数buf:用来存放读取到的数据的地址

参数count:最多读取count个字节的数据

返回值:读取成功,返回成功读取的数据的字节数,返回0表示未读取到数据,读取失败返回-1(基本都是因为文件本身破损的原因导致的读取失败)

3个特殊的描述符

标准输入流:STDIN_FILENO

标准输出流:STDOUT_FILENO

标准错误流;STDERR_FILENO

重定向

dup2

函数原型

int dup2(int oldfd, int newfd);

函数使用

int fd=open(“错误日志”);

dup2(fd,STDERR_FILENO);将标准错误流重定向到fd

dup2(fd2,fd1);

功能:

将newfd重定向到oldfd

参数oldfd:重定向的目标描述符

参数newfd:重定向的原描述符

dup

函数原型:

int dup(int oldfd);

调用形式:

int b=dup();

功能:

将oldfd描述的文件,在返回值(b)处做备份

练习

将一个程序的标准输出流重定向到文件msg.txt中,将标准错误流重定向到err.txt中并测试

printf(“hello\n”);

printf(“world\n”);

要求:将hello输出到msg.txt中,world输出到终端

int main(int argc, const char *argv[])
{
	
	int fd1 = open("./msg1.txt",O_WRONLY | O_TRUNC | O_CREAT,0666);
	int fd2=dup(STDOUT_FILENO);

	dup2(fd1,1);
	printf("hello\n");      //此时stdout是流向msg1.txt中,printf由行缓
                          //存变为全缓存,全缓存遇到\n不会刷新缓存

	fflush(stdout);         //手动刷新缓存

	dup2(fd2,1);
	printf("world\n");

	close(fd1);
	return 0;
}

获取文件权限和属性的函数

access

函数原型:

int access(const char *pathname, int mode);

调用形式:

int a=access(文件名,F_OK/R_OK/W_OK/X_OK);

if(0==a)

{

判断成功

}

功能:

判断pathname文件是否存在或者是否用有mode权限

参数pathname:文件的路径名

参数mode:判断文件权限的选项

F_OK:判断文件是否存在

R_OK:判断文件是否有用户的可读权限

W_OK:判断文件是否有用户的可写权限

X_OK:判断文件是否有用户的可执行权限

返回值:如果判断成功(拥有权限或者文件返回),返回0,判断失败返回-1

stat/fstat/lstat

函数原型

int stat(const char *pathname, struct stat *statbuf);

int fstat(int fd, struct stat *statbuf);

int lstat(const char *pathname, struct stat *statbuf);

这三个函数全是用来实现获取文件属性以及文件的类型

stat与fstat的区别:

stat用的是文件名。

fstat用的是文件描述符。

stat与lstat的区别:

stat函数判断软链接文件的时候,会找到被软连接文件所链接的原文件去判断类型。

lstat判断软链接文件直接判断为软连接文件。

功能:

获取文件的属性,并将获取到的文件的属性存入statbuf指向的结构体中

statbuf结构:

    struct stat {
    dev_t     st_dev;         /* ID of device containing file *
    /
    ino_t     st_ino;         /* Inode number */
    mode_t    st_mode;        /* File type and mode */
    nlink_t   st_nlink;       /* Number of hard links */
    uid_t     st_uid;         /* User ID of owner */
    gid_t     st_gid;         /* Group ID of owner */
    dev_t     st_rdev;        /* Device ID (if special file) */
    off_t     st_size;        /* Total size, in bytes */
    blksize_t st_blksize;     /* Block size for filesystem I/O */
    blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

    };
      其中核心数据就是 mode_t类型的 st_mode 结构体变量
      st_mode里面就存放了文件类型以及文件的属性

权限

The following mask values are defined for the file mode component of the st_mode field:
 
           S_ISUID     04000   set-user-ID bit
           S_ISGID     02000   set-group-ID bit (see below)
           S_ISVTX     01000   sticky bit (see below)
           
           //属主的权限user
           S_IRWXU     00700   owner has read, write, and execute permission
           
           S_IRUSR     00400   owner has read permission
           S_IWUSR     00200   owner has write permission
           S_IXUSR     00100   owner has execute permission
           
           //所在组的权限group
           S_IRWXG     00070   group has read, write, and execute permission
           
           S_IRGRP     00040   group has read permission
           S_IWGRP     00020   group has write permission
           S_IXGRP     00010   group has execute permission
          //other的权限      
           S_IRWXO     00007   others  (not  in group) have read, write, and exe‐
                               cute permission
           S_IROTH     00004   others have read permission
           S_IWOTH     00002   others have write permission
           S_IXOTH     00001   others have execute permission

掩码

文件创建的时候最终权限=手动指定的权限 去除 掩码权限

去除:&(~需要去除的数据)

某些程序权限过高无法运行,需要通过掩码来降低权限。

举例:
    掩码设定成的是 0111
    
    文件创建的时候,指定的权限是 0777 
    最终文件权限是 0666
    
    如文件创建的时候,指定的权限是0666     //权限中没有0111所以不需要去除
    最终文件权限是 0666
    
    如果文件创建的时候,指定的权限是 0333
    最终文件权限是 0222

umask*

函数原型:

mode_t umask(mode_t mask);

功能:

将当前程序的掩码设置成mask,那么当前程序创建的所有文件都会去除mask值

 可变参函数

函数的参数列表中为(固定参,...)其中...为可变参

可变参的地址跟在固定参后面

练习 

 

使用read函数读取一个文件中的所有内容

使用printf函数将读取到的内容,写入到另一个文件中

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char *argv[])
{
	int fd1 = open("./read",O_RDONLY);
	int fd2 = open("./read1",O_WRONLY | O_TRUNC | O_CREAT,0666);

	dup2(fd2,STDOUT_FILENO);

	while(1)
	{
		char arr[24]={0};
		int a = read(fd1,arr,23);
		if(0==a)
			break;
		printf("%s",arr);
		fflush(stdout);
	}
	return 0;
}

使用stat函数判断一个文件是否拥有用户可写,同组人可写,其他组人可写权限

如果同时拥有以上三个权限,则关闭上述三个权限(使用chmod函数)如果以上三个权限不全,则补全

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char *argv[])
{
	struct stat buf={0};
	stat(argv[1],&buf);
	mode_t mode =buf.st_mode;
	if((mode | S_IWUSR )==mode && (mode | S_IWGRP )== mode && (mode | S_IWOTH )== mode)
	{
		chmod(argv[1],0444);
	}
	else
	{
		chmod(argv[1],0664);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值