Linux中,一切皆文件!
1.文件IO
浏览书本:《4.2.1系统IO》和《4.2.2标准IO》
问题:
- 两种IO操作方式有何相同点?不同点?关系?
相同点:两种方式都是用于操作文件。
不同点:
系统IO:在操作系统层面,由系统提供。
标准IO:在库函数层面,由标准C库提供。
(关系:标准IO函数,其本质也是调用系统IO)
- 他们的优缺点是什么?
系统IO:由系统提供,有最基本的操作函数。(简洁、精炼)(类似于菜市场)
好处:简洁单一,稳定,不需要消耗过多系统资源。
缺点:对于功能性要求较高的程序,更加繁琐。
标准IO:由标准C库提供,拥有多样化的操作函数。(功能多样)(类似于饭馆)
好处:复杂操作更为方便,函数接口更加多样化。
缺点:消耗系统资源更多,不适用于简单功能。
2.系统IO
——》在操作系统层面,由系统提供。
常用的接口函数:
- 文件的打开 open();
- 文件的关闭 close();
- 文件的写入 write();
- 文件的读取 read();
- 文件的偏移 lseek();
备注:
- 查看函数的用法:
直接查看man手册
查阅相关函数资料(书籍、网络)
- open打开文件描述符范围:3 ~ 1023
- 文件描述符 0~2分别对应不同的设备,自行open只能分配3以上。
- 当不再使用某个文件时,记得close关闭文件,释放资源。
(当程序结束时,所有资源也都会被释放)
- 文件偏移量:
也称为读写偏移量,读写操作都会先后移动。
每次重新打开一个文件,文件偏移量默认为0(位于文件开头)
3.主函数传参功能
主函数形式:
- 无参形式:
int main() int main(void) //等同于上一个
- 带参形式:
int main(int argc, const char *argv[]) int main(int argc, const char **argv)
4.系统IO常用函数
- 控制硬件设备(绕过应用层,直接与驱动层通信)
#include <sys/ioctl.h> int ioctl(int fd, unsigned long request, ...);
备注:
- 函数的形参个数最少2个,最多不限,由驱动程序决定。
比如6818开发板的蜂鸣器驱动有3个参数:
int ioctl(蜂鸣器硬件文件描述符, 电平状态, 引脚号);
蜂鸣器设备:”/dev/beep”
电平状态: 低电平0,高电平1(分别控制蜂鸣器响/不响)
引脚号: 固定为1号引脚
- 复制文件描述符:
dup和dup2
备注:
dup函数由系统自动分配最小且未用的文件描述符
dup2函数分配指定的文件描述符,如指定文件描述符已使用,会被替代。
- 文件控制:(软件、硬件。。)
fcntl()
备注:
可实现类似于dup和dup2的功能。
打开文件后,仍然能够设置/获取文件描述符的属性,无需重新打开文件。
- 内存映射 (作用:将文件与内存进行关联,提高操作效率!)
mmap()
空洞文件有什么用呢?空洞文件对多线程共同操作文件是及其有用的,有时候我们创建一个很大的文件,如果单个线程从头开始依次构建该文件需要很长的时间,有一种思路就是将文件分为多段,然后使用多线程来操作,每个线程负责其中一段数据的写入;这个有点像我们现实生活当中施工队修路的感觉,比如说修建一条高速公路,单个施工队修筑会很慢,这个时候可以安排多个施工队,每一个施工队负责修建其中一段,最后将他们连接起来。
来看一下实际中空洞文件的两个应用场景:
在使用迅雷下载文件时,还未下载完成,就发现该文件已经占据了全部文件大小的空间,这也是空洞文件;下载时如果没有空洞文件,多线程下载时文件就只能从一个地方写入,这就不能发挥多线程的作用了;如果有了空洞文件,可以从不同的地址同时写入,就达到了多线程的优势;
在创建虚拟机时,你给虚拟机分配了 100G 的磁盘空间,但其实系统安装完成之后,开始也不过只用了 3、4G 的磁盘空间,如果一开始就把 100G 分配出去,资源是很大的浪费。
1.open.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) fd = open("1.txt", O_RDWR); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d]\n", fd); return 0; }
2.open_close.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) int cnt=1; while(1) { // 打开 fd = open("1.txt", O_RDWR); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d][%d]\n", fd, cnt++); // 关闭 // close(fd); } return 0; }
3.creat.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) // 打开 fd = open("a.txt", O_RDWR|O_CREAT|O_EXCL, 0644); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d]\n", fd); // 关闭 close(fd); return 0; }
4.write.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) // 1.打开(不存在则创建,存在则直接打开) fd = open("1.txt", O_RDWR|O_CREAT, 0644); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d]\n", fd); // 2.写入 // sizeof(str1) :计算的是指针的大小(64位都是8字节) char *str1 = "a"; int n_write = write(fd, str1, strlen(str1)); printf("%d write\n", n_write); // 关闭 close(fd); return 0; }
5.read.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) // 1.打开 fd = open("1.txt", O_RDONLY, 0644); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d]\n", fd); // 2.读取 char r_buf[10]; bzero(r_buf, sizeof(r_buf)); int n_read = read(fd, r_buf, sizeof(r_buf)); printf("[%d]: %s\n", n_read, r_buf); // 3.关闭 close(fd); return 0; }
6.lseek偏移
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { // 文件路径: //相对路径:1.txt //绝对路径:/mnt/hgfs/GZ2203/04 文件IO/01 系统IO/code/1.txt int fd; // 文件描述符(操作句柄,文件编号) // 1.打开 fd = open("1.txt", O_RDWR); if(fd == -1) { perror("open failed"); // 打印错误信息 return -1; } printf("open success![%d]\n", fd); // 2.写入 char w_buf[100] = "Lisi"; int n_write = write(fd, w_buf, strlen(w_buf)); printf("%d write\n", n_write); // 3.文件偏移量修改 // lseek(fd, -4, SEEK_CUR); // 从当前位置向前偏移4个字节 lseek(fd, 0, SEEK_SET); // 从文件开头,不偏移 // 4.读取 char r_buf[10]; bzero(r_buf, sizeof(r_buf)); int n_read = read(fd, r_buf, sizeof(r_buf)); printf("read[%d]: %s\n", n_read, r_buf); // 5.关闭 close(fd); return 0; }
7.读写偏移.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { // 1.打开文件 int fd; fd = open("1.txt", O_RDWR); if(fd == -1) { perror("open failed"); return -1; } // 2.输入名字并写入指定位置 char name[10] = {0}; printf("Pls Input: "); scanf("%s", name); while(getchar()!='\n'); // 偏移到指定位置并写入 lseek(fd, 6, SEEK_SET); write(fd, name, strlen(name)); // 3.读取文件内容 // 偏移到开头并读取 lseek(fd, 0, SEEK_SET); char r_buf[100]; bzero(r_buf, sizeof(r_buf)); int n_read = read(fd, r_buf, sizeof(r_buf)); printf("read(%d): %s\n", n_read, r_buf); // 4.关闭文件 close(fd); return 0; }
8.主函数传参.c
#include <stdio.h> // 主函数 // arg:argument形参简称 // c:count计数 // v:varible变量 // int main(int argc, const char *argv[]) int main(int argc, const char **argv) { int i; for(i=0; i<argc; i++) printf("argv[%d]: %s\n", i, argv[i]); return 0; }
9.ioctl控制蜂鸣器.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> int main() { // 1.打开蜂鸣器 int beep_fd = open("/dev/beep", O_RDWR); if(beep_fd == -1) { perror("open beep failed"); return -1; } // 2.控制蜂鸣器 int i; for(i=0; i<3; i++) { ioctl(beep_fd, 0, 1); //响 sleep(1); ioctl(beep_fd, 1, 1); //不响 sleep(1); } // 3.关闭蜂鸣器 close(beep_fd); return 0; }
10.dip和dup2复制文件描述符.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> int main() { int fd = open("1.txt", O_RDWR); if(fd == -1) { perror("open failed"); return -1; } // 复制文件描述符,由系统分配新的文件描述符(最小、未用) int new_fd1 = dup(fd); char ch; lseek(fd, 0, SEEK_SET); read(fd, &ch, 1); printf("fd(%d): %c\n", fd, ch); lseek(new_fd1, 0, SEEK_SET); read(new_fd1, &ch, 1); printf("new_fd1(%d): %c\n", new_fd1, ch); // 复制文件描述符,自行指定新的文件描述符 int new_fd2 = dup2(fd, 100); lseek(new_fd2, 0, SEEK_SET); read(new_fd2, &ch, 1); printf("new_fd2(%d): %c\n", new_fd2, ch); return 0; }