IO(文件)
文件操作:
文本文件,mp3,jpeg,png ,mp4,avi
文件:
一组相关数据的有序集合
文件名:
这组相关数据的一个名称
linux里面对文件的处理:
思想:
一切皆文件 ,文件用来存储数据(数据、指令)
everything is file!
b c d - l p s
b -- block -- 块设备文件 --- 硬盘(存储设备)
c -- character -- 字符设备文件 --- 鼠标
d -- directory -- 目录文件
- -- regular -- 普通文件
l -- link -- 软连接文件 --- 类似windows的快捷方式
p -- pipe -- 管道文件 --- 实现操作系统中 进程间的一些 信息交换(通信)
s -- socket -- 套接字文件 --- 网络的时候 (进程间的通信)
【操作文件的基本思路及框架】//凡是文件,都可从这个思路出发进行思考
文件操作三步骤:
1.打开
2.读写
3.关闭
Linux提供的两种文件操作方式:
文件编程:
1.标准IO --- 库函数 -------标准c库函数,
2.文件IO --- 系统调用-------Linux内核为用户提供的函数接口
系统调用:Linux内核为用户提供的函数接口
库函数:标准c库函数, 对Linux内核中系统调用的封装
标准IO库:
1.标准io的概念
1975 Dennis Ritchie编写, IO库,
从C语言的标准,ANSI c
IO input output
I: 键盘是标准输入设备 ====》
默认输入就是指键盘 /dev/input
O: 显示器是标准输出设备 ==》默认输出就是指显示器
Linux操作系统当中IO都是对文件的操作
C一部分,任何支持标准C的系统都可使用标准IO实现文件存储
标准IO在UNIX上是对文件IO的封装
一般都是对普通文件操作是一种有缓存的IO 在文件IO和用户程序之间,
加入缓冲区,可以有效减少系统调用的次数,节省系统IO调度资源
2.功能:
用来操作普通文件
普通文件:
1.ASCII码文件(代码、文本文件)
2.二进制文件(音视频、图片)
ASCII码文件是一种特殊的二进制文件
2021
'2' '0' 2' '1'
2021
0000 0000 0000 0000 0000 0111 1110 0101
3.操作方法
1.打开 -- fopen //FILE open
2.读写 --
fgetc / fputc 读出、写入单个字符
fgets / fputs 读出、写入一行字符
fread / fwrite 读出、写入指定长度数据
3.关闭 -- fclose
man手册
标准man手册分为8个章节:
man 1 用户命令
man 2 系统调用
man 3 c函数库调用
man 4 设备文件和特殊文件
man 5 配置文件和格式
man 6 游戏相关
man 7 杂项,总述
man 8 管理类命令
4.API函数接口
1.fopen
#include <stdio.h>
FILE* fopen(const char *path, const char *mode);
功能:
流打开函数 (打开文件,并关联到一个流)
参数:
@path --要打开的文件的文件名(字符串形式)
@mode --打开文件的操作模式
r ---打开文件做读操作
注意:
文件必须存在
r+ 打开文件做读写操作
注意:
文件必须存在
w 打开文件做写操作(写入前清零)
注意:
如果文件已经存在,则会将文件清空为0
如果文件不存在,则会创建一个新文件。
w+ 打开文件做读写操作(写入前清零)
注意:
如果文件已经存在,则会将文件清空为0
如果文件不存在,则会创建一个新文件。
a 打开文件做写操作(后续写入,不清零)
注意:
如果文件已经存在,则在文件末尾进行写入
如果文件不存在,则会创建一个新文件。
a+ 打开文件做读写操作(后续写入,不清零)
注意:
如果文件已经存在,则在文件末尾进行写入
如果文件不存在,则会创建一个新文件。
返回值:
成功 FILE * (文件流指针)
失败 NULL 并且 设置 errno 表明错误原因
流:
数据从文件当中流入和流出所体现出来的字节流叫做流
FILE 结构定义的对象(FILE * 指向的对象)称之为流对象,FILE *叫文件流指针。
标准IO将对文件的操作转换成了对"流"的操作。
所以,标准IO的文件相关的函数都是围绕着 FILE进行的。
FILE * fp
FILE * fp;//流指针------关联一个文件
FILE * 实际上是指向了一块内存空间(缓存,fileno)
FILE *fp <->【FILE结构体[缓存,fileno]】//堆区(malloc)
2.fclose
int fclose(FILE *fp);
功能:
关闭文件流指针
参数:
fp:文件流指针
返回值:
成功返回0
失败返回EOF(-1)
注意:fopen操作完毕后使用fclose关闭,否则会产生内存泄漏
不要重复调用fclose
3.fputc
int fputc(int c, FILE *stream);
功能:
向流中写入一个字符
参数:
c:要写入的字符
stream:文件流指针
返回值:
成功返回 写入的字符ASCII码值
失败返回 EOF
//读
4.fgetc
int fgetc(FILE *stream);
功能:
从流中读取一个字符
参数:
stream:文件流指针
返回值:
成功返回读到字符的ASCII码值(无符号字符)
读到文件末尾 返回 EOF
失败返回EOF EOF
操作系统在运行一个程序时,会默认打开三个流:
stdin FILE* 标准输入流 ---->键盘
stdout FILE* 标准输出流 ---->屏幕
stderr FILE* 标准出错流 ---->屏幕
gets scanf getchar -> stdin
puts printf putchar -> stdout
perror -> stderr
1.概念
文件io:
操作系统为了方便用户使用系统功能而对外提供的一组系统函数。
称之为 系统调用
其中有一组对文件的操作,称为文件IO
一般都是对设备文件操作,当然也可以对普通文件进行操作。
一个基于Linux内核的没有缓存的IO机制
库函数(标准io):
1.移植性好
任何支持标准c库的系统都可以使用标准IO的方式实现对文件的操作,
不单单是linux上有,在windows,Mac os上都有。
printf、puts、putchar
scanf、gets、getchar
2.库函数的调用,一般用于应用程序对普通文件的访问
3.库函数本质是对系统调用的封装
系统调用:
1.操作系统相关,没有跨平台系统的可移植性
read write
2.可以操作普通文件,也可以操作设备文件;通常用于对底层文件的访问
3.发生在内核空间(有空间切换的开销)
文件操作:
缓存 操作对象 具体操作
标准IO 全缓存/行缓存 文件指针(流指针)FILE * 1.打开 --fopen
2.读写
fgetc/fputc
fgets/fputs
fread/fwrite
3.关闭
fclose
4.定位
fseek/ftell/rewind
文件IO 不带缓存 文件描述符 (整数) 1.打开 --open
2.读写 --read/write
3.关闭 --close
4.定位 --lseek
文件IO特性:
.1 没有缓存区 (//可以认为数据直接交给了内核 )
.2 操作对象不在是流(FILE *),而是文件描述符(整数)
.3文件描述符
很小的非负的整数 int 0-1023
内核每打开一个文件就会获得一个文件描述符
新生成的文件描述符永远为最小的非负整数
最小未被占用
每个程序在启动的时候操作系统默认为其打开
三个描述符与流对象匹配:
0 ==>STDIN_FILENO === stdin
1 ==>STDOUT_FILENO == stdout
2 ==>STDERR_FILENO == stderr
stdin,stdout,stderr,===>FILE*
2.函数接口
1.open
int open(const char *pathname, int flags); //打开一个已有文件
int open(const char *pathname, int flags,int mode);//O_CREAT + 权限
功能:
获得一个文件描述符
参数:
pathname:文件名
flags:
必须项:他们之间是互斥的,所以有且只能有一个
O_RDONLY
O_WRONLY
O_RDWR
可选项:
O_CREAT 创建文件,若文件存在只作打开操作 //这个标志量存在,则需要指定参数 mode
O_TRUNC 文件内容清空
O_APPEND 追加方式
//后面
O_NOCTTY 不是终端设备
O_ASYNC 异步io,什么时候io不确定,
O_NONBLOCK 非阻塞
返回值:
成功返回文件描述符 (最近最小未使用)
失败返回-1
open("1.txt",O_WRONLY|O_CREAT,0666);
最终文件的权限
~umask & mode
r w x r w x r w x
1 1 0 1 1 0 1 1 0 666
1 1 1 1 1 1 1 0 1 ~002 & 1 1 0
---------------------
1 1 0 1 1 0 1 0 0 664
2.close
int close(int fd);
功能:
关闭文件描述符
1.使用文件IO模拟标准IO的所有打开方式
"r" O_RDONLY
"r+" O_RDWR
"w" O_WRONLY | O_CREAT | O_TRUNC, 0664
"w+" O_RDWR | O_CREAT | O_TRUNC, 0664
"a" O_WRONLY | O_CREAT | O_APPEND, 0664
"a+" O_RDWR | O_CREAT | O_APPEND, 0664
2.用open实现类似touch的命令
3.write
char buf[1024];
ssize_t write(int fd, const void *buf, size_t count);
功能:
通过文件描述符向文件中写一串数据
参数:
fd:文件描述符
buf:要写入文件的字符串的首地址
count:要写入字符的个数
返回值:
成功返回实际写入的个数
失败返回-1
4.read
ssize_t read(int fd, void *buf, size_t count);
功能:
通过文件描述符读取文件中的数据
参数:
fd:文件描述符
buf:存放数据空间的首地址
count:要读到数据的个数
返回值:
成功返回读到数据的个数
失败返回-1
读到文件结尾返回0
5.lseek
off_t lseek(int fd, off_t offset, int whence);
功能:
重定位一个文件描述符的偏移量(文件定位器)
参数:
fd:文件描述符
offset:偏移量
正:向后偏移
负:向前偏移
零:不偏移
whence:
SEEK_SET
SEEK_CUR
SEEK_END
正 空洞
返回值:
成功返回当前偏移量的值(off_t long int)
失败返回-1
off_t len =lseek(fd,0,SEEK_END); //获取到文件的大小
注意:
1、lseek函数执行失败,文件指针还在偏移前的位置。
2、lseek函数在设备文件上偏移无效。
3、fifo,socket
1.fileno FILE* fp -> int fd
int fileno(FILE *stream);
功能:
获得一个文件流指针中的文件描述符
参数:
stream:文件流指针
返回值:
成功返回文件描述符
失败返回-1
2.fdopen int fd -> FILE *fp
FILE *fdopen(int fd, const char *mode);
功能:
将文件描述符转化为文件流指针
参数:
fd:已经打开的文件描述符
mode:
"r"
"r+"
"w"
"w+"
"a"
"a+"
返回值:
成功返回文件流指针
失败返回NULL
strtok:
char *strtok(char *str, const char *delim);
功能:分割一个字符串
参数:
str:要分割的字符串
delim:分隔符
返回值:
成功返回分割后的字符串首地址
失败:NULL
时间相关函数:
1.time
time_t time(time_t *t);
功能:
获得1970年1月1日到现在的秒数
参数:
t:存放秒数空间的首地址
返回值:
成功返回1970年1月1日到现在的秒数 (time_t long)
失败返回-1
time_t 1970年1月1日到现在的秒数
日历时间
2.ctime
char *ctime(const time_t *timep);
功能:
将秒数转换为字符串时间
参数:
timep:1970年1月1日到现在的秒数
返回值:
成功返回时间字符串首地址
失败返回NULL
3.localtime
struct tm *localtime(const time_t *timep);
功能:
将秒数转换为时间结构体
参数:
timep:存放秒数空间首地址
返回值:
成功返回包含时间结构体空间首地址
失败返回NULL
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
目录也是文件:
目录文件 ----> 目录流指针 ----> 提供给相关函数操作
01-打开目录 --opendir
02-读目录 --readdir
03-关闭目录 --closedir
1.opendir
DIR *opendir(const char *name);
功能:
打开一个目录获得一个目录流指针
参数:
name:目录名
返回值:
成功返回目录流指针
失败返回NULL
2.readdir
struct dirent *readdir(DIR *dirp);
功能:
从目录流中读取文件信息并将保存信息的结构体
地址返回
参数:
dirp:目录流指针
返回值:
包含文件信息的结构体
出错或者读到目录流末尾返回NULL
On Linux, the dirent structure is defined as follows:
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 */
};
练习:
读取目录下的所有文件,打印起inode编号 和名字
3、关闭目录
int closedir(DIR *dirp);
功能:关闭之前已经打开的目录流对象
参数:
opendir的返回结果中目录流对象
返回值:
成功 0
失败 -1;
DT_BLK This is a "block device".
DT_CHR This is a "character device".
DT_DIR This is a "directory".
DT_FIFO This is a named "pipe (FIFO)". //管道文件
DT_LNK This is a "symbolic link".//软链接 ---相当于是windows的快捷方式
DT_REG This is a regular file.//普通文件
DT_SOCK This is a UNIX domain socket. //socket --- 套接字文件
DT_UNKNOWN The file type is unknown. //
3.chdir
int chdir(const char *path);// /home/linux
功能:
改变当前程序的工作路径
参数:
path:改变到的路径
返回值:
成功返回0
失败返回-1
4.getcwd //pwd
char *getcwd(char *buf, size_t size);
功能:
获得当前的工作路径
参数:
buf:保存工作路径空间的首地址
size:保存路径空间的长度
返回值:
成功返回包含路径空间的字符串首地址
失败返回NULL
5.mkdir
int mkdir(const char *pathname, mode_t mode);
功能:
创建一个目录
参数:
pathname:路径
mode: 0777
mode & ~umask 0002
返回值:
成功返回0
失败返回-1
6.rmdir rm -rf rmdir
int rmdir(const char *pathname);
功能:
删除一个空目录文件
参数:
pathname:目录文件的名字
返回值:
成功返回0
失败返回-1
//目录操作:
1.opendir
2.readdir
3.closedir
--------
4.chdir
5.getcwd
6.mkdir
7.rmdir
drwxrwxr-x 2 linux linux 4096 Mar 22 19:31 ./
说明:
d rwx rwx r-x 2 linux linux 4096 Mar 22 19:31 ./
文件类型 相关权限 目录 所有者 所在组 文件大小 最后被修改的时间 文件名
用户 (子目录个数)
所在组 文件
其他人 (硬链接数)
(用户组)
---------------------------
1. Linux文件系统:
目录项:文件名 inode
inode表:inode号, 文件大小 类型 指示
数据块:文件内容
1.软连接:符号链接
1.占用内存空间
2.可以链接目录
3.删除软链接源文件无影响,删除源文件,软链接失效
创建:
ln -s 源文件名 软链接名
2.硬链接:文件别名(inode)
1.目录不能有硬链接
2.硬链接不占空间
3.当硬链接数为0时,此文件才被删除
创建:
ln 源文件名 硬链接文件名
3.symlink
int symlink(const char *target, const char *linkpath);
功能:创建软连接
参数:
target 源文件
linkpath 链接文件
4.link
int link(const char *oldpath, const char *newpath);
功能:创建硬链接
参数:
oldpath 源文件
newpath 链接文件
5.readlink
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
功能:读软链接文件(获得软链接文件指向的文件名)
参数:
pathname 软连接文件
buf 存放链接文件的空间
bufsiz buff的大小
---------------------------
ls -l
2. 文件属性的获取
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
//软链接 --- lstat 获取软链接这个链接文件本身的属性信息,而不是连接到的目标文件的属性信息。
stat
int stat(const char *path, struct stat *buf);
功能:
获得文件的属性
参数:
path: 文件的路径
buf: 属性存放空间的首地址
返回值:
成功返回0
失败返回-1
All of these system calls return a stat structure, which contains the following fields:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */(*)
mode_t st_mode; /* protection */(* 权限信息)
nlink_t st_nlink; /* number of hard links */(* 硬链接数)
uid_t st_uid; /* user ID of owner */ (*UID 用户id)
gid_t st_gid; /* group ID of owner */(*group 所在组ID)
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */(*文件的大小)
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */ (*最后访问的时间)
time_t st_mtime; /* time of last modification */ (*最后修改的时间)
time_t st_ctime; /* time of last status change */(*最后的状态改变的时间)
};
The following flags are defined for the st_mode field:
S_IFMT 0170000 bit mask for the file type bit fields
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
//---------------------------------------------------------------
S_ISUID 0004000 set UID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
//---------------------------------------------------------------
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
//---------------------------------------------------------------
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
//---------------------------------------------------------------
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
0 000 1
0 000 2
0 000 4
000 ---- 100
000 ---- 010
000 ---- 001
st_mode标志位
000 000 000 100 000 000
001 100 110 0
000 000 000 000 000 000
|文件 | |设置| |文件权限 |
|类型 | |组和|
|用户|
|ID |
4.Linux用户相关函数
// /etc/passwd
1.getpwuid
struct passwd *getpwuid(uid_t uid);
功能:
获得uid对应用户信息
参数:
uid:用户的ID号
返回值:
成功返回包含用户信息的结构体地址
失败返回NULL
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 */
};
// /etc/group
2.getgrgid
struct group *getgrgid(gid_t gid);
功能:
根据组ID获得组信息
参数:
组ID
返回值:
成功返回组信息结构体指针
失败返回NULL
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
4.linux下时间的获取
1.获取秒数 --time() 秒数
2.转换为需要个格式 ()
系统时间的获取:
1.time
time_t time(time_t *t);
time_t tm;
time(&tm)
tm = time(NULL);
功能:
获得1970年到现在的秒数
参数:
t:存放秒数的空间首地址
返回值:
成功返回1970年到现在的秒数
失败返回-1
2.localtime
struct tm *localtime(const time_t *timep);
功能:
将一个秒数转化成日历时间
参数:
timep:保存秒数空间的地址
返回值:
成功返回保存日历时间结构体的指针
失败返回NULL
3.ctime
char *ctime(const time_t *timep);//date
功能:
将时间秒数转化成字符串
参数:
timep:保存时间空间的地址
返回值:
成功返回获得时间字符串的首地址
失败返回NULL
struct tm
{
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};