I/O

学习笔记(一)之I/O

输入:数据从内核空间-->用户空间 scanf
输出:数组从用户空间-->内核空间 printf

linux中文件类型:b:块设备文件,c:字符设备文件,d:目录文件,-:普通文件,l:链接文件,s:套接字文件,p:管道文件

标准IO 利用文件流指针对文件操作
1.C库调用(属于用户空间) man 3
2.移植性强 高级IO
3.自带缓存
行缓存 标准输出 stdout
1k 1024byte
刷新条件:1.'\n' 2.满了 3.程序正常退出 4.fflush
fflush
int fflush(FILE *stream);

 1 #include <stdio.h>
 2 
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7     printf("hello world");
 8     fflush(NULL);
 9     while(1)
10     {
11         ;
12     }
13     return 0;
14 }
fllush


功能:按照参数刷新指定流,填NULL时刷新所有打开的输出流
返回值:成功返回0,失败返回EOF -1 并设置errno号

全缓存 标准输入 stdin
4k 4*1024byte
刷新条件:1.满了 2.程序正常退出 3.fflush 4.关闭流

无缓存 标准错误 stderr

流指针:
FILE * == struct _IO_FILE *
typedef struct _IO_FILE FILE;

对文件操作:
1.打开文件:fopen
FILE *fopen(const char *path, const char *mode);
参数:1.文件所在路径(字符串形式) 2.对文件的访问权限(字符串形式)
mode:
r:只读打开文件,文件指针指向文件开头,若文件不存在,报错
r+:读写打开文件,文件指针指向文件开头,若文件不存在,报错
w:只写打开文件,文件存在,清空文件,文件不存在,创建该文件,文件指针指向文件开头
w+:读写打开文件,文件存在,清空文件,文件不存在,创建该文件,文件指针指向文件开头
a:如果文件不存在,创建该文件,文件存在,再文件末尾追加 (文件指针指向文件末尾)
a+:读和追加模式,如果文件不存在,创建该文件,文件存在,在文件末尾追加 (指针指向文件末尾) 读操作时,从文件开头读

返回值:成功返回该文件的文件流指针,失败返回NULL,并设置errno
errno:指定的一些错误 使用时加头文件:#include <errno.h>
strerror:将errno号对应的错误信息转换成字符串
char *strerror(int errnum);

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <errno.h>
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {   
 8     //打开文件
 9     FILE *fp = NULL;
10     fp = fopen("./444.txt","a+");
11     if(fp == NULL)
12     {
13         fprintf(stderr,"fail to fopen:%s\n",strerror(errno));    
14         return -1;
15     }
16 
17     //关闭文件
18     fclose(fp);
19 
20     return 0;
21 }
strerror

fprintf
int fprintf(FILE *stream, const char *format, ...);
功能:将信息打印到指定的流上
参数:1.指定流 2.格式控制串 3.输出表
注:fprintf(stdout,....) == printf(....)

容错函数:perror
void perror(const char *s);
参数:自己书写的报错信息

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {   
 7     //打开文件
 8     FILE *fp = NULL;
 9     fp = fopen("./111.txt","r");
10     if(fp == NULL)
11     {
12         perror("fail to fopen");
13         return -1;
14     }
15 
16     //关闭文件
17     fclose(fp);
18 
19     return 0;
20 }
perror

关闭文件:fclose
int fclose(FILE *fp);
功能:关闭指定文件

字符输入输出:
fgetc:从指定流中获取单个字符
int fgetc(FILE *stream);
返回值:成功返回获取到字符的ascii码,失败返回EOF 注:1.error 2.文件末尾判断:feof
fgetc(stdin) == getchar()

 1 #include <stdio.h>
 2 
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7     int ret;
 8     ret = fgetc(stdin);
 9     printf("%c\n",ret);
10     return 0;
11 }
fgetc

int feof(FILE *stream);

功能:判断是否到达文件末尾
返回值:到达文件末尾返回非0值

