alin的学习之路(Linux系统编程:四)(Makefile,文件I/O)
alin的学习之路(Linux系统编程:四)(Makefile,文件I/O)
编码格式的调整:
visual stuio 中用的是GBK的编码,我们在Linux vim 里用的是 utf-8 编码。
vim 的末行模式下:
:set fileencoding=utf8 // 将文件修改为 utf-8 编码
1.Makefile
-
概述:Makefile是文件编译工具,方便源文件编译成可执行文件。Makefile 是一个文本文件,一个包含了编译规则的文本文件。在项目中敲击一个命令:make ,即可完成编译。
-
文件命名:Makefile 或 makefile
-
编写规则
目标 : 依赖 由依赖生成目标的命令
目标:要生成的文件 - 依赖:制作目标文件的材料
- 命令:执行该命令能够通过依赖文件制作出目标文件
- 如果Makefile有多个规则,默认执行第一个规则
- 第一个规则中的依赖文件如果不存在,则从文件中向后找其他规则有没有能够生成该依赖文件的
书写Makefile
# $(wildcard 文件路径) 表示指定路径下的所有匹配文件 # 假设要获取当前路径下的所有.c文件 # $(wildcard ./*.c) # # $(patsubst 被替换模式,替换模式,进行操作的文件内容) # 假设要将所有.c 替换成.o # $(patsubst %.c,%.o,a.c b.c c.c) srcs=$(wildcard ./*.c) objs=$(patsubst %.c,%.o,$(srcs)) target=app $(target) : $(objs) gcc $^ -o $@ -I include/ # gcc $(objs) -o $(taregt) -I include/ %.o : %.c gcc -c $< -o $@ -I include/ # .PHONY 指的该文件是一个虚拟文件,不需要创建出来这个文件,仅执行该目标文件下的命令 .PHONY:clean clean: rm $(target) $(objs)
srcs、objs、target都是定义变量,用来减少下面书写的代码,使用
$(变量名)在后面使用
表示上面规则中的全部依赖文件,^ 表示上面规则中的全部依赖文件,表示上面规则中的全部依赖文件,< 表示上面规则中的依赖文件中的第一个,$@ 表示目标文件
规则中的%表示可以匹配任意字符,例如:%.c 表示匹配任意名字的 .c 文件
注意:在Makefile规则中%表示通配,路径中*表示通配
Makefile中特有的函数(通俗理解为字符串操作函数)
$(wildcard 文件路径) 表示指定路径下的所有匹配文件
假设要获取当前路径下的所有.c文件
$(wildcard ./*.c)
$(patsubst 被替换模式,替换模式,进行操作的文件内容)
假设要将所有.c 替换成.o
$(patsubst %.c,%.o,a.c b.c c.c)
.PHONY:目标名表示虚拟文件,即不需要创建出这个文件,仅执行目标文件下的命令
2.Linux I/O
-
标准I/O与系统I/O的区别:
标准I/O自带缓冲区,系统I/O不带缓冲区 - 标准I/O通过调用系统I/O完成I/O操作
- 标准I/O的fopen返回的是一个FILE类型的指针,而系统I/O的open返回的是一个大小为(0-1023)的文件描述符
fopen与open的效率对比:
-
fread 会从用户空间的缓冲区读,如果用户空间的缓冲区没有内容了,会进入到内核空间调用一次read从磁盘读数据到内核缓冲区,再把内核缓冲区的数据拷贝到用户缓冲区,fread读用户缓冲区即可
程序和文件:
程序运行时,会默认打开 3 个文件:标准输入文件、标准输出文件、标准错误文件。
-
对于标准IO函数而言:stdin、stdout、stderr , 这 3 个都是 FILE 类型的指针。
字,文件描述符。这三个定义在 unistd.h 头文件中
3.Linux I/O 函数
1.文件打开、关闭、读写
-
open函数:
int open (const char *file, int oflag, ...)
-
头文件:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
-
当打开一个文件的时候,如果文件不存在则创建。Linux 中文件是有权限的,创建时候需要指定权
限。由 mode 参数指定文件权限。 -
int open(const char *pathname, int flags); 用于打开已经有的文件,不需要传递第三个参数。
-
mode 参数
int open(const char *pathname, int flags, mode_t mode);
如果文件不存在,要创建,则
需要传递第三参数 mode,实际创建文件的权限 = 指定的权限 - 掩码。 - mode 参数可以写数字法:0777(八进制,前面一定要加0)
- 指定宏写法:比如:希望文件的权限是,用户读、组用户写、其他用户执行:S_IRUSR | S_IWGRP |
S_IXOTH
oflag 参数:
-
O_RDONLY(只读打开文件)、O_WRONLY(只写打开文件)、O_RDWR(读写打开文
件)、O_CREAT(创建文件)、O_APPEND(追加方式打开文件)
open 函数的打开模式中并没有区分文本模式和二进制模式:因为Linux系统函数仅在系统中使用,没有行结尾的相异
成功则返回文件描述符,失败则返回-1,此时 errno 会被设置为相应的错误码,使用 perror函数
可打印详细的错误描述。
write 函数
ssize_t write(int fd, const void *buf, size_t count);
include <unistd.h>
误码。我们可以使用 perror 函数打印错误信息。
read 函数
ssize_t read(int fd, void *buf, size_t count);
#include <unistd.h>
perror 可以打印该错误码对应的详细错误描述。
close 函数
-
头文件:
#include <unistd.h>
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>#include <unistd.h> #include <string.h> void test01() { int fd; fd = open("demo01.txt",O_WRONLY | O_CREAT,0777); if(fd == -1) { perror("open"); return; } const char* data = "hello world\n"; int len = write(fd,data,strlen(data)); if(len == -1) { perror("write"); return; } int ret = close(fd); if(-1 == ret) { perror("close"); return; } } void test02() { int fd; fd = open("demo01.txt",O_RDONLY); if(fd == -1) { perror("open"); return; } char buf[128] = { 0 }; int len = read(fd,buf,128); if(len == -1) { perror("write"); return; } printf("buf = %s",buf); int ret = close(fd); if(-1 == ret) { perror("close"); return; } } int main() { //test01(); test02(); return 0; }
2.文件随机读写
lseek 函数可以实现移动文件指针,从而实现随机文件读写。
off_t lseek(int fd, off_t offset, int whence);
头文件:
#include <sys/types.h> #inlude <unistd.h>
- fd 文件描述符
- offset 偏移量
- whence 相对位置 SEEK_SET 开始位置
- SEEK_CUR 当前位置
- SEEK_END 尾部位置
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>#include <unistd.h> struct Person{ char name[32]; int age; }; void test01() { struct Person persons[] = { {"Obama",50}, {"Smith",60}, {"Trump",70} }; int fd = open("person.txt",O_WRONLY | O_CREAT,0777); if(-1 == fd) { perror("open"); return; } int len = write(fd,persons,sizeof(persons)); if(-1 == len) { perror("write"); return; } int ret = close(fd); if(-1 == ret) { perror("close"); return; } } void test02() { int fd = open("person.txt",O_RDONLY); if(-1 == fd) { perror("open"); return; } struct Person p1; int len = read(fd,&p1,sizeof(struct Person)); if(-1 == len) { perror("read"); return; } printf("Name:%s Age:%d\n",p1.name,p1.age); int ret = lseek(fd,sizeof(struct Person),SEEK_CUR); if(-1 == ret) { perror("lseek"); return; } struct Person p2; len = read(fd,&p2,sizeof(struct Person)); if(-1 == len) { perror("read"); return; } printf("Name:%s Age:%d\n",p2.name,p2.age); ret = close(fd); if(-1 == ret) { perror("close"); return; } } int main() { test01(); test02(); return 0; }
3.文件信息获取
stat 函数可以获取文件的信息。
-
int stat(const char *pathname, struct stat *statbuf);
-
头文件:
#include <sys/types.h> #include <sys/stat.h> #include <unistd.h>
-
pathname 指的是文件的路径。
-
statbuf (传入传出参数)保存获取的文件信息。
-
成功返回0,失败返回 -1,并且 errno 会被设置为合适的值,使用 perror 函数打印。
-
**manpage查看:**stat结构体在
man 2 stat
中,st_mode中一些宏的查看在man 7 inode
-
struct stat 结构体:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */ mode_t st_mode; /* 文件的类型、文件的权限*/ nlink_t st_nlink; /* 文件的硬链接数 */ uid_t st_uid; /* 文件所有者ID */ gid_t st_gid; /* 文件所有者组ID */ dev_t st_rdev; /* Device ID (if special file) */ off_t st_size; /* 文件大小*/ blksize_t st_blksize; /* Block size for filesystem I/O */ blkcnt_t st_blocks; /* Number of 512B blocks allocated */ struct timespec st_atim; /* Time of last access */ struct timespec st_mtim; /* Time of last modification */ struct timespec st_ctim; /* Time of last status change */ };
-
示例代码:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>#include <unistd.h> void test01() { struct stat info; int ret = stat("demo01.txt",&info); if(-1 == ret) { perror("stat"); return; } printf("文件大小为:%ld\n",info.st_size); if(S_ISREG(info.st_mode)) { printf("普通文件\n"); } if(S_ISDIR(info.st_mode)) { printf("目录文件\n"); } if(S_ISLNK(info.st_mode)) { printf("硬链接\n"); } if(info.st_mode & S_IRUSR) { printf("用户的读权限\n"); } if(info.st_mode & S_IWUSR) { printf("用户的写权限\n"); } if(info.st_mode & S_IXUSR) { printf("用户的执行权限\n"); } if(info.st_mode & S_IRGRP) { printf("用户组的读权限\n"); } if(info.st_mode & S_IWGRP) { printf("用户组的写权限\n"); } if(info.st_mode & S_IXGRP) { printf("用户组的执行权限\n"); } if(info.st_mode & S_IROTH) { printf("其他用户的读权限\n"); } if(info.st_mode & S_IWOTH) { printf("其他用户的写权限\n"); } if(info.st_mode & S_IXOTH) { printf("其他用户的执行权限\n"); } } int main() { test01(); return 0; }
4. 文件大小扩展
使用 truncate 函数可将指定文件扩展为指定大小。
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
注意:off_t 是 long 类型
头文件:
#include <unistd.h> #include <sys/types.h>
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>#include <fcntl.h> void test() { int fd = open("download.txt",O_WRONLY | O_CREAT); if(-1 == fd) { perror("open"); return; } int ret = ftruncate(fd,1024); if(-1 == ret) { perror("ftruncate"); return; } ret = close(fd); if(-1 == ret) { perror("close"); return; } } int main() { test(); return 0; }
- alin的学习之路(Linux系统编程:八)(匿名映射、信号)
- alin的学习之路(Linux系统编程:七)(命名管道、共享存储映射)
- alin的学习之路(Linux系统编程:九)(SIGCHLD、守护进程、线程)
- alin的学习之路(Linux系统编程:十)(互斥锁、读写锁、条件变量、信号量、哲学家就餐问题)
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】揭开Linux Proc文件系统的神秘面纱
- LS8-linux系统调用方式文件编程之学习笔记
- Linux 系统编程学习之文件编程
- 大数据学习之路----linux系统的shell脚本编程(一)
- alin的学习之路(Linux网络编程:三)(高并发服务器-多线程、TCP通信时序状态、多路IO转接select概述)
- Linux学习记录--文件IO操作相关系统编程
- Linux系统学习--文件编程(open,write,read、光标lseek)
- Linux 系统编程学习-文件操作
- Linux 系统编程学习-文件I/O操作
- Linux编程学习笔记--proc文件系统 http://www.cnblogs.com/weichsel/archive/2012/06/23/2559613.html
- LINUX C系统编程学习笔记-----------文件编程
- Linux学习记录--文件管理相关系统编程
- linux 系统编程-学习笔记2-文件I/O-open-read
- Linux编程学习笔记--proc文件系统
- Linux/Unix C编程之系统函数文件读写 学习笔记
- Linux学习记录--文件管理相关系统编程