精华内容
下载资源
问答
  • 文件IO和标准IO

    2021-03-16 22:15:31
    文件 IO 是 Linux 系统提供的接口,针对文件磁盘进行操作,不带缓存机制; 标准 IO 是 C 语言函数库里的标准 I/O 模型,在 stdio.h 中...标准IO 文件IO 打开/创建 fopen open 读 getc,fgetc,getchar,fgets,gets

    文件 IO 是 Linux 系统提供的接口,针对文件和磁盘进行操作,不带缓存机制;
    标准 IO 是 C 语言函数库里的标准 I/O 模型,在 stdio.h 中定义,通过缓冲区操作文件,带缓存机制。

    Linux 系统中一切皆文件,包括普通文件,目录,设备文件(不包含网络设备),管道,fifio 队列,socket 套接字等,在终端输入“ls -l”可查看文件类型和权限。

    标准IO 文件IO
    打开/创建 fopen open
    getc,fgetc,getchar,fgets,gets,fread read
    putc,fputc,puts,fputs,fwrite write
    关闭 fclose close

    本节使用 Linux 提供的接口来进行打开关闭文件。

    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);
    参数含义:
    pathname:路径和文件名,
    flags: 文件打开方式,可用多个标志位按位或设置,常用的标志位参数如下:
    O_CREAT 要打开的文件名不存在时自动创建改文件。
    O_EXCL 要和 O_CREAT 一起使用才能生效,如果文件存在则 open()调用失败。
    O_RDONLY 只读模式打开文件。
    O_WRONLY 只写模式打开文件。
    O_RDWR 可读可写模式打开文件。
    O_APPEND 以追加模式打开文件。
    O_NONBLOCK 以非阻塞模式打开。
    mode: 权限掩码,对不同用户和组设置可执行,读,写权限,使用八进制数表示,此参数可不写。
    返回值:
    open()执行成功会返回 int 型文件描述符,出错时返回-1。

    close()可以关闭文件,通过系统调用取消文件描述符到文件的映射。
    函数定义:
    #include <unistd.h>
    int close(int

    read():

    读取文件最常用的函数,定义如下:
    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
    参数含义:
    fd: 要读的文件描述符
    buf: 缓冲区,存放读到的内容。
    count: 每次读取的字节数
    函数功能:
    每次从 fd 读取 count 个字节,保存到 buf 中。
    返回值:
    返回值大于 0,表示读取到的字节数;
    等于 0 在阻塞模式下表示到达文件末尾或没有数据可读(EOF),并调用阻塞;
    等于-1 表示出错,在非阻塞模式下表示没有数据可读。

    write():

    常用来写文件,定义如下:
    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);
    参数含义:
    fd: 文件描述符;
    buf: 缓存区,存放将要写入的数据;
    count: 每次写入的个数。
    函数功能:
    每次从 buf 缓存区拿 count 个字节写入 fd 文件。
    返回值:
    大于或等于 0 表示执行成功,返回写入的字节数;
    返回-1 代表出错。

    常用函数如下:

    opendir():

    打开指定的目录,并返回 DIR*形态的目录流,
    #include <sys/types.h>
    #include <dirent.h>
    DIR *opendir(const char *name);
    参数含义:
    name:路径名字。
    返回值:成功返回打开的目录流,失败返回 NULL。
    closedir():关闭目录流。
    #include <sys/types.h>
    #include <dirent.h>
    int closedir(DIR *dirp);
    参数含义:dirp:要关闭的目录流指针。

    标准 IO 使用了缓冲区机制,从而减少系统调用,实现更高的效率,三种缓冲机制为:
    全缓冲:当流的缓冲区无数据或无空间时才执行实际 I/O 操作
    行缓冲:当在输入和输出中遇到换行符(‘\n’)时,进行 I/O 操作。
    无缓冲:数据直接写入文件,流不进行缓冲。
    常用函数如下:

    fopen():

    打开或创建文件流,返回指向该文件流的指针
    #include <stdio.h>
    FILE *fopen(const char *path, const char *mode);
    参数含义:
    filename :字符串,用来命名文件;
    mode:访问模式,有以下几种选项:
    r:打开一个已有的文本文件,允许读取文件;
    w:打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件;
    a:打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件;
    r+:打开一个文本文件,允许读写;
    w+:打开一个文本文件,允许读写文件,如果文件不存在,则会创建一个新文件,如 果文件已
    存在, 则文件会被截断为零长度,
    a+:打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件,读取 会从文件
    的开头开始,写入则只能是追加模式
    返回值:返回一个 FILE 对象,FILE 对象包含了用来控制流的方法。

    fclose():

    关闭文件
    #include <stdio.h>
    int fclose(FILE *stream);
    参数含义:打开的文件流对象
    返回值:成功关闭文件,函数返回零,如果关闭文件时发生错误,函数返回 EOF

    fgets():

    从文件流中读取一行,并把它存储在 s 所指向的字符串内,
    #include <stdio.h>
    char *fgets(char *s, int size, FILE *stream);
    参数含义:
    s:数组指针,读到的字符串储存在此数组内;
    size:读取的字符数量,通常填写数组长度;
    stream:打开的文件流。
    返回值:读取成功返回与 s 相同的参数,错误返回一个空指针。
    fread():从文件流 stream 中读 nmemb 个元素到 ptr 指向的内存中,每个元素有 size 个字节。
    #include <stdio.h>
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    参数含义:
    ptr:指向内存块的指针;
    size:每个元素的字节数;
    nmemb:一次读取的元素个数;
    stream:打开的 FILE 对象的指针。
    返回值:如果返回结果与 nmemb 不同,则发生了一个错误或达到了文件末尾

    fwrite():

    把 ptr 所指向的数组中的数据写入到给定流 stream 中,
    #include <stdio.h>
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    参数含义:
    ptr:指向内存块的指针;
    size:每个元素的字节数;
    nmemb:一次写入的元素个数;
    stream:打开的 FILE 对象的指针。
    返回值:成功返回写入元素的个数,如果该数字与 nmemb 不同会显示错误。

    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    
    int main(int argc,char *argv[])
    {
        char buf[8]={0};
        int rlen,wlen;
        int fd = open("./hello",O_RDWR);
        int fd1 = open("./temp.txt",O_CREAT|O_RDWR);
        if(fd == -1 || fd1 == -1)
        {
            perror("open");
            return -1;
        }
        do{
            rlen = read(fd,buf,8);
            wlen = write(fd1,buf,rlen);
            printf("%s",buf);
            memset(buf,0,8);
        }while (rlen > 0 && wlen > 0);
        printf("ok\n");
        close(fd);
        close(fd1);
        return 0;
    }
    
    展开全文
  • 04-文件IO和标准IO

    2020-10-23 22:27:29
    标准IO和文件IO

    IO

    什么是IO

    #include <stdio.h>

    std:standard 标准的
    IO:input output
    i:输入,数据从外部存储设备输入到内存中
    o:输出,数据从内存到外部存储设备

    存储设备:
    1.硬件:机械硬盘,固态硬盘
    2.内存:SDROM DDR4
    总结:IO就是数据从硬盘到内存,内存到硬盘的流动

    IO分类

    1.文件IO
    文件IO是由系统提供的基本IO函数,是与系统绑定的,又称之为系统调用

    1.文件IO的复用性低
    2.文件IO涉及到用户空间到内核空间的切换,cpu模式切换,C代码调用汇编指令等等。属于一种耗时操作,应该尽量减少文件IO的使用
    3.每调用一次文件IO,就会进行一次空间切换

    2.标准IO
    标准IO是根据ANSI标准,对文件IO进行了二次封装(scanf printf)

    if(操作系统 == windows){
    	w_input;
    }else if(操作系统 == ubuntu){
    	l_input;
    }
    

    思考:既然有了文件IO,为什么还需要标准IO?
    答案:为了达到代码的可移植性,让代码的复用性更高

    作用:
    1.提高代码的可移植性和复用性
    2.提高代码的输入输出效率
    设置了一个缓冲区,缓冲区满或者满足一定条件后,陷入到内核中,由内核完成对硬件的操作,大大减少了对文件IO的调用次数。

    2.标准IO

    1.流和流指针

    1.概念
    流(stream):将数据一个一个地移入或移出文件的形式,叫做字节流;
    流指针(FILE*):每打开一个文件,就会在内存中申请一片空间(缓冲区),管理这片内存空间的变量都存储在FILE结构体中,FILE结构体由系统定义的,我们直接拿来用就好。

    2.查看FILE结构体成员

    $ vi -t FILE #可以用于查看系统提供的数据类型,结构体,变量,宏定义
    输入1
    
    struct _IO_FILE {
      int _flags;       /* High-order word is _IO_MAGIC; rest is flags.
    #define _IO_file_flags _flags
                                                                       
      /* The following pointers correspond to the C++ streambuf protoco
      /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields direct
      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. */ 缓冲区的结尾地址
      /* The following fields are used to support backing up and undo. 
      char *_IO_save_base; /* Pointer to start of non-current get area.
      char *_IO_backup_base;  /* Pointer to first valid character of ba
      char *_IO_save_end; /* Pointer to end of non-current get area. */
    
      struct _IO_marker *_markers;
    
      struct _IO_FILE *_chain;
    
      int _fileno;
    
    安装vim: 	vimconfig.tar.bz2
    	1.	tar –xvf vimconfig.tar.bz2
    	2. 	执行 ping ww.baidu.com 	保证有网络
    	3.	sudo apt-get install vim 		安装vim
    	4. 	./config.sh 				进入解压目录(vimconfig)
    

    3.标准输入输出流

    在main函数启动之前,会默认打开三个流指针:
    stdin -----标注输入-----从终端获取数据
    stdout -----标准输出-----将数据输出到终端
    stderr -----标准错误输出

    2.标准IO函数

    1.常见的标准IO函数

    fopen	/fclose	打开/关闭一个文件
    fprintf /fscanf 将标准格式化数据输出到文件中/从文件标准格式化获取数据
    fputc   /fgetc  将单个字符输出到文件中/从文件中获取单个字符
    fputs   /fgets  将字符串输出到文件中/从文件中获取字符串
    fwrite  /fread  将数据的二进制数输出/输入到文件中
    fseek           偏移文件指针
    

    2.man手册

    $man man #查看man手册
     1   Executable programs or shell commands #linux的shell指令
     2   System calls (functions provided by the kernel)  #Linux的系统调用(文件IO)
     3   Library calls (functions within program libraries) #Linux的库调用(标准IO)
    

    3.标准IO函数的使用

    1.fopen

    fopen
    功能:打开一个文件
    头文件:
    #include <stdio.h>
    原型:
    FILE *fopen(const char *path, const char *mode);
    参数:
    char *path:指定要打开的文件的路径
    char *mode:文件的打开方式
    返回值:
    成功返回打开的流指针
    失败返回NULL,更新errno

    r      Open text file for reading.  The stream is positioned at the beginning of the file.
    //以只读的方式打开;
    r+     Open for reading and writing.  The stream is positioned at the beginning of the file.
    //以读写的方式打开,如果文件不存在,打开文件失败;
    w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
    //以写的方式打开,如果文件不存在,则创建该文件;如果文件存在,则清空文件。
    w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is  truncated.   The  stream  is positioned at the beginning of the file.
    //以读写的方式打开,如果文件不存在,则创建该文件;如果文件存在,则清空文件。
    a      Open  for  appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.
    //以写的方式打开文件,如果文件不存在,则创建文件;如果文件存在,则以追加的方式写文件;
    a+     Open for reading and appending (writing at end of file).  The file is created if it does not exist.  The initial  file position for reading is at the beginning of the file, but output is always appended to the end of the file.
    //以读写的方式打开文件,如果文件不存在,则创建文件;如果文件存在,则以追加的方式写文件;
    
    //fopen
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./fopen","w");
    	if(p == NULL){
    		printf("打开失败\n");
    		return -1;
    	}
    	printf("打开成功\n");
    	fclose(fp);
    }
    

    2.perror

    功能:通过errno(错误码),打印错误信息
    头文件:
    #include <stdio.h>
    原型:
    void perror(const char* s);
    参数:
    char* s:用于提示的字符
    #include <errno.h>
    int errno
    errno:本质上是一个全局变量,对文件进行操作的时候,会出现各种错误,errno中已经定义好了各种数值,与错误相对应
    位置:/usr/include/asm-generic/errno.h errno-bash.h

    //perror,errno
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./fopen","r");
    	if(p == NULL){
    		printf("打开失败\n");
    		printf("%d\n",errno);
    		perror("fopen");
    		return -1;
    	}
    	printf("打开成功\n");
    	fclose(fp);
    
    }
    

    3.fclose

    功能:关闭一个文件;
    头文件:
    #include <stdio.h>
    原型:
    int fclose(FILE* fp);
    参数:
    FILE *fp:指定要关闭的文件流指针
    返回值:
    成功,返回0
    失败,返回-1,更新errno

    //fclose
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./fopen","r");
    	if(p == NULL){
    		perror("fopen");
    		return -1;
    	}
    	printf("打开成功\n");
    	int ret = fclose(fp);
    	if(ret < 0){ //if(fclose(fp) < 0)
    		printf("关闭失败\n");
    	}else{
    		printf("关闭成功\n");
    	}
    }
    

    思考:能否对一个文件进行重复fopen和fclose
    答案:不能。
    1.调用fopen时,会去堆空间申请一片缓冲区,并且返回的流指针中储存了这片缓冲区的首地址
    2.不要重复打开一个文件,会造成资源浪费,而且,Linux内核文件的打开次数是有限制的(1024个)
    3.调用fclose时,会通过free释放指定的堆空间,再次调用fclose,会造成重复释放。

    4.fprintf

    功能:将标准格式化数据输出到文件中
    头文件:
    #include <stdio.h>
    原型:
    int printf(const char *format, ...);
    int fprintf(FILE *stream, const char *format, ...);
    参数:
    FILe *stream:文件流指针
    const char *fromat:格式化数据
    ...:不定参数
    返回值:
    成功,返回输出的数据个数
    失败,返回负数,更新errno

    //fprintf
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./test.c","w");
    	if(p == NULL){
    		perror("fopen");
    		return -1;
    	}
    	printf("打开成功\n");
    	//将"hello"输出到文件中
    	if(fprintf(fp,"hello") < 0){
    		perror("fprintf");
    		return -1;
    	}
    	
    	if(fclose(fp) < 0){
    		perror("fclose");
    		return -1;
    	}
    	printf("关闭文件\n");
    }
    

    5.fscanf

    功能:从文件中标准格式化获取数据
    头文件:
    #include <stdio.h>
    原型:
    int scanf(const char *format, ...);
    int fscanf(FILE *stream, const char *format, ...);
    参数:
    FILe *stream:文件流指针
    const char *fromat:格式化数据
    ...:不定参数
    返回值:
    成功,返回获取的数据个数。大于等于0
    失败,或读取到文件结尾,返回EOF(其实就是-1),更新errno

    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./test.c","r");
    	if(p == NULL){
    		perror("fopen");
    		return -1;
    	}
    	
    	char buf[12] = "";
    	char buf1[12] = "";
    	scanf("%s%s",buf,buf1);
    	printf("%s \n",buf,buf1);
    	//按照"%s %s"获取文件内容,分别存入到buf和buf1
    	fscanf(fp,"%s %s",buf,buf1);
    	
    	fclose(fp) < 0
    }
    

    6.fputc

    功能:将单个字符输出到文件中
    头文件:
    #include <stdio.h>
    原型:
    int fputc(int c, FILE *stream);
    参数:
    int c:指定输出的字符
    FILe *stream:文件流指针
    返回值:
    成功,返回输出字符的ASCII码
    失败,返回EOF,更新errno

    //fputc
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./test.c","w");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	if(fputc('a',fp) < 0){
    		perror("fputc");
    		return -1;
    	}
    	fclose(fp);
    }
    

    7.fgetc

    功能:从文件中获取单个字符
    头文件:
    #include <stdio.h>
    原型:
    int fgetc(FILE *stream);
    参数:
    FILe *stream:文件流指针
    返回值:
    成功,返回获取到的字符,从字符类型转化为int类型
    失败,返回EOF,更新errno

    //fgetc
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp;
    	fp = fopen("./test.c","w+");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	if(fputc('a',fp) < 0){
    		perror("fputc");
    		return -1;
    	}
    	int ret = fgetc(fp);
    	if(ret < 0){
    		printf("%d\n",ret);//输出-1
    		perror("fgetc"); //succeed,未关闭的文件结尾默认加EOF
    		return -1;
    	}
    	printf("%d\n",ret);
    	
    	fclose(fp) < 0
    }
    

    文件结尾默认加\nEOF

    练习
    1.计算文件的大小
    2.写一个函数,计算一个文件总共有几行;(提示:判断文件有几个’\n’),就算是文件的结尾也会有个换行符
    3.实现一个文件的拷贝,例如将a.txt中的内容,拷贝到b.txt

    //计算文件大小
    #include <stdio.h>
    int getsize(FILE* fp){
    	int size = 0;
    	while(fgetc(fp) != EOF){
    		szie++;
    	}
    	return size;
    }
    int main(int argc, const char *argv[])
    {
    	if(argc < 2){
    		printf("Usage %s filename\n",argv[0]);
    		return -1;
    	}
    	//打开文件
        FILE *fp = fopen(argv[1],"r");
        if(NULL == fp){
            perror("fopen");
            return -1; 
        }   
        //计算文件大小
        int szie = getsize(fp);
        printf("size = %d\n",size);
    	//关闭文件
        fclose(fp);
        return 0;
    } 
    
    //计算文件行数
    #include <stdio.h>
    int mygetline(FILE* fp){
    	int line = 0,res;
    	while((res = fgetc()) != EOF){
    		if(res == '\n')
    			line++;
    	}
    	return line;
    }
    int main(int argc, const char *argv[])
    {
    	if(argc < 2){
    		printf("Usage %s filename\n",argv[0]);
    		return -1;
    	}
    	//打开文件
        FILE *fp = fopen(argv[1],"r");
        if(NULL == fp){
            perror("fopen");
            return -1; 
        }   
        //计算文件行数
        int line = mygetline(fp);
        printf("line = %d\n",size);
    	//关闭文件
        fclose(fp);
        return 0;
    } 
    
    //拷贝文件
    #include <stdio.h>
    void my_copy(FILE* src,FILE* dest){
        int res;
        while((res = fgetc(src)) != EOF){
            fputc(res,dest);
        }   
    }
    int main(int argc, const char *argv[])
    {
        if(argc < 3){ 
            printf("Usage %s file_src file_dest\n",argv[0]);
            return -1; 
        }   
        FILE *src,*dest;
        src = fopen(argv[1],"r");
        if(NULL == src){
            perror("fopen");
            return -1; 
        }   
        dest = fopen(argv[2],"w");
        if(NULL == dest){
            perror("fopen");
            return -1; 
        }   
    	//拷贝文件
        my_copy(src,dest);
    
        fclose(src);
        fclose(dest);
        return 0;
    }  
    

    8.缓冲区

    标准IO的内容都是存储在缓冲区中,然后输出到硬件中

    • 1.全缓冲

    操作对象:对普通文件进行操作(即通过fopen打开的文件),通过FILEfp流指针维护一个4K大小的缓冲区
    大小:4K=4
    1024=4096 或 fp->_IO_buf_end - fp->_IO_buf_base = 4096

    //全缓冲
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE* fp = fopen("./test.c","r");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	//由于系统优化,如果只打开文件,不操作的话,并不会真正的去申请空间
    	fputc('a',fp);
    	int size = fp->_IO_buf_end - fp->_IO_buf_base;
    	printf("%d\n",size);
    	fclose(fp) < 0
    }
    
    • 刷新缓冲区
      • 1)缓冲区满
      • 2)用fflush强制刷新缓冲区
      • 3)关闭流指针的时候刷新
      • 4)程序正常退出的时候刷新(return)
      • 5)调用exit函数 – 退出整个进程

    fflush
    功能:强制刷新缓冲区
    头文件:
    #include <stdio.h>
    原型:
    int fflush(FILE *stream);
    参数:
    FILe *stream:文件流指针
    返回值:
    成功,返回0
    失败,返回-1,更新errno

    exit
    功能:退出进程
    头文件:
    #include <stdlib.h>
    原型:
    void exit(int status);
    参数:
    int status:可以输入任意int类型数据

    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE *fp = fopen("./test.txt","w");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	putc('a',fp);
    	fflush(fp); //刷新缓冲区,a直接写进去
    	while(1){
    		if(i<4096)
    			putc('b',fp);
    		i++;
    	} //缓冲区刚好为4096,不刷新
    	fclose(fp);
    	return 0;
    }
    
    • 2.行缓冲

    操作对象:标准输入(stdin)和标准输出(stdout)
    大小:1K 或 fp->_IO_buf_end - fp->_IO_buf_base = 1024byte
    关闭fclose(stdout)

    • 刷新缓冲区
      • 1)缓冲区满
      • 2)用fflush强制刷新缓冲区
      • 3)关闭流指针的时候刷新
      • 4)程序正常退出的时候刷新(return)
      • 5)调用exit函数 – 退出整个进程
      • 6)遇到’\n’刷新
    //这个程序需加#if #elif #endif 后执行
    #include <stdio.h>
    #include <stdlib.h> //exit
    int main(int argc, const char *argv[])
    {
    	//1.缓冲区满
    	int i=0;
    	while(i<1024+1){ //比缓冲区多才能输出
    		fputc('a',stdout);
    		i++;
    	}
    	//2.fflush强制刷新
    	fputc('b',stdout);
    	fflush(stdout);
    	//3.关闭流指针
    	fputc('a'.stdout);
    	fclose(stdout);
    	//4.程序正常退出
    	fputc('a'.stdout);
    	return 0;
    	//5.调用exit函数
    	fputc('a',stdout);
    	exit(1);
    	//6.遇到'\n'
    	printf("fff\n");//putc('\n',stdout);
    	
    	while(1);
    	return 0;
    }
    
    • 3.无缓冲

    操作对象:标准错误输出(stderr)
    大小:0,无缓冲,perror调用的就是stderr

    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	fprintf(stderr,"hello world");
    	while(1){
    	return 0;
    }
    

    9.fputs

    功能:将字符串输出到文件中
    头文件:
    #include <stdio.h>
    原型:
    int fputs(const char *s, FILE *stream);
    参数:
    char *s:指定要输出的字符串首地址
    返回值:
    成功,返回0
    失败,返回-1,更新errno

    10.fgets

    功能:从文件中获取字符串
    头文件:
    #include <stdio.h>
    原型:
    char *fgets(char *s, int size, FILE *stream);
    参数:
    char *s:存储获取到的字符串
    int size:从文件中读取 size-1 个字符,因为要保留’\0’;注意:如果一行不足size个,则读取个数为一行的实际个数;
    返回值:
    成功,返回char* s
    失败,返回NULL,更新errno

    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	//通过fopen打开的文件是全缓冲
    	FILE *fp = fopen("./test.txt","w+");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	//文件指针已经移动到d之后
    	if(fputs("hello world",fp) < 0){
    		perror("fputs");
    		return -1;
    	}
    	//关闭再打开让文件指针指向头
    	fclose(fp);
    	FILE *fp = fopen("./test.txt","r");
    	//fseek(fp,0,SEEK_SET);直接调用fseek函数比较方便
    	char buf[10] = "";
    	fgets(buf,10,fp);
    	printf("%s\n",buf);//hello wor
    	fclose(fp);
    	return 0;
    }
    

    11.fwrite

    功能:将数据的二进制形式写入文件中
    头文件:
    #include <stdio.h>
    原型:
    size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    参数:
    void *ptr:要输出的数据地址,可以是任意类型的数据;
    size_t size:以size个字节为单位输出。例如:
    如果要输出的是int类型数据,size == 4;
    如果要输出的是char类型数据,size == 1;
    如果要输出的是自定义结构体类型,struct aa ,size == sizeof(aa);
    size_t nmemb:要输出的数据个数;
    FILE *stream:流指针;
    返回值:
    成功,返回输出的数据个数,其实就是nmemb;
    失败,返回-1,更新errno;

    //fwrite,写入的是二进制
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE *fp = fopen("./test.txt","w");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	int arr[4] = {1,2,3,4};
    	if(fwrite(arr,sizeof(int),sizeof(arr),fp) < 0){
    		perror("fwrite");
    		return -1;
    	}
    	printf("fwrite succeed\n");
    	fclose(fp);
    	return 0;
    }
    

    12.fread

    功能:从文件中读取二进制数据;
    头文件:
    #include <stdio.h>
    原型:
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    参数:
    void *ptr:成功读取数据后,数据存储在该位置;
    size_t size:以size个字节为单位输出。例如:
    如果要输出的是int类型数据,size == 4;
    如果要输出的是char类型数据,size == 1;
    如果要输出的是自定义结构体类型,struct aa ,size == sizeof(aa);
    size_t nmemb:要输出的数据个数;
    FILE *stream:流指针;
    返回值:
    成功,返回读取的数据个数,其实就是nmemb;
    失败,返回-1,更新errno;

    //fwrite,写入的是二进制
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	FILE *fp = fopen("./test.txt","r");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	int arr[4];
    	if(fread(arr,sizoef(int),3,fp) < 0){
    		perror("read");
    		return -1;
    	}
    	printf("fread succeed\n");
    	int i=0;
    	for(i=0;i<3;i++)
    		printf("%d ",arr[i]);
    	putchar(10);
    	fclose(fp);
    	return 0;
    }
    

    13.fseek

    功能:偏移流指针;
    头文件:
    #include <stdio.h>
    原型:
    int fseek(FILE *stream, long offset, int whence);
    参数:
    FILE *stream:流指针;
    long offset:偏移量;
    int whence:SEEK_SET:文件开头
    SEET_CUR:文件指针当前位置
    SEET_END:文件结束位置
    返回值:
    成功,返回0
    失败,返回-1,更新errno;

    long ftell(FILE *stream); 获取文件当前位置到文件开头的偏移量
    例子:long int size = ftell(fp);
    void rewind(FILE *stream); 偏移文件指针到文件开头,相当于 fseek(fp, 0, SEEK_SET);

    思考:如何使用fseek() ftel()计算文件大小

    //使用fseek() ftel()计算文件大小
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
    	//通过fopen打开的文件是全缓冲
    	FILE *fp = fopen("./test.txt","w+");
    	if(NULL == fp){
    		perror("fopen");
    		return -1;
    	}
    	//文件指针已经移动到d之后
    	if(fputs("hello world",fp) < 0){
    		perror("fputs");
    		return -1;
    	}
    	//将文件指针移动到EOF前
    	if(fseek(fp,0,SEEK_END) < 0){
    		perror("fseek");
    		return -1;
    	}
    	long int size = ftell(fp);
    	fprintf(stdout,"%ld",size);
    	fclose(fp);
    	return 0;
    }
    

    14.time

    功能:获取1970-01-01起至今的秒数;
    头文件:
    #include <time.h>
    原型:
    time_t time(time_t *tloc);
    参数:
    time_t *tloc:存储获取到的时间;
    返回值:
    成功,返回获取到的时间;
    失败,返回(time_t) -1;更新errno;

    //方法1
    time_t tloc;
    time(&tloc);
    printf("%ld\n",tloc);
    //方法2
    tloc = time(NULL);
    printf("%ld\n",tloc);
    

    15.localtime

    功能:将1970-01-01起至今的秒数,转换成日历格式;
    头文件:
    #include <time.h>
    原型:
    struct tm *localtime(const time_t *c);
    参数:
    time_t *timep:time函数返回的值
    返回值:
    成功,返回存储日历格式的结构体指针: struct tm *
    struct tm
    {
    int tm_sec; /* Seconds. [0-60] (1 leap second) /
    int tm_min; /
    Minutes. [0-59] /
    int tm_hour; /
    Hours. [0-23] /
    int tm_mday; /
    Day. [1-31] /
    int tm_mon; /
    Month. [0-11] / 月 = tm_mon+1;
    int tm_year; /
    Year - 1900. / 年 = tm_year+1900;
    int tm_wday; /
    Day of week. [0-6] / 星期 = tm_wday+1;
    int tm_yday; /
    Days in year.[0-365] */
    }
    失败,返回NULL

    //localtime
    #include <stdio.h>
    #include <time.h>
    int main(int argc, const char *argv[])
    {
    	time_t tloc = time(NULL);
    	struct tm* info = localtime(&tloc);
    	if(NULL == info){
    		perror("localtime");
    		return -1;
    	}
    	printf("%d-%d-%d %02d-%02d-%02d\n",info->tm_year+1900,info->tm_mon+1,\
    	info->tm_mday,info->tm_hour,info->tm_min,info->tm_sec);
    	return 0;
    }
    

    16.sprintf

    功能:将数据格式化输出到字符串中,可以做数据拼接
    头文件:
    #include <stdio.h>
    原型:
    int printf(const char *format, ...);
    int fprintf(FILE *stream, const char *format, ...);
    int sprintf(char *str, const char *format, ...);
    参数:
    char *str:接收的字符串
    const char *format:格式化输出
    ...:不定参数
    返回值:

    17.sscanf

    功能:将字符串以标准格式输入
    头文件:
    #include <stdio.h>
    原型:
    int scanf(const char *format, ...);
    int fscanf(FILE *stream, const char *format, ...);
    int sscanf(const char *str, const char *format, ...);
    参数:
    char *str:字符串
    const char *format:格式化输出
    ...:不定参数
    返回值:

    //sprintf,sscanf
    #include <stdio.h>
    int main(int argc, const char *argv[])
    {
        int num = 100;
        char name[10] = "lisi";
        char sex = 'f';
        float score = 89.5;
    
        printf("%d %s %c %.1f\n",num, name, sex, score);
    
        char buf[50] = ""; 
        sprintf(buf, "%d %s %c %.1f",num, name, sex, score);
    
        printf("%s\n", buf);
    
        int num1;
        char name1[10] = ""; 
        char sex1;
        float score1;                                                                                            
        sscanf(buf, "%d %s %c %f",&num1, name1, &sex1, &score1);
        printf("%d %s %c %f\n", num1, name1, sex1, score1);
    
    
        return 0;
    }
    

    3.文件IO

    1.文件IO是不带缓冲区的
    2.文件IO函数是由操作系统提供的,与操作系统绑定的,又称之为系统调用
    3.文件IO是通过文件描述符来维护一个文件

    文件描述符

    1.概念

    1.尝试打开一个文件的时候,系统会主动给这个文件分配一个编号(文件描述符),用这个编号来描述文件
    ⒉标准I0是对文件IO的二次封装,在文件I0的基础上封装了一个缓冲区,同时会将文件描述符也一起封装到FILE结构体中.
    3.文件IO对文件的读写,是通过文件描述符实现的。
    4.标准IO对文件的读写,是通过操作流指针实现的。

    2.特殊的文件描述符

    特殊的流指针 特殊的文件描述符 数值
    stdin stdin->_fileno 0 STDIN_FILENO
    stdout stdout->_fileno 1 STDOUT_FILENO
    stderr stderr->_fileno 2 STDERR_FILENO
    //stdin->_fileno
    #include <stdio.h>                                                                                                                         
    int main(int argc, const char *argv[])
    {
    	printf("%d %d %d\n",stdin->_fileno,stdout->_fileno,stderr->_fileno);
    	return 0;
    }
    

    3.文件描述符的总量

    文件描述符的标号:[0,1023]。总共1024个
    其中0,1,2分别对应stdin、stdout、stderr

    注意:

    1.每一个进程能打开的最大文件描述符是1023,数量是1024个;
    2.文件描述符的资源是有限的,在不使用的情况下,需要关闭;

    getdtableszie()函数

    功能:获取当前进程能打开的文件描述符总量
    头文件:
    #include <unistd.h>
    原型:
    int getdtablesize(void);
    参数:
    返回值:当前进程能打开的文件描述符总量
    例子:int size = getdtablesize(); //szie = 1024

    //用fopen查看文件描述符总量
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(int argc, const char *argv[])
    {
        FILE *fp;
        while(1){
            fp = fopen("./1.txt","w");
            if(NULL == fp){
                perror("fopen");
                break;
            }
            printf("%d\t",fp->_fileno);
        }
        putchar(10);
        return 0;
    }
    

    2.文件IO的函数

    1.常见的文件IO函数

    man 2 卷
    open / close 打开 / 关闭一个文件
    read / write 读 / 写一个文件
    lseek 偏移

    2.文件IO的使用

    1.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);
    参数:
    char *pathname:指定要打开的文件路径及文件名
    int flags:文件的打开方式;如果要包含多种方式,可以用按位或(|)的方式连接
    O_RDONLY:只读方式打开
    O_WRONLY:只写方式打开
    O_RDWR:读写方式打开
    以上三种,必须包含一种
    O_APPEND:追加的方式; flags = O_WRONLY | O_APPEND
    O_CREAT:文件不存在则创建;
    O_TRUNC:清空文件;
    mode_t mode:文件的八进制权限,如0777,0664;
    如果falgs中包含了O_CREAT,则必须要定义文件权限,如果不加,则忽略O_CREAT


    S_IRWXU 00700 user (file owner) has read, write and execute permission
    S_IRUSR 00400 user has read permission
    S_IWUSR 00200 user has write permission
    S_IXUSR 00100 user has execute permission
    **************文件所属用户的权限
    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
    **************文件所属组的权限
    S_IRWXO 00007 others have read, write and execute permission
    S_IROTH 00004 others have read permission
    S_IWOTH 00002 others have write permission
    S_IXOTH 00001 others have execute permission
    **************文件其他用户的权限


    返回值:
    成功,返回对应的文件描述符
    失败,返回-1,更新errno

    作业:fopen的r r+ w w+ a a+,分别对应open的flags的哪几种组合

    //open,close
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main(int argc, const char *argv[])
    {
        int fd = open("./test.c",O_RDWR|O_CREAT|O_TRUNC,0777);
        if(fd < 0){ 
            perror("close");
            return(-1);
        }   
        printf("open succeed %d\n",fd);
        close(fd);
        return 0;
    }
    

    2.umask

    The permissions of the created file are (mode & ~umask).
    文件创建的真实权限是 mode & (~umask);
    1.什么是umask

    umsk:文件权限掩码,会影响文件创建时候的权限,实际文件的权限是 mode & (~umask);

    2.查看umask

    $ umask 得到结果是 0002
    实际创建的文件权限:0777 & (~0002) = 0775

    3.设置umask

    方法1:在终端上设置,但只在当前终端有效
    $ umask 0000 将umask清0
    方法2:通过umask()函数实现

    umsk()函数

    功能:设置umask的值;
    头文件:
    #include <sys/stat.h>
    原型: mode_t umask(mode_t cmask);
    参数:
    返回值:

    //umask
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(int argc, const char *argv[])
    {
        umask(0000);//设置文件权限掩码为0000(八进制)
        int fd = open("./open", O_RDWR|O_CREAT|O_TRUNC, 0777);
        if(fd < 0){
    		perror("open");
    		return -1;
    	}
        printf("open succeed %d\n", fd);
        close(fd);
        return 0;
    }
    

    3.close

    功能:关闭文件描述符
    头文件:
    #include <unistd.h>
    原型:
    int close(int fd);
    参数:
    int fd:指定要关闭的文件描述符;
    返回值:
    成功,返回0;
    失败,返回-1, 更新errno;

    4.write

    功能:将数据写入文件描述
    头文件:
    #include <unistd.h>
    原型:
    ssize_t write(int fd, const void *buf, size_t count);
    参数:
    int fd:指定文件描述符;
    void *buf:要写入文件的数据的首地址;可以是任意类型;
    size_t count:要写入的数据大小,以字节为单位;如果要写入int a[2], count = 8;
    返回值:
    成功,返回写入的数据个数;
    失败,返回-1,更新errno;

    //write
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h> //strlen
    int main(int argc, const char *argv[])
    {
        int fd = open("./test.c",O_WRONLY|O_TRUNC);
        if(fd < 0){
            perror("open");
            return -1;
        }
        char buf[10] = "";
        fgets(buf,10,stdin);//终端输入hello world回车
        int ret = write(fd,buf,strlen(buf));//strlen不计'\0'
        if(ret < 0){
            perror("write");
            return -1;
        }
        printf("write %d\n",ret);//输出write 9,文件里为hello wor
        close(fd);
        return 0;
    }
    

    5.read

    功能:从文件描述符读取数据;
    头文件:
    #include <unistd.h>
    原型:
    ssize_t read(int fd, void *buf, size_t count);
    参数:
    int fd:文件描述符;
    void *buf:存储读取到的数据;
    size_t count:要读取的数据大小,以字节为单位;
    返回值:
    成功,返回读取到的数据个数;如果读到文件结尾返回0;
    失败,返回-1,更新errno;

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main(int argc, const char *argv[])
    {
        int fd = open("./test.c",O_RDONLY);
        if(fd < 0){ 
            perror("open");
            return -1; 
        }   
        char buf[10] = ""; 
        int ret = read(fd,buf,10);//fd文件里写了hello world
        if(ret < 0){ 
            perror("read");
            return -1; 
        }   
        printf("read %d :%s\n",ret,buf);//read 10:hello word
        close(fd);
        return 0;
    }   
    

    6.lseek

    功能:偏移文件指针;
    头文件:
    #include <sys/types.h>
    #include <unistd.h>
    原型:
    off_t lseek(int fd, off_t offset, int whence);
    参数:
    int fd:文件描述符;
    off_t offset:相对于 int whence 偏移量;
    int whence
    SEEK_SET 文件开头;
    SEEK_CUR 当前位置;
    SEEK_END 文件结尾;
    返回值:
    成功,返回设置后的文件指针相对于文件开头的偏移量;
    失败,返回-1,更新errno;

    用于计算文件的大小:
    off_t size = lseek(fd, 0, SEEK_END); //size就是文件的大小;

    //lseek
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>//lseek
    #include <fcntl.h>
    #include <string.h>//bzero
    
    int main(int argc, const char *argv[])
    {
        umask(0);
        int fd = open("./write.txt", O_RDWR|O_CREAT|O_TRUNC, 0777);
        if(fd < 0)
        {   
            perror("open");
            return -1; 
        }
        printf("open成功\n");
    
        char buf[15] = ""; 
        //fgets(buf, 15, stdin);
        scanf("%s", buf);
    	//写入
        int ret = write(fd, buf, strlen(buf));
        if(ret < 0)
        {   
            perror("write");
            return -1;
        }   
        printf("写入成功 %d\n", ret);
    
        //关闭重新打开;
        //用lseek函数
        lseek(fd, 0, SEEK_SET);
       //读取
        bzero(buf, 15);
        ret = read(fd, buf, 20);
        if(ret < 0)
        {
            perror("read");
            return -1; 
        }   
        printf("%s\n",buf);
    
        close(fd);
        return 0;
    }
    

    练习:通过write和read函数实现图片的拷贝;

    //通过write和read函数实现图片的拷贝;
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int main(int argc, const char *argv[])
    {
        if(argc != 3){ 
            printf("Usage %s filesrc filedist\n",argv[0]);
            return -1; 
        }   
        umask(0);
        int fd_src = open(argv[1],O_RDONLY);
        if(fd_src < 0){ 
            perror("open src");
            return -1; 
        }   
        int fd_dist = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0664);
        if(fd_dist < 0){ 
            perror("open dist");
            close(fd_src);
            return -1; 
        }   
        char buf[20] = ""; 
        int ret;
        while((ret = read(fd_src,buf,20)) > 0){ 
            write(fd_dist,buf,ret);
        }   
        close(fd_src);
        close(fd_dist);
        return 0;
    } 
    

    3.文件属性相关的函数

    1.stat

    功能:获取文件的属性;
    头文件:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    原型:
    int stat(const char *path, struct stat *buf);
    参数:
    char *path:指定文件的路径或路径加名字;
    struct stat *buf:系统定义的结构体,存储文件的属性;

    struct stat {
    	dev_t     st_dev;     /* ID of device containing file */
    	ino_t     st_ino;     /* inode number */ 				inode号 		    %ld
    	mode_t    st_mode;    /* protection */ 					文件的类型+文件的权限  %o
    	nlink_t   st_nlink;   /* number of hard links */		硬连接数 			%d
    	uid_t     st_uid;     /* user ID of owner */			当前用户的uid		%d
    	gid_t     st_gid;     /* group ID of owner */			当前用户组的gid 		%d
    	dev_t     st_rdev;    /* device ID (if special file) */
    	off_t     st_size;    /* total size, in bytes */		文件大小			    %ld
    	blksize_t st_blksize; /* blocksize for filesystem I/O */
    	blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    	time_t    st_atime;   /* time of last access */			最后一次被访问的时间  %ld
    	time_t    st_mtime;   /* time of last modification */	最后一次被修改的时间
    	time_t    st_ctime;   /* time of last status change */	最后一次改变状态的时间
    	};
    

    返回值:
    成功,返回0;
    失败,返回-1,更新errno;

    //stat例子
    struct stat buf;
    int ret = stat(argv[1],&buf);
    if(ret < 0){
    	perror("stat");
    	return -1;
    }
    

    2.提取文件权限

    mode_t st_mode; /* protection */ 文件的类型+文件的权限st_mode;
    是一个32位无符号的整形变量,其中低9位[0 , 8],代表了文件的权限(rwx rwx rwx);
    用st_mode & 相应权限,如果结果大于0, 说明有该权限;如果结果等于0,说明没有该权限;

    st_mode: 100664
       664-> 110 110 100
       & 	 100 000 000     -->0400
        ------------------
        	 100 000 000 	----> 0400 文件所属用户有可读权限。
    

    对应的权限的宏:

    S_IRWXU    00700     mask for file owner permissions
    S_IRUSR    00400     owner has read permission
    S_IWUSR    00200     owner has write permission
    S_IXUSR    00100     owner has execute permission
    S_IRWXG    00070     mask for group permissions
    S_IRGRP    00040     group has read permission
    S_IWGRP    00020     group has write permission
    S_IXGRP    00010     group has execute permission
    S_IRWXO    00007     mask for permissions for others (not in group)
    S_IROTH    00004     others have read permission
    S_IWOTH    00002     others have write permission
    S_IXOTH    00001     others have execute permission
    
    //mode_t st_mode
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    //方法1
    void getPermission(mode_t m)
    {
        if(m & 0400)
            printf("r");
        else
            printf("-");
    
        if(m& 0200)
            printf("w");
        else
            putchar('-');
    
        if(m & 0100)
            putchar('x');
        else
            putchar('-');
    
        /*****************************/
        if(m & 0040)
            printf("r");
        else
            printf("-");
    
        if(m& 0020)
            printf("w");
        else
            putchar('-');
    
        if(m & 0010)
            putchar('x');
        else
            putchar('-');
        
        /*****************************/
        if(m & 0004)
            printf("r");
        else
            printf("-");
    
        if(m& 0002)
            printf("w");
        else
            putchar('-');
    
        if(m & 0001)
            putchar('x');
        else
            putchar('-');
    
        putchar(10);
    
    }
    //方法2
    void getPermission(mode_t m)
    {
        int i = 0;
        for(i = 8; i>=0; i--)
        {
            if((m & (1 << i)) == 0)
            {
                printf("-");
                continue;
            }
    
            switch(i)//或switch(i%3){case2:putcahr('r');case1:...
            {
            case 8:
            case 5:
            case 2:
                putchar('r');
                break;
    
            case 7:
            case 4:
            case 1:
                putchar('w');
                break;
    
            case 6:
            case 3:
            case 0:
                putchar('x');
                break;
    
            }                               
        }
    
        putchar(10);
    }
    
    int main(int argc, const char *argv[])
    {
        if(argc < 2)
        {
            fprintf(stderr, "运行参数缺失\n");
            return -1;
        }
    
        struct stat buf;
        int ret = stat(argv[1], &buf);
        if(ret < 0)
        {
            perror("stat");
            return -1;
        }
    
        //文件的类型+权限
        printf("mode : %o\n", buf.st_mode);
        getPermission(buf.st_mode);
    
        return 0;
    }
    

    折叠:选中要折叠的->zf
    打开折叠:zE或左右键
    关上折叠:zc

    3.提取文件类型

    7种文件类型:bsp-lcd

    i)通过宏函数判断

    S_ISREG(m) is it a regular file? -
    S_ISDIR(m) directory? d
    S_ISCHR(m) character device? c
    S_ISBLK(m) block device? b
    S_ISFIFO(m) FIFO (named pipe)? p
    S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) l
    S_ISSOCK(m) socket? (Not in POSIX.1-1996.) s
    参数:
    mode_t st_mode;
    返回值:
    1,代表是该类型文件;
    0,不是该该类型文件;

    //mode_t st_mode通过宏函数判断提取文件类型
    void getType(mode_t m)
    {
        if(S_ISREG(m))
            putchar('-');
        else if(S_ISDIR(m))
            putchar('d');                                                                              
        else if(S_ISCHR(m))
            putchar('c');
        else if(S_ISBLK(m))
            putchar('b');
        else if(S_ISFIFO(m))
            putchar('p');
        else if(S_ISLNK(m))
            putchar('l');
        else if(S_ISSOCK(m))
            putchar('s');
    }
    

    ii)通过提取文件类型

    mode_t st_mode; /* protection */ 文件的类型+文件的权限
    st_mode:是一个32位无符号的整形变量,其中低[18位 , 13位],共6bit,代表了文件的类型;
    S_IFMT 0170000 bit mask for the file type bit fields
    st_mode & S_IFMT :提取出[低18位,低13位]:6bit,这6bit代表文件类型。

    st_mode:100775
        	100775		001 000 000 111 111 101
    S_IFMT  170000     001 111 000 000 000 000
        ----------------------------------------------------
        				001 000 ---------------------->提取出6bit: 0100000
    将结果与下列宏作比较,如果相等,那么就是对应的文件类型:
    		   S_IFSOCK   0140000   socket
               S_IFLNK    0120000   symbolic link
               S_IFREG    0100000   regular file
               S_IFBLK    0060000   block device
               S_IFDIR    0040000   directory
               S_IFCHR    0020000   character device
               S_IFIFO    0010000   FIFO
    
    void getType(mode_t m)
    {              
        mode_t mode = m&S_IFMT;
        switch(mode)
        {   
        case S_IFSOCK:
            putchar('s');
            break;
        case S_IFLNK:
            putchar('l');
            break;
        case S_IFREG:
            putchar('-');
            break;
        case S_IFBLK:
            putchar('b');
            break;
        case S_IFDIR:
            putchar('d');
            break;
        case S_IFCHR:
            putchar('c');
            break;
        case S_IFIFO:
            putchar('p');
            break;
        }   
    }
    

    4.获取文件所属用户

    uid_t st_uid; /* user ID of owner */ 当前用户的uid
    通过struct stat结构体中的 uid_t st_uid 成员变量获取文件所属用户

    getpwuid函数

    功能:通过struct stat结构体中的 uid_t st_uid 成员变量获取文件所属用户;
    头文件:
    #include <sys/types.h>
    #include <pwd.h>
    原型:
    struct passwd *getpwuid(uid_t uid);
    参数:
    uid_t uid:文件所属用户的uid;
    返回值:
    成功,返回存储文件所属用户信息的结构体地址;
    失败,返回NULL,更新errno;

    struct passwd {
    	char   *pw_name;       /* username */
    	char   *pw_passwd;     /* user password */
    	uid_t   pw_uid;        /* user ID */
    	gid_t   pw_gid;        /* group ID */
    	char   *pw_gecos;      /* user information */
    	char   *pw_dir;        /* home directory */
    	char   *pw_shell;      /* shell program */
    };
    sudo chown root:root 文件名		将文件所属用户改成root
    sudo chown linux:root 文件名		将文件所属用户改成linux
    

    5.获取文件所属组用户

    gid_t st_gid; /* group ID of owner */ 当前用户组的gid

    getgrgid函数

    功能:根据 struct stat 结构体中的gid_t st_gid,获取文件所属的组;
    头文件:
    #include <sys/types.h>
    #include <grp.h>
    原型:
    struct group *getgrgid(gid_t gid);
    参数:
    gid_t gid:组ID;
    返回值:
    成功,返回存储用户组信息的结构体地址;
    失败,返回NULL;

    struct group {
    	char   *gr_name;       /* group name */
    	char   *gr_passwd;     /* group password */
    	gid_t   gr_gid;        /* group ID */
    	char  **gr_mem;        /* group members */
    };
    

    练习:读取一个文件的信息,main函数外部传参的方式。要求输出结果格式如下:
    -rw-rw-r-- 1 linux linux 11 Sep 23 05:24 fileno

    4.操作文件目录的函数

    1.opendir

    功能:打开一个目录文件;
    头文件:
    #include <sys/types.h>
    #include <dirent.h>
    原型:
    DIR *opendir(const char *name);
    参数:
    char *name:指定要打开的目录文件路径及目录名;
    返回值:
    成功,返回目录流指针;
    失败,返回NULL;更新errno;

    2.closedir

    3.readdir

    功能:通过DIR*读取目录;
    头文件:
    #include <dirent.h>
    原型:
    struct dirent *readdir(DIR *dirp);
    参数:
    DIR *dirp:指定的目录流指针;
    返回值:
    成功,返回 struct dirent *结构体地址;
    失败,返回NULL,更新errno;

    struct dirent {
    	ino_t          d_ino;       /* inode number */
    	off_t          d_off;       /* not an offset; see NOTES */
    	unsigned short d_reclen;    /* length of this record */
    	unsigned char  d_type;      /* type of file; not supported
    	                               by all filesystem types */
    	char           d_name[256]; /* filename */
    };
    
    //opendir/closedir/readdir
    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    
    int main(int argc, const char *argv[])
    {
        DIR* dirp = opendir("../1_stdio/");
        if(NULL == dirp)
        {   
            perror("opendir");
            return -1; 
        }   
        printf("打开成功\n");
    
        struct dirent* dir_read;
        while(1)
        {   
            dir_read = readdir(dirp);
            if(NULL == dir_read)
            {   
                break;
            }   
    
            printf("%ld %s\n", dir_read->d_ino, dir_read->d_name);
        }   
    
        if(closedir(dirp)<0)
        {   
            perror("closedir");
            return -1; 
        }
    
        printf("关闭成功\n");
    
        return 0;                                                           
    } 
    

    练习:1.代码实现,打开目录,显示该目录下面所有文件的属性,权限,最有一次被修改的时间,类似ls –l。

    展开全文
  • linux应用基础知识点2-文件IO和标准IO open、close、write、read这类API函数构成的一套读写文件的体系,我们称为“文件IO”。 应用层C语言库函数提供了一系列读写函数fopen、fclose、fwrite、fread,由文件io封装来...

    linux应用基础知识点2-文件IO和标准IO

    open、close、write、read这类API函数构成的一套读写文件的体系,我们称为“文件IO”。
    应用层C语言库函数提供了一系列读写函数fopen、fclose、fwrite、fread,由文件io封装来的,我们称之为“标准IO”。

    两者的对比:
    1.工作效率
    以write操作为例,文件io会根据硬盘特性,选择合适时间将底层缓冲区文件写入块设备中。这套体系可以完成工作,但是效率不高。
    标准IO为应用层增加了一个缓冲机制,这样当写操作时,不是直接进入内核的buf,而是先进入标准io维护的应用层buf,然后标准io根据系统单次写入的最佳时机写到内核buf中。效率更高。
    文件IO对比标准IO
    2.移植性
    文件IO在不同的操作系统间不能通用,而标准IO则几乎一样。

    展开全文
  • 文件IO和标准IO的区别? 1、标准IO是c库提供的,文件IO是linux系统提供的 2、标准IO是通过FILE*来操作文件,文件IO是通过文件描述符操作文件 3、标准IO有缓冲区,系统开销小,文件IO没有缓冲区,系统开销大 4、标准...

    文件IO和标准IO的区别?
    1、标准IO是c库提供的,文件IO是linux系统提供的
    2、标准IO是通过FILE*来操作文件,文件IO是通过文件描述符操作文件
    3、标准IO有缓冲区,系统开销小,文件IO没有缓冲区,系统开销大
    4、标准IO可移植,而文件IO不行
    5、标准IO只能操作普通文件,而文件IO可以操作普通文件、设备文件、管道文件等等

    展开全文
  • 浅谈 文件IO和标准IO

    2019-03-31 23:06:17
    标准IO: 标准IO处理了很多细节,对文件IO进行了封装,可移植性高,提供缓冲区(全缓冲、行缓冲、不带缓冲) 区别: 通过文件IO读写文件时,会频繁的进行系统调用,这样就增加了系统的开销;而标准I/O可以看成是在文件...
  • 文件IO和标准IO的比较

    2009-12-11 11:24:00
    文件IO和标准IO的比较文件IO是一种不带缓冲机制,需要自己建立缓冲区的低级IO。标准IO自己带有缓冲区。 各自使用的函数如下. 文件IOopenclosereadwritelseek 标准IOfopenfclosegetc,fscanf,fgetsputc,fputs,...
  • Linux文件IO和标准IO

    2018-11-13 21:46:52
    Linux中做文件IO最常用到的5个函数是: open , close , read , write lseek ,不是ISO C的组成部分,这5个函数是不带缓冲的IO,也即每个readwrite都调用了内核的一个系统调用。 #include &lt;fcntl.h&...
  • 文件IO和标准IO的区别

    2021-03-25 11:57:25
    一、先来了解下什么是文件I/O和标准I/O: 文件I/O:文件I/O称之为不带缓存的IO(unbuffered I/O)。不带缓存指的是每个read,write都调用内核中的一个系统调用。也就是一般所说的低级I/O——操作系统提供的基本IO...
  • 29_文件IO和标准IO

    2018-03-14 23:15:31
    一块去操作硬件,这个数量应用程序是不清楚的所以C语言库函数提供了一些c语言错做文件的标准IO操作库函数fopen fclose fread fwrite f表示库函数(标准IO),有文件IO封装而来,内部调用的还是open等API函数 只不过...
  • [TOC]Linux 文件IO 标准IOLinux 文件IOLinux中做文件IO最常用到的5个函数是: open , close , read , write lseek ,不是ISO C的组成部分,这5个函数是不带缓冲的IO,也即每个readwrite都调用了内核的一个...
  • 文件 IO是Linux系统提供的接口,针对文件和磁盘进行操作,不带缓存机制;...标准IO和文件IO常用API如下: 1 文件IO open()/close() 本节使用Linux提供的接口来进行打开关闭文件。 open():通过系统调用,可以打开文
  • 标准IO使用了缓冲区机制,从而减少系统调用,实现更高的效率,三种缓冲机制为: 全缓冲:当流的缓冲区无数据或无空间时才执行实际I/O操作 行缓冲:当在输入输出中遇到换行符(‘\n’)时,进行I/O操作。 无缓冲:...
  • 文件IO和标准IO区别及其效率

    千次阅读 2016-10-16 21:10:20
    文件IO 就指的是我们通常讲的open、close、write、read等API函数构成的一套用来读写...标准IO有一系列的C库函数构成(fopen,fclose,fwrite,fread),这些标准IO函数其实是有文件IO封装而来的(fopen内部还是调用了op
  • write():常用来写文件,定义如下: #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 参数含义: fd: 文件描述符;...实验代码在io/io3.c:路径为:11_Linux系统开发
  • fgets(): 从文件流中读取一行,并把它存储在 s 所指向的字符串内, #include <stdio.h> char *fgets(char *s, int size, FILE *stream); 参数含义: s:数组指针,读到的字符串储存在此数组内; size:读取的...
  • 使用fwrite()将当前系统时间写入文件, #include #include #include #include #include char * tm; char * get_time(void); int main(int argc, const char *argv[]) { int ret; FILE *filp; char * ptm; char time...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,163
精华内容 1,265
关键字:

文件io和标准io