fputc:将单个字符输出到指定的流中
int fputc(int c, FILE *stream);
参数:1.字符的ascii码 2.指定的流
返回值:成功返回输出字符的ascii码,失败返回EOF
fputc(..,stdout) == putchar(..)

 1 #include <stdio.h>
 2 
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7 
 8     if(argc != 2)
 9     {
10         fprintf(stderr,"fail to input filename\n");
11         return -1;
12     }
13 
14     FILE * fp = NULL;
15     int ret = 0;
16 
17     fp = fopen(argv[1],"r");
18     if(fp == NULL)
19     {
20         perror("fail to fopen");
21         return -1;
22     }
23 
24     while(1)
25     {
26         ret = fgetc(fp);
27         if(ret == -1)
28         {
29             if(feof(fp))  //判断是否到达文件末尾
30             {
31                 break;
32             }
33             else
34             {
35                 fprintf(stderr,"fail to fgetc\n");
36                 return -1;
37             }
38         }
39         
40         fputc(ret,stdout);
41 
42     }
43 
44     fclose(fp);    
45     return 0;
46 }
mycat_fgetc

按行输入输出
fgets
char *fgets(char *s, int size, FILE *stream);
参数:1.应用层buf(用于存放fgets获取的一行数据) 2.安全枷锁(sizeof(buf)) 3.指定流
功能:从指定流中读取一行数据,并在末尾自动加上'\0',并且会将'\n'作为字符读入
返回值:成功返回获取字符串的首地址,失败返回NULL 注:1.error 2.判断文件末尾 feof
例如:
char a[10]
fgets(a,10,stdin); 除了'\0'做多只能存放9个字符
注:
1.fgets(a,sizeof(a),stdin); == gets(a);
2.fgets不能对图片操作,会损坏图片

gets :该函数可以淘汰了,没有安全性的检查,很容易造成数组越界导致段错误
char *gets(char *s);

fputs
int fputs(const char *s, FILE *stream);
参数:1.需要输出的内容 2.指定流
功能:将字符串输出到指定的流上,fputs末尾不会自动加'\n'
fputs(s,stdout); == puts(s);

 1 #include <stdio.h>
 2 
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7     char array[10];
 8     fgets(array,sizeof(array),stdin);
 9 //    gets(array);
10     fputs(array,stdout);
11     return 0;
12 }
fgets

清空函数:
#include <strings.h>
bzero
void bzero(void *s, size_t n); size_t == unsigned int
参数:1.需要被操作的空间的首地址 2.空间大小
功能:根据首地址将该空间清空

#include <string.h>
memset
void *memset(void *s, int c, size_t n);
参数:1.需要被操作的空间的首地址 2.想要变成的数值(例如'\0' 'a') 3.空间大小
功能:根据首地址将空间内的内容变成指定的内容int c
memset(a,0,sizeof(a)) == bzero(a,szieof(a))

#include <stdio.h>
#include <strings.h>


int main(int argc, const char *argv[])
{

    if(argc != 2)
    {
        fprintf(stderr,"fail to input filename\n");
        return -1;
    }

    FILE * fp = NULL;
    char a[10];

    fp = fopen(argv[1],"r");
    if(fp == NULL)
    {
        perror("fail to fopen");
        return -1;
    }

    while(1)
    {
        bzero(a,sizeof(a));
        //memset(a,0,sizeof(a));
            
        if(NULL == fgets(a,sizeof(a),fp))
        {
            if(feof(fp))
            {
                break;
            }
            else
            {
                fprintf(stderr,"fail to fgets!\n");
                return -1;
            }            
        }
        fputs(a,stdout);
    }

    fclose(fp);    
    return 0;
}
mycat_fgets

按块输入输出

fread

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数:1.应用层准备的buf(用于保存即将读取的数据) 2.单个块的大小
3.最多一次能搬运的块数sizeof(ptr)/sizeof(size) 4.指定流
返回值:成功返回读取的块数的个数 失败返回0 注:1.error 2.到达文件末尾feof

fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
参数:1.buf 2.单个块的大小 3.最多一次书写的块数(看fread的脸色,参照fread的返回值)(读多少写多少)
4.指定流

 1 #include <stdio.h>
 2 #include <strings.h>
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7 
 8     if(argc != 2)
 9     {
10         fprintf(stderr,"fail to input filename\n");
11         return -1;
12     }
13 
14     FILE * fp = NULL;
15     int ret;
16     char buf[10];
17 
18 
19 
20     fp = fopen(argv[1],"r");
21     if(fp == NULL)
22     {
23         perror("fail to fopen");
24         return -1;
25     }
26 
27     while(1)
28     {
29         bzero(buf,sizeof(buf));
30         ret = fread(buf,sizeof(char),sizeof(buf)/sizeof(char),fp);
31         if(ret < 0)
32         {
33             fprintf(stderr,"fail to fread!\n");
34             return -1;
35         }
36         else if(ret == 0)
37         {
38             break;
39         }
40         else
41         {
42             fwrite(buf,sizeof(char),ret,stdout);//读多少写多少
43         }
44     }
45 
46     fclose(fp);    
47     return 0;
48 }
mycat_fread

