File IO for Linux system programming
- The first day of file IO
-
- 1. Basic concepts of standard IO
-
- 1.1c language function (c library function) is called to implement a certain function (API)
- 1.2 System call: Program interface in the kernel, the middle layer between applications and hardware devices
- 1.3 Basic concepts of files
- 1.4 File classification *
- 1.5 File pointer FILE* (the difference between standard IO and file IO)
- 1.6 Conversion of file descriptors and file pointers*
- 2. File IO
- File IO the next day
- one,
- 2. Time function
-
- 1. Function prototype: time_t time(time_t *); [Key Points]
- 2. Function prototype: char *ctime(const time_t *); [Key points]
- 3. Function prototype: struct tm *gmtime(const time_t *);
- 4. Function prototype: char *asctime(const struct tm *);
- 5. Function prototype: struct tm *localtime(const time_t *); [Key points]
- 6. Function prototype: time_t mktime(struct tm *tm);
- 3. File attribute function
- 4. Directory operation functions
- File IO third day
The first day of file IO
Standard IO
open file: FILE* fopen (file name string, open mode)
rwa r+ w+ a+
(text file, binary file)
close file: fclose (FILE* p);
read a character: int fgetc (FILE* P);
Write a character: fputc(int c,FILE* P)
Read a string: fgets(char* buf,int size,FILE*)
Write a string: fputs(char* p,FILE* P);
char arr[4 ] = “abc” char* p = “abc”; (Complete memorizing the four memory areas - Jiang Yang) Binary
reading: fread (void* buf, size of each block, number of blocks, file pointer);
Binary writing: fwrite (void*buf, size of each block, number of blocks, file pointer)
Formatted reading: int fscanf(FILE *stream, const char *format, …); Similar to scanf
formatted writing: int fprintf(FILE *stream, const char *format, …); Similar to printf
file offset: fseek, rewind, ftell
(calloc, realloc) malloc -->memset() bzero( )
1. Basic concepts of standard IO
1.1c language function (c library function) is called to implement a certain function (API)
POSIX:可移植操作系统接口,软件需要在linux下运行,API关联的标准的总称
1.2 System call: Program interface in the kernel, the middle layer between applications and hardware devices
1> 文件操作系统调用: 打开文件,关闭文件,读写
2> 进程控制系统调用: 创建进程 关闭进程 ps -aux
3> 通信类控制系统调用: 发送消息,接受消息 socket套接字
4> 设备管理系统调用: 打开设备 关闭设备
5> 信息维护类系统嗲用:用户程序和操作系统之间的信息
1.3 Basic concepts of files
文件:一组相关数据的集合, 文件名:集合的名称
1.4 File classification *
普通文件:touch 文件
目录文件: mkdir 目录名
设备文件: 放在dev目录下,和普通文件一样
字符文件: sudo mknod 字符设备名 c 主编号 次编号
块 设 备: sudo mknod 字符设备名 b 主编号 次编号
管道设备: sudo mknod 管道设备名 p 主编号 次编号
网络设备: sudo mknod 网络设备名 s 主编号 次编号
链接文件: 理解成快捷方式
软连接:ln -s 被连接文件名 新文件名 ( 是保存了被连接文件的绝对路径,是另外一个新的文件,访问时用被连接文件的路径替换)
硬链接:ln 被连接文件名 新文件名 (普通文件没区别,指向硬盘的同一块区域)快捷方式
删除对应的被链接文件,软连接会受到影响,而硬链接不会。
1.5 File pointer FILE* (the difference between standard IO and file IO)
typedef struct _iobuf{
char* ptr ; //下一个字符的位置
int cnt //剩余字节数
int* base; // 缓冲区的位置
int fd ; // 文件描述符 (文件的标志)
int flag ; //文件的访问模式
} FILE
File descriptor: is a non-negative integer and is an index pointing to the record of open files maintained by the kernel for each process.
Three default open streams: stdin (0) input stream stdout (1) output stream stderr (2) standard error stream
1.6 Conversion of file descriptors and file pointers*
#include <stdio.h>
函数原型:FILE *fdopen(int fd, const char *mode);
函数作用:把fd的文件描述符转换成文件指针,当文件IO中打开文件,需要用标准IO中的函数时需要使用。
函数参数:fd 文件描述符 mode打开模式
返 回 值:文件指针。
练习:找到标准输入的 文件指针。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
FILE * file = fopen("abc","r");
FILE* p = fdopen(0,"r");
if(p)
{
printf("p = %p\n",p);
}
if(file == NULL)
{
//perror("fdopen");
printf("%s\n",strerror(errno));
exit(0);
}
return 0;
}
函数原型: int fileno(FILE *stream);
函数作用:文件指针转换成文件描述符。
函数参数:stream 是文件指针
返 回 值:文件描述符。
使用: 标准io打开的文件fopen,用read去读取或者write写需要文件描述符,需要进行转换。
2. File IO
2.1 Open file*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数原型 int open(char *pathname, int flags, mode_t mode);
函数参数:pathname 文件名或者文件路径
flags 打开模式
mode 只有创建时候使用 文件创建权限0666
作 用: 打开文件
返 回 值: 文件描述符,也是文件的打开标志,失败返回-1;
打开模式:
第一组: 只读打开 O_RDONLY
只写方式:O_WRONLY
读写方式:O_RDWR
第二组: O_CREAT 创建文件,如果文件不存在则创建,需要和mode一起配合使用,mode的创建时候的文件权限
O_APPEND 追加的方式写入文件,如果文件已经有内容了,则在文件末尾添加内容,不会覆盖,文件末尾开始读不到内容。
O_TRUNC 覆盖写,每一次写都会把原有内容 清空。
2.2 File closing *
函数原型: int close(int fd);
头文件: #include <unistd.h>
作用: 关闭文件
返回值: 是否成功,如果是0则关闭成功 -1关闭失败
练习:创建danny.log文件 提示3秒后关闭
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("danny.log",O_RDWR| O_CREAT,0666);
if(fd == -1)
{
printf("%s\n",strerror(errno));
return 0;
}
sleep(1);
printf("倒计时1妙\n");
sleep(2);
close(fd);
}
2.3 File reading and writing*
#include <unistd.h>
函数原型: ssize_t read(int fd, void *buf, size_t count);
函数参数: fd 文件描述符
buf 存放读取内容的缓存。(数组,malloc申请空间)
count:从文件中读取的字节数
返回值:如果成功返回实际读取的字节数 如果失败返回-1,文件末尾返回0;
函数原型: int write(int fd, const void *buf, long count);
头 文 件: #include <unistd.h>
作 用: 写入文件内
参 数: fd 文件描述符
buf 存放读取内容的缓存。(数组,malloc申请空间)
count:从文件中读取的字节数
返回值:如果成功返回实际写入的字节数
失败返回-1 错误信息错入errno
练习:文件拷贝功能:./cp 文件1 文件2 (实现cp命令)
2.4 File offset*
#include <sys/types.h>
#include <unistd.h>
函数原型:off_t lseek(int fd, off_t offset, int whence);
作 用: 移动光标,移动文件偏移位置。
参 数:whence SEEK_CUR 从当前位置为餐卡偏移
SEEK_SET 从文件头开始偏移
SEEK_END 从文件尾开始偏移
offset:偏移多少,正数或者负数,正数往右,负数往
注 意: socket文件--网络设备文件,管道文件没法移动,
2.5 File permissions *
函数原型: int access(const char *pathname, int mode);
头 文 件: #include <unistd.h>
参 数: *pathname,文件名 ,mode 用来判断某一个模式
mode格式如下:
R_OK 判断文件是否有可读权限
W_OK 可写权限
F_OK 文件是否存在
X_OK 判断文件是否可执行
返回值:如果是0则表示成功。失败返回-1 错误信息存入errno中
练习:判断参数中的文件是否存在,如果存在判断有可执行权限
2.6 Delete files*
函数原型:int remove(const char *pathname);
头文件: stdio.h
作用: 删除文件
返回值:如果成功返回0 失败返回-1 errno
如果pathnam是目录,则需要调用rmdir()处理。
如果pathname是文件,则会调用unlink()处理
2.7 fcntl function*
函数原型: int fcntl(int fd, int cmd, ... /* arg */ );
头 文 件: #include <unistd.h> #include <fcntl.h>
参 数: fd 文件描述符
cmd 命令
F_DUPFD 赋值文件描述符
F_GETFD 获取文件描述符标志
F_SETFD 修改文件描述符
F_GETFL 获取文件的状态标志
F_SETFL 设置文件的状态标志
F_GETLK 获取文件锁
F_SETLK 设置文件锁
F_GETOWN 获取信号处理
F_SETOWN 设置信号处理
第三个:操作命令的参数,比如说设置文件描述符,设置成多少需要用第三个
返回值:如果是错误 返回-1
返回文件描述符 返回文件锁 返回状态标志
第一个重点: 文件状态获取和设置(可读可写)
获取状态标志:通过第二个参数 F_GETFL 来获取到现有的状态标志。例如O_REDONLY ,O_WRONLY, O_RDWR,然后用int变量接受,则得到的属性存入到了int中,
把得到的返回值和某一个属性例如O_REONLY进行按位与操作
增加状态标志: 通过第二个参数F_SETFL来设置,第三个参数是设置的内容,我们可以通过 返回值 |= 你想为期增设的标志,最后调用fcntl函数保存标志。
删除状态标志: 通过第二个参数F_SETFL来设置,第三个参数是设置的内容,我们可以通过 返回值 &=你想为期增设的标志的~来设置,最后调用fcntl函数保存标志。
第二个重点 :设置IO设备非堵塞 F_SETFL
设置: O_NONBLOCK 属性。
第一种设置方式: 在open的时候添加非堵塞属性
第二种设置方式:使用fcntl函数添加非堵塞属性。
第三个重点:设置文件锁 F_SETLK F_GETLK
对文件枷锁后,只允许一个进程读写,其他进程等待读写,直到解锁。
struct flock {
...
short l_type; /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /*偏移量的起始位置,枷锁的参考位置 SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 正数表示往后偏移后枷锁, */
off_t l_len; /* 枷锁多少个字节 */ 如果字节数为0默认为偏移位置到文件结束。
pid_t l_pid; /* 锁的进程id号
...
};
代码:先定义机构体,给结构体成员赋值,fcntl(fd,F_SETLK,&结构体);
struct flock lock;
lock.type =F_RDLCK;
lock.whence = SEEK_SET;
lock.start = 3;
lock.len = 0;
fcntl(fd,F_SETLK,&lock);
File IO the next day
one,
- Buffer: Standard IO has a buffer. The input and output data are first put into the cache. When the cache is full or the cache encounters \n, it will be refreshed and the data will be refreshed to the screen.
#include <stdio.h>
int fflush(FILE *stream);
Function: To refresh the cache area, you need to use FILE, because file IO does not have a cache area, you can refresh the input cache or output cache, such as fflush(stdout);
Introduced: open uses creation attribute O_CREAT, 0666
1. Create files [Key points]
函数原型: int creat(const char *pathname, mode_t mode);
头文件:#include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h>
参数:pathname 文件名/文件路径
mode 创建模式 0666
先从终端 输入一个文件名,如果文件存在则打印存在,如果不存在则创建文件。 ./a.out danny.txt
练习:从终端输入文件名的参数,先判断文件是否存在,如果不存在则创建。
2. fcntl file locking
对文件枷锁后,只允许一个进程读写,其他进程等待读写,直到解锁。
struct flock {
...
short l_type; /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /*偏移量的起始位置,枷锁的参考位置 SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 正数表示往后偏移后枷锁, */
off_t l_len; /* 枷锁多少个字节 */ 如果字节数为0默认为偏移位置到文件结束。
pid_t l_pid; /* 锁的进程id号
...
};
代码:先定义机构体,给结构体成员赋值,fcntl(fd,F_SETLK,&结构体);
struct flock lock;
lock.type =F_RDLCK;
lock.whence = SEEK_SET;
lock.start = 3;
lock.len = 0;
fcntl(fd,F_SETLK,&lock);
2. Time function
1. Function prototype: time_t time(time_t *); [Key Points]
参 数: timt_t为 long int类型 的指针 或者NULL
返 回 值:从公元1970年1月1号UTC 0点0分0秒到现在的秒数。
2. Function prototype: char *ctime(const time_t *); [Key points]
参 数: time_t 是从1970年1月1号0点到现在的时间 time();
返回值: 时间字符串信息,本地时间的日期和事件
作用:获取本地时间,会自动在时间字符串后面加 \r \n自动换行
3. Function prototype: struct tm *gmtime(const time_t *);
作用:转换成真实世界所使用的时间和日期表示方式,返回给tm结构体
参数: time_t是从1970年到现在的秒数 time函数的返回值
返回值: tm结构体,保存的是真实世界的时间。
结构体信息如下:
struct tm {【重点】
int tm_sec; /* 秒数 [0-60] (1 leap second) */
int tm_min; /* 分钟数 [0-59] */
int tm_hour; /* 小时 [0-23] */
int tm_mday; /* 一个月中的日期 [1-31] */
int tm_mon; /* 月份[0-11] */
int tm_year; /* 年份 - 1900. */
int tm_wday; /* 周中的天数(星期数). [0-6] */
int tm_yday; /* 一年中的哪一天.[0-365] */
}
4. Function prototype: char *asctime(const struct tm *);
参数: tm* 结构体指针,保存的是国际时间的结构体信息
作用: 把国际时间转换成本地时间字符串
返回值:时间字符串
5. Function prototype: struct tm *localtime(const time_t *); [Key points]
参 数: time_t 是time()函数的返回值
作 用: 把1970年1月1号到现在的秒数转换成本地时间
返 回 值: tm结构体指针
6. Function prototype: time_t mktime(struct tm *tm);
参数: tm*的结构体
返回值: time_t 在time函数中的参数中用过
作用: 把tm结构体的时间转换成1970年1月1号到现在的秒数。
3. File attribute function
Function prototype: int stat(const char *pathname, struct stat *buf); [Key points]
头 文 件: #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>
作 用: 获取文件的属性信息
参 数: pathname 文件路径或者文件名 buf 是结构体指针,保存的是文件属性信息
返 回 值: 如果成功返回0 如果是失败返回-1
结构体解析:
struct stat {
dev_t st_dev; /* 文件使用的设备号 */
ino_t st_ino; /* inode 设备的次设备号*/
mode_t st_mode; /* 文件的属性(目录 设备 链接)文件对应的模式 */
nlink_t st_nlink; /* 硬链接数*/
uid_t st_uid; /* 拥有者的用户ID */
gid_t st_gid; /* 组用户id */
dev_t st_rdev; /* 设备id */
off_t st_size; /* 文件的总字节数*/
blksize_t st_blksize; /* 磁盘块大小4k */
blkcnt_t st_blocks; /*占用的磁盘数 */
struct timespec st_atim; /* 最后一次访问的时间 */
struct timespec st_mtim; /* 最后一次修改的时间 */
struct timespec st_ctim; /* 最后一次改变状态的时间 */
}
详解stat结构体中的 st_mode;
总共16位 (short类型)
文件类型属性:(st_mode; 的前4位)
S_ISDIR(m) 目录文件
S_ISCHR(m) 字符设备
S_ISBLK(m) 块设备
S_ISFIFO(m) 管道设备
S_ISLNK(m) s连接设备
S_ISSOCK(m) 网络设备
文件权限( (st_mode; 的后9位))
S_IRWXU 00700 拥有者有可读可写可执行权限 rwx
S_IRUSR 00400 拥有者有可读权限 r
S_IWUSR 00200 拥有者有可写权限 w
S_IXUSR 00100 拥有者有可执行权限 x
S_IRWXG 组的权限 S_IRGRP S_IWGRP S_IXGRP
S_IRWXO (other)其他人权限 S_IROTH S_IWOTH S_IXOTH
3.2 To delete a file remove() calls unlink [Key Points]
#include <unistd.h>
函数原型:int unlink(const char *pathname);
返回值: 0表示成功 -1表示失败
作用: 删除文件
3.3 Intercept file content [Key points]
函数原型: int truncate(const char *path, off_t length);
头文件:#include <unistd.h> #include <sys/types.h>
参 数 : path 文件路径 或者文件名
length 需要截取的长度
返回值: 0表示成功 -1表示失败
函数作用: 从path文件中文件首位置开始截取length个字节。
3.4 File permission modification
#include <sys/stat.h>
函数原型: int chmod(const char *pathname, mode_t mode);
参 数 : pathname 文件名
mode是文件新的权限 0666
作用: 修改文件权限
返回值: 如果成功返回0 失败返回-1
3.5 Modify permission mask
#include <sys/types.h>
#include <sys/stat.h>
函数原型: mode_t umask(mode_t mask);
参数: mask 新的权限掩码
返回值: 返回老的权限掩码
4. Directory operation functions
#include <sys/stat.h>
#include <sys/types.h>
函数原型:int mkdir(const char *pathname, mode_t mode); 【重点】
作用: 创建目录
参数: pathname 文件路径 目录路径 目录名
mode 创建权限 0777
返回值: 成功0 失败-1
#include <unistd.h>
函数原型:int rmdir(const char *pathname); 【重点】
作用: 删除目录 (空目录)
参数: pathname 目录
返回值: 成功0 失败-1
#include <sys/types.h>
#include <dirent.h>
函数原型: DIR *opendir(const char *name); 【重点】
作用: 打开目录 相当于cd 目录名
参数: name 目录名
返回值: dir的结构体指针
#include <sys/types.h>
#include <dirent.h>
函数原型: int closedir(DIR *dirp); 【重点】
参数: dirp 是opendir的返回值
作用: 关闭目录
返回值: 成功0 失败-1
#include <dirent.h>
函数原型: struct dirent *readdir(DIR *dirp); 【重点】
参数: dirp 结构体指针
返回值: 独到的文件或者目录信息 dirent结构体指针,失败返回NULL
作用: 读取目录,按照文件一个一个的读取。
返回值结构体:struct dirent {
ino_t d_ino; /* inode 数目 次设备号 inode节点 */
off_t d_off; /*现在偏移的位置*/
unsigned short d_reclen; /* 目录的长度 */
unsigned char d_type; /* 文件类型 d s l c b */
char d_name[256]; /* 文件名 */
};
struct dirent中d_type中的宏定义如下:
DT_BLK 块设备 DT_CHR 字符设备 DT_DIR 目录 DT_REG 普通文件 DT_LNK 连接
File IO third day
1. Directory functions
#include <sys/types.h>
#include <dirent.h>
Function prototype: void rewinddir(DIR *dirp);
Function parameters: dirp This is the return value of open.
Function: reset the starting position of the directory and offset the directory. Move the setting to the starting position.
Function prototype void seekdir(DIR *dirp, long loc);
Function parameters: dirp is the return value of open
and loc is the length (offset) from the starting position of the directory to the offset position.
Function: Set the offset of the directory
函数原型: long telldir(DIR *dirp);
函数参数: open的返回值 DIR*的结构体指针。
返 回 值: 当前目录的偏移位置
作 用: 查看当前目录的偏移位置
#include <unistd.h>
函数原型: int chdir(const char *path);
函数作用: 跳转到某一个目录中
参数 : 需要跳转的目标目录
2. Library file basics
2.1 Library file features:
对源文件屏蔽 。
尊重开发者的知识产权
使用方便,方便开发。
2.2 Library file concept
本质是上库文件是可执行的二进制文件,可以被操作系统载入内存执行
库是别人写好,成熟的,可以重复使用的某一部分功能。
windows和linux的库文件是不一样的,不兼容。
2.3 Library file classification
Dynamic library: (it ends with dll under windows and .so file under linux)
1>在程序运行的时候加载到目标程序中,编译不检测。
2> 代码小 ,程序升级简单
3>实现资源共享
Static library: (lib file under windows, .a file under linux)
1>在程序编译阶段连接到目标文件
2>体积大,不利于程序的更新
3>程序运行运行过程中不需要静态库,移植方便。
注意:动态库和静态库是寄生虫,没办法单独运行,单独使用。
3. Static library writing
第一步:创建一个源文件和头文件 比如说xx.c xx.h
第二步: 在文件中按照多文件编译写需要的函数代码。
第三步:将库的源文件编译成目标文件 xx.o
gcc -c x.c -o xx.o
第四步: 将目标文件制作成静态库(lib库名.a)
命令:ar crs lib库名.a -o xxx.o
第五步: 编写测试代码 有main函数的代码(调用静态库函数)
第六步: 编译xx.c文件同时链接库文件
gcc -o abc xxx.c -L 目录 -l 库名
第七步:执行可执行程序
注意: gcc -o abc xxx.c -L 目录 -l 库名中 -L后不可以有空格, -l后也不可以有空格, -l后直接加静态库名称不需要加lib的前缀和.a后缀
4. Dynamic library writing
第一步:创建一个源文件和头文件 比如说xx.c xx.h
第二步: 在文件中按照多文件编译写需要的函数代码。
第三步:将库的源文件编译成目标文件 xx.o
命令: gcc -fPIC -c xxx.c
fPIC 创建和地址无关的编译程序
第四步:将.o文件编译成动态库(产生了xx.so)
命令:gcc -shared -fPIC -o xxxx.so xxx.o
第五步: 编写测试代码 有main函数的代码(调用动态库函数)
第六步:将编译的xx.c文件编译连接动态库
命令: gcc -o abc xxx.c -L目录 -l库名
第七步: 运行可执行程序。
注意: 在编译完so文件后,需要放入到/lib 或者/usr/lib下
在gcc时 -L不可以省略 并且 -l后如果加空格则需要加动态库的后缀名 如果不加空格 则直接使用名称不用后缀。
运行时动态库必须存在,否则没法找到函数地址,运行出错,但静态库不会,编译完成后删除不会影响代码运行。