一、标准IO和文件IO的区别:
1>标准IO拥有缓冲区,文件IO没有
2>标准IO是文件IO的基础上封装缓冲区形成
3>标准IO是应用层IO 来自C库
文件IO是底层IO 来自系统
------------文件IO在移植性上面,优于标准IO
4>标准IO大多数来自stdio.h
文件IO的头文件相对比较多
缓冲区的分类:
1>全缓冲:主要针对普通文件
只有当缓冲区域满的时候,才会执行IO操作
2>行缓冲:标准输入
当缓冲区域满或者遇到“\n”;
3>不缓冲:标准错误输出
直接输出
二、时间编程
1>时间编程 — 智能手表 —哎哟我去
获取系统时间
1>世界标准时间:格林尼治时间
简称UTC,是一种规范世界时间的规则,将地球划分为24个时区
2>系统标准时间
计算方式: 1970年 1月 1日 0时0分0秒 到 此时此刻的秒数
1970:UNIX time的起始.世界上大多数计算机语言都是以这个时间
为开始的.
我们以前用的系统32位:可以存放236年的秒数
64
3>获取系统时间
time
#include <time.h>
time_t time(time_t *tloc);
功能:
获取到系统标准时间返回到某个地方
参数:
用来保存秒数的变量地址
返回值:
成功:获取到的秒数
失败:-1
4>将系统时间转化为字符串时间
ctime
#include <time.h>
char *ctime(const time_t *timep);
功能:
将系统时间转化为字符串时间
参数:
*timep:保存以秒为单位变量地址
返回值:
成功:字符串时间
失败:NULL
5>将标准时间转化为可定义的本地时间
#include <time.h>
struct tm *localtime(const time_t *timep);
功能:
将标准时间转化为可定义的本地时间
参数:
*timep:保存以秒为单位变量地址
返回值:
成功:返回值结构体指针
失败:返回NULL
struct tm {
int tm_sec; /* Seconds (0-60) */ 秒数
int tm_min; /* Minutes (0-59) */ 分
int tm_hour; /* Hours (0-23) */ 时
int tm_mday; /* Day of the month (1-31) */ 天
int tm_mon; /* Month (0-11) */ 月 + 1
int tm_year; /* Year - 1900 */ 年 + 1900
int tm_wday; /* Day of the week (0-6, Sunday = 0) */ 周几
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */一年中第几天
int tm_isdst; /* Daylight saving time */夏令时
};
6>将本地时间转化为字符串时间
asctime
#include <time.h>
char *asctime(const struct tm *tm);
功能:
将本地时间转化为字符串时间
参数:
tm:结构体指针
返回值:
成功:字符串时间
失败:NULL
三、文件IO
核心: 文件描述符
对于系统来说:所有打开的文件,都由文件描述符来引用
文件描述符是一个非负整数,每打开一个文件,内核向进程返回该文件的文件描述符
永远优先分配最小且未被使用的文件描述符
流和文件描述符有什么关系?
只有前三个文件描述符和流有关系
0 1 2
stdin stdout stderr 都是 0 1 2 的链接文件
操作stdin 等于操作 0
==============
文件IO的API:应用程序接口 --->函数
1>打开文件
open
#include <sys/types.h>
#include <sys/stat.h> 来源posix
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
功能:
打开文件 --->文件IO的
参数:
pathname:要打开的文件路径: 相对路径 绝对路径
flags:要打开的方式:
互斥方式 :
O_RDONLY: 以只读的方式打开文件
O_WRONLY: 以只写的方式打开文件
O_RDWR: 以读写的方式打开文件
这三个方式只能三选一
多选方式:
O_EXCL:使用O_CREAT时.检查文件是否已经存在,用来测试文件是否存在
O_NOCTTY:使用本参数时,要打开的文件不能是终端
O_TRUNC:清空模式
O_APPEND:追加模式
O_CREAT:如果该文件不存在,则创建,使用该参数,会开启第三参
:mode
mode:如果参数2中拥有O_CREAT,则开启
用来规定创建文件的权限的 0777 掩码
返回值:
成功返回该文件的文件描述符
失败返回-1,并返回错误码
标准IO 文件IO 对比 标准IO的方式和文件IO的方式
fopen open
r O_RDONLY
r+ O_RDWR
w O_WRONLY|O_TRUNC|O_CREAT,0666 - 掩码 0664
w+ O_RDWR|O_TRUNC|O_CREAT,0666 - 掩码 0664
a O_WRONLY|O_APPEND|O_CREAT,0666 - 掩码 066
a+ O_RDWR|O_APPEND|O_CREAT,0666 - 掩码 066
2>读写文件
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:
根据文件描述符,读取数据
参数:
fd:文件描述符 --open返回的
buf:读取出来的数据存放的位置
count:读取数据的大小
返回值:
成功:返回读取到的字节数
失败:返回-1,并返回错误码
读到文件末尾:0
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:
写入数据到相应的文件描述符
参数:
fd:文件描述符 --open返回的
buf:读取出来的数据存放的位置
count:读取数据的大小
返回值:
成功:返回写入的字节数
失败:返回-1,并返回错误码
3>关闭文件
close
#include <unistd.h>
int close(int fd);
功能:
根据文件描述符,关闭文件
参数:
fd:文件描述符
返回值:
成功:返回0
失败:返回-1,并返回错误码
2 3 4 5 6 110 95
4>实用函数
lseek----文件IO的光标偏移
有个兄弟 fseek
ftell ---- 当前光标位置
rewind ---- 光标回到文件头部
lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:
对相应的文件描述符的光标进行移动
参数:
fd:文件描述符 --open返回的
offset:偏移量
whence:基准位置:
SEEK_SET:文件头部
SEEK_CUR:当前位置
SEEK_END:文件尾部
返回值:
成功返回光标所在位置
失败返回-1,并设置错误码
4>非格式化IO和格式化IO ----->标准IO
非格式化IO:无法自定义输入输出的格式
fgetc/getc/getchar
fgets/gets
fread
fputc/putc/putchar
fputs/puts
fwrite
格式化IO:自定义输入输出的格式
printf
scanf
格式化输出
int fprintf(FILE *stream, const char *format, ...);
//将数据输出到流中
int sprintf(char *str, const char *format, ...);
//将格式化字符输出到字符数组中
格式化输入
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
//从流中获取数据
int sscanf(const char *str, const char *format, ...);
//从字符串中获取数据
例子:
格式化IO操作流
int num;
char c;
FILE *fp_r=fopen("1.c","r");
FILE *fp_w=fopen("2.c","w");
fscanf(fp_r,"%d %c",&num,&c);
fprintf(fp_w,"%d %c",num,c);
从字符串中获取数据
int num;
char c;
char buf[64]="28,C";
sscanf(buf,"%d %c",&num,&c);
sprintf(buf,"%d %c",num,c);
文件IO的函数:
打开文件
open:
需要记住打开的方式
flags:要打开的方式:
互斥方式 :
O_RDONLY: 以只读的方式打开文件
O_WRONLY: 以只写的方式打开文件
O_RDWR: 以读写的方式打开文件
这三个方式只能三选一
多选方式:
O_EXCL:使用O_CREAT时.检查文件是否已经存在,用来测试文件是否存在
O_NOCTTY:使用本参数时,要打开的文件不能是终端
O_TRUNC:清空模式
O_APPEND:追加模式
O_CREAT:如果该文件不存在,则创建,使用该参数,会开启第三参
:mode
mode:如果参数2中拥有O_CREAT,则开启
用来规定创建文件的权限的 0777 掩码
读写操作:
read
write
关闭文件:
close
实用函数:
lseek
dup
dup2
----文件描述符重定向
1>文件和目录属性 —>学习如何使用函数实现ls -l功能
获取文件属性
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
//如果文件为符号链接文件(软链接),则返回本体文件的文件信息
int fstat(int fd, struct stat *statbuf);
//需要先打开文件获取文件描述符,才可以获取文件属性
int lstat(const char *pathname, struct stat *statbuf);
//如果文件为符号链接文件,则返回符号链接文件的文件信息
三个函数的返回值:成功返回0,失败返回-1,并设置错误码
struct stat {
dev_t st_dev; /* ID of device containing file /
设备文件
ino_t st_ino; / Inode number /
inode索引码
mode_t st_mode; / File type and mode /*!
文件类型与权限
nlink_t st_nlink; / Number of hard links /
硬链接数
uid_t st_uid; / User ID of owner /
文件拥有者ID
gid_t st_gid; / Group ID of owner /
文件所属组ID
dev_t st_rdev; / Device ID (if special file) /
设备号
off_t st_size; / Total size, in bytes /
文件大小
blksize_t st_blksize; / Block size for filesystem I/O /
块大小
blkcnt_t st_blocks; / Number of 512B blocks allocated */
块数
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
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 */
文件状态最后更改时间
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
通过ID转化为文件拥有者和文件所属组
struct passwd *getpwuid(uid_t uid);
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 */
};
所属组
struct group *getgrgid(gid_t gid);
struct group {
char *gr_name; /* group name */ 组名
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
5>文件类型与权限:
该数据来自st_mode
类型与权限:
10位 1+3+3+3
1:文件类型
第一个3:文件拥有者的权限
第二个3:文件所属组的权限
第三个3:其他用户的权限
解析st_mode
1>目录的属性 ----实现ls操作
1>打开目录
opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:
打开一个目录
参数:
name:目录名
返回值:
成功返回DIR *指针
失败返回NULL,并返回错误码
2>读取目录
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:
读取目录
参数:
DIR指针 :opendir返回的
返回值:
成功返回结构体指针
失败返回NULL,并返回错误码
struct dirent {
ino_t d_ino; /* Inode number */
索引码
off_t d_off; /* Not an offset; see below */
目录文件的偏移
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]; /* Null-terminated filename */
文件名
};
3>关闭目录
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:
关闭目录
参数:
DIR指针
返回值:
成功返回0
失败返回-1,并设置错误码
=========================================================================
6>静态库和动态库----函数工具库
1>什么是库?
本质上是某一个代码的二进制形式,可以被载入到内存中执行。
库一般是别人写好的,现成的,成熟的。
linux和windows不兼容,二者的二进制计算不一样
2>库的分类:
静态库和动态库
二者的不同点在于代码被载入的时刻不同。
静态库的特点:
静态库在程序编译时会被连接到目标代码中,
程序运行时将不再需要该静态库,因此体积较大。
动态库的特点:
动态库在程序编译时并不会被连接到目标代码中,
而是在程序运行时才被载入,因此在程序运行
时还需要动态库存在,因此代码体积较小。
二>实操编写静态库和动态库
静态库:
1>特点
静态库对函数库的链接是放在编译时期(compile time)完成的。
gcc编程的四大步骤:预处理—>编译—>汇编—>链接
优点:程序在运行时与函数库再无瓜葛,移植方便
缺点:浪费空间和资源,因为所有相关的对象文件(object file)与牵涉到的函数
库(library)被链接合成一个可执行文件(executable file)
2>如何创建静态库?
1>第一步:编写一个库源文件:mylib.c
int myplus(int a,int b)
{
return a+b;
}
int myusb(int a,int b)
{
return a-b;
}
2>第二步:将mylib.c编译成.o文件
gcc -c mylib.c -o mylib.o
ps:-c 对源文件进行编译汇编 但不链接-->不会产生可执行文件
3>第三步: 将.o文件制作成静态库文件 --->静态库命名必须:lib库名.a
ar crs libmylib.a mylib.o
ar crs 制作静态库的命令
4>第四步:编写一个测试代码:test.c 用于测试静态库是否可以顺利调用
#include <stdio.h>
#include "mylib.h"
int main(){
int a,b;
printf("请输入a和b");
scanf("%d%d",&a,&b);
printf("%d+%d=%d\n",a,b,myplus(a,b));
printf("%d-%d=%d\n",a,b,myusb(a,b));
return 0;
}
5>第五步: 编译test.c的同时链接静态库
gcc -Wall -o test test.c -L. -lmylib
-L 找库的路径
-l 指定库名
6>第六步:执行测试
./test
请输入a和b10 20
10+20=30
10-20=-10
=========================================================================
2>如何创建动态库
1>创建一个库源文件:mylib.c
int myplus(int a,int b)
{
return a+b;
}
int myusb(int a,int b)
{
return a-b;
}
2>将库源文件编译.o 的目标文件
gcc -fPIC -Wall -c mylib.c
-fPIC//创建与地址无关的编译程序
3>将.o文件制作成动态库文件 库的命名必须:lib库名.so
gcc -shared -fPIC -o libmylib.so mylib.o
4>编写测试代码:
test.c
5>编译test的同时链接动态库
gcc -Wall -o test test.c -L. -lmylib
6>发现无法执行---如何让系统认识动态库?
1>方法一:一般推荐
直接将动态库文件放到 /lib 或 /usr/lib 中
2>方法二:墙裂推荐
在系统配置文件中声明路径
1>打开配置文件
sudo vim /etc/ld.so.conf
2>在该文件新行中添加动态库路径
/home/farsight/shared/IO/day3/dt_LIB
3>保存退出后执行
sudo ldconfig
3>方法三:不推荐
将动态库的路径声明到环境变量中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/farsight/shared/IO/day3/dt_LIB
export --- 声明环境变量
LD_LIBRARY_PATH---声明的变量类型是库文件
7>三选一后 测试
./test