fseek:文件指针偏移
int fseek(FILE *stream, long offset, int whence);
参数:1.文件流指针 2.偏移量 +向后偏移 -向前偏移
3.相对位置 SEEK_SET 文件开头 SEEK_CUR 当前位置 SEEK_END 文件末尾
返回值:成功返回0,失败返回-1,并设置errno号
注:文件开头不能像前偏移,文件末尾也最好不要向后偏移(文件空洞)

ftell:告诉当前文件指针距离文件开头的偏移量
long ftell(FILE *stream);

rewind:将文件指针回归文件开头
void rewind(FILE *stream);

 1 #include <stdio.h>
 2 
 3 
 4 
 5 int main(int argc, const char *argv[])
 6 {
 7     FILE *fp;
 8     int ret;
 9     fp = fopen("./log.txt","r+");
10     if(fp == NULL)
11     {
12         perror("fail to fopen");
13         return -1;
14     }
15 
16     fseek(fp,10,SEEK_SET);
17     ret = ftell(fp);
18     printf("%d\n",ret);
19 
20     rewind(fp);
21     printf("%ld\n",ftell(fp));
22 
23     return 0;
24 }
fseek

文件IO 利用文件描述符对文件操作
1.系统调用 man 2 注:系统调用:内核提供的函数接口
2.移植性差 低级IO
3.无缓存(内核缓存)

文件描述符:本质是一个整型数值 (其实是数组下标,是索引)
1.在当前操作系统中,一个程序打开的文件描述符取值范围0~1023 共1024
2.默认打开的三个文件描述符: 0 stdin , 1 stdout , 2 stderr
3.每当打开新的文件时,分配的文件描述符总是最小且未使用的文件描述符

打开文件:open
int open(const char *pathname, int flags); 直接访问文件时使用
int open(const char *pathname, int flags, mode_t mode); 创建文件时使用
参数:1.文件路径(字符串形式) 2.旗帜
3.创建权限mode (在使用O_CREAT时才会使用) 直接书写想要的权限例如 0666 0777
注:最终真实得到的文件权限 mode & ~umask 当前目录下输入umask就能看到文件权限掩码

flag: 想要的功能通过 '|' 的方式组合
访问旗:O_RDONLY只读 O_WRONLY只写 O_RDWR读写 flag必须包含有且一个访问旗
创建旗:O_CREAT创建 O_EXCL测试是否文件存在(通常情况下与O_CREAT连用) O_TRUNC 清空
状态旗:后期学习

返回值:成功返回文件描述符,失败返回-1,并设置errno号

例子:
r:O_RDONLY | O_EXCL
w:O_WRONLY | O_CREAT | O_TRUNC
a:O_WRONLY | O_APPEND | O_CREAT

关闭文件:close
int close(int fd); 

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11 #if 0
12     //直接访问形式的open样例
13     int fd;
14     fd = open("./log.txt",O_RDONLY);    
15     if(fd == -1)
16     {
17         perror("fail to open");
18         return -1;
19     }
20 
21 
22 #endif
23     //创建时open样例
24     int fd;
25     int flag = O_WRONLY | O_CREAT | O_EXCL; 
26     fd = open("./1.txt",flag,0666);
27     if(fd == -1)
28     {
29         perror("fail to open");
30         return -1;
31     }
32 
33 
34 
35     close(fd);
36     return 0;
37 }
open

输入输出函数:
read
ssize_t read(int fd, void *buf, size_t count);
参数:1.文件描述符 2.应用层准备的buf(用于接收数据) 3.buf的大小,一次最多读取的数据大小限制
返回值:成功时返回真实读取字节的个数 返回0时表示数据读取完毕,到达文件末尾
返回-1时代表错误,并设置errno号

write
ssize_t write(int fd, const void *buf, size_t count);
参数:1.文件描述符 2.应用层准备的buf(用于输出的数据)
3.和read连用时,该参数需要参照read的返回值,读多少写多少
返回值:-1表示出错,并设置errno号

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <strings.h>
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     int fd1,fd2;
12     char buf[20];
13     int ret_read;
14     fd1 = open("./log.txt",O_RDONLY);
15     if(fd1 == -1)
16     {
17         perror("fail to open1");
18         return -1;
19     }
20 
21     fd2 = open("./2.txt",O_WRONLY | O_CREAT | O_EXCL,0666);
22     if(fd2 == -1)
23     {
24         perror("fail to open2");
25         return -1;
26     }
27 
28 
29 
30     while(1)
31     {
32         bzero(buf,sizeof(buf));
33         ret_read = read(fd1,buf,sizeof(buf));
34         if(ret_read < 0)
35         {
36             perror("fail to read");
37             return -1;
38         }
39         else if(ret_read == 0)
40         {
41             break;
42         }
43         else
44         {
45             write(fd2,buf,ret_read);  //读多少写多少
46         }
47     }
48 
49     close(fd1);
50     close(fd2);
51     return 0;
52 }
mycp_read
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 #include <strings.h>
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     int fd;
12     char buf[20];
13     int ret_read;
14     fd = open("./log.txt",O_RDONLY);
15     if(fd == -1)
16     {
17         perror("fail to open");
18         return -1;
19     }
20 
21     while(1)
22     {
23         bzero(buf,sizeof(buf));
24         ret_read = read(fd,buf,sizeof(buf));
25         if(ret_read < 0)
26         {
27             perror("fail to read");
28             return -1;
29         }
30         else if(ret_read == 0)
31         {
32             break;
33         }
34         else
35         {
36             write(1,buf,ret_read);  //读多少写多少
37         }
38     }
39 
40     close(fd);
41     return 0;
42 }
mycat_read

lseek:文件偏移
off_t lseek(int fd, off_t offset, int whence);
参数:1.文件描述符 2.偏移量 +向后偏移 -向前偏移 3.相对位置 SEEK_SET SEEK_CUR SEEK_END
功能:参照相对位置偏移大小
返回值:成功返回距离文件开头相差的字节数 失败返回-1并设置errno号

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <unistd.h>
 6 
 7 
 8 
 9 int main(int argc, const char *argv[])
10 {
11     int fd;
12     off_t ret;
13     fd = open("./log.txt",O_RDONLY);
14     if(fd == -1)
15     {
16         perror("fail to open");
17         return -1;
18     }
19 
20     ret = lseek(fd,10,SEEK_SET);
21     
22     printf("%d\n",(int)ret);
23 
24 
25     close(fd);
26     return 0;
27 }
lseek

练习:
time

localtime

 1 #include <stdio.h>
 2 #include <time.h>
 3 #include <unistd.h>
 4 
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     time_t t;
 9     struct tm *p = NULL;
10     char * week[] = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
11     FILE * fp = NULL;
12 
13     fp = fopen("./log.txt","a");
14     if(fp == NULL)
15     {
16         perror("fail to fopen");
17         return -1;
18     }
19 
20     while(1)
21     {
22         t = time(NULL);
23         p = localtime(&t);
24         fprintf(fp,"%d-%d-%d %d-%d-%d %s\n"
25                 ,p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec,week[p->tm_wday]);
26         fflush(fp);
27         sleep(1);
28     }
29 
30 
31 
32     fclose(fp);
33     return 0;
34 }
localtime

ctime

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <time.h>
 4 
 5 
 6 
 7 int main(int argc, const char *argv[])
 8 {
 9     time_t t;
10     while(1)
11     {
12         t = time(NULL);
13         printf("%s\n",ctime(&t));
14         sleep(1);
15     }
16     return 0;
17 }
ctime

扩展:
opendir man 3
DIR *opendir(const char *name);
功能:打开目录文件
参数:目录路径
返回值:成功返回目录流指针,失败返回NULL,1并设置errno号

closedir
int closedir(DIR *dirp);
功能:关闭指定目录

readdir
struct dirent *readdir(DIR *dirp);
参数:目录流指针
功能:读取目录中的文件信息
返回值:成功返回记录该目录下文件信息的结构体指针struct dirent* 失败返回NULL,如果errno为0则代表读取到目录末尾如果不为0则error,并设置errno号
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <dirent.h>
 4 #include <errno.h>
 5 
 6 int main(int argc, const char *argv[])
 7 {
 8     if(argc != 2)
 9     {
10         fprintf(stderr,"please input dirname!\n");
11         return -1;
12     }
13 
14     DIR *dp;
15     struct dirent * p = NULL;
16     dp = opendir(argv[1]);
17     if(dp == NULL)
18     {
19         perror("fail to opendir");
20         return -1;
21     }
22     
23     while(1)
24     {
25         p = readdir(dp);
26         if(p == NULL)
27         {
28             if(errno == 0)
29             {
30                 break;
31             }
32             else
33             {
34                 perror("fail to readdir");
35                 return -1;
36             }
37         }
38 
39 
40         printf("%s\n",p->d_name);
41 
42     }
43 
44     closedir(dp);
45     return 0;
46 }
ls

stat:获取文件详细信息 man 2
int stat(const char *path, struct stat *buf);
参数:1.文件路径2.文件信息结构体
注:(双向传参) 在应用层准备对应数据类型的空间,并将该空间首地址传入函数,函数执行结束后,内核将结果通过地址返回

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <dirent.h>
 4 #include <errno.h>
 5 #include <sys/stat.h>
 6 #include <unistd.h>
 7 #include <strings.h>
 8 struct stat buf;
 9 
10 
11 int fun(char *name);
12 
13 
14 int main(int argc, const char *argv[])
15 {
16     if(argc != 2)
17     {
18         fprintf(stderr,"please input dirname!\n");
19         return -1;
20     }
21 
22     DIR *dp;
23     struct dirent * p = NULL;
24     //打开目录文件
25     dp = opendir(argv[1]);
26     if(dp == NULL)
27     {
28         perror("fail to opendir");
29         return -1;
30     }
31     
32     while(1) //循环读取目录中文件信息
33     {
34         p = readdir(dp);
35         if(p == NULL)
36         {
37             if(errno == 0)
38             {
39                 break;
40             }
41             else
42             {
43                 perror("fail to readdir");
44                 return -1;
45             }
46         }
47         //获取该目录下文件的名字,传递给fun函数执行
48         fun(p->d_name);
49 
50     }
51 
52     closedir(dp);
53     return 0;
54 }
55 
56 //调用stat函数获取文件信息
57 int fun(char *name)
58 {
59     bzero(&buf,sizeof(buf));
60     stat(name,&buf);
61     switch(buf.st_mode & S_IFMT)
62     {
63         case S_IFSOCK:
64             printf("s ");
65             break;
66         case S_IFLNK:
67             printf("l ");
68             break;
69         case S_IFREG:
70             printf("- ");
71             break;
72         case S_IFBLK:
73             printf("b ");
74             break;
75         case S_IFDIR:
76             printf("d ");
77             break;
78         case S_IFCHR:
79             printf("c ");
80             break;
81         case S_IFIFO:
82             printf("p ");
83             break;
84     }
85 
86     printf("%ld %s\n",buf.st_size,name);
87 
88     return 0;
89 }
stat

库:


ELF文件 可执行可链接格式

静态库 在编译时需求 在运行时不需求
特点:编译生成的文件会较大,编译完成后运行时可以脱离静态库运行
静态库的制作:
1.gcc -c 需要被制作的文件.c -o 需要被制作的文件.o
例如:gcc -c fun1.c -o fun1.o
2.ar crs lib库名.a 需要被制作的文件.o
例如:ar crs libmyhello.a fun1.o
运行时链接库:
3.gcc xxx.c -o xxx -L(指定静态库所在路径)路径 -l库名
例如:gcc main.c -o hello -L. -lmyhello

动态库 在编译时不需求 在运行时需求
特点:编译时不需求动态库,生成的文件较小,但是运行时需要加载动态库的代码
动态库的制作:
1.gcc -fPIC -Wall -c 需要被制作的文件.c
例如: gcc -fPIC -Wall -c fun1.c
2.gcc -shared -o lib库名.so 需要被制作的文件.o
例如:gcc -shared -o libhqyj.so fun1.o
3.gcc xxx.c -L. -l库名
例如:gcc main.c -L. -lhqyj
4.mv lib库名.so /lib 或者 /usr/lib
例如:sudo mv libhqyj.so /lib

原文地址:https://www.cnblogs.com/hslixiqian/p/9558933.html