学习目标:
核心思想:一切皆文件
学习内容:
【操作文件的基本思路及框架】
凡是文件,都可从这个思路出发进行思考文件操作三步骤:
1.打开
2.读写
3.关闭
文件操作两种方式:
标准IO
缓存: 全缓存/行缓存
操作对象: 文件指针(流指针)FILE *
具体操作: 1.打开 --fopen
2.读写 fgetc/fputc fgets/fputs fread/fwrite
3.关闭 fclose
4.定位 fseek/ftell/rewind
优点:a.方便,功能多b.可移植性好标准
不足:c.可能存在安全性隐患
文件IO
缓存: 不带缓存
操作对象: 文件描述符 (整数)
具体操作:1.打开 --open
2.读写 --read/write
3.关闭 --close
4.定位 --lseek
优点:a.使用起来,简单功能简单b.安全性高c.设备文件----文件I0
缺点:c.很多复杂功能需要自己封装设计d.可移植性差
FILE *fp <--操作系统内核([fileno])--->[1.txt]
特性:.1 没有缓存区 (//可以认为数据直接交给了内核 )
.2 操作对象不在是流(FILE *),而是文件描述符(整数)
.3文件描述符 很小的非负的整数 内核每打开一个文件就会获得一个文件描述符
文件描述符 <----------操作系统--------->[1.txt] //硬盘
每个程序在启动的时候操作系统默认为其打开三个描述符与流对象匹配:
标准输入 0 ==>STDIN_FILENO === stdin
标准输出 1 ==>STDOUT_FILENO == stdout
标准报错 2 ==>STDERR_FILENO == stderr
stdin,stdout,stderr,===>FILE*
fopen/open函数
标准IO库: 系统调用
fopen open
r O_RDONLY
w O_WRONLY|O_CREAT|O_TRUNC
r+ O_RDWR
w+ O_RDWR |O_CREAT|O_TRUNC
a O_WRONLY|O_CREAT|O_APPEND
a+ O_RDWR |O_CREAT|O_APPEND
库函数 本质上是 对系统调用 的封装
2.函数接口
1.open
函数原型:int open(const char *pathname, int flags,int mode);
功能:获得一个文件描述符
参数:pathname:文件名
flags:打开权限 必选项:三者互斥,有且只能有一个
O_RDONLY
O_WRONLY
O_RDWR
可选项:
O_CREAT, 创建文件
O_EXCL, 需要和O_CREAT同时使用,表示新建的文件不存在,成功,否则open就会失败
O_TRUNC 文件内容清空
O_APPEND 文件内容追加
返回值:成功返回文件描述符 (最近最小未使用) 失败返回-1
fopen open
r O_RDONLY
r+ O_RDWR
w O_WRONLY| O_CREAT|O_TRUNC,0666
w+ O_RDWR| O_CREAT|O_TRUNC,0666
a O_WRONLY|O_APPEND|O_CREAT,0666
a+ O_RDWR|O_APPEND|O_CREAT,0666
//后面
O_NOCTTY,不是终端设备
O_ASYNC 异步io,什么时候io不确定,
O_NONBLOCK 非阻塞
最终文件的权限
~umask & 0666
touch --- 如果文件不存在,则创建该文件(空文件)
如果文件存在,则更新文件的时间戳(makefile)
2.write
函数原型:ssize_t write(int fd, const void *buf, size_t count);
功能: 通过文件描述符向文件中写一串数据
参数:fd :文件描述符
buf:要写入文件的字符串的首地址
count:要写入字符的个数
返回值:成功 实际写入的个数
失败 -1 & errno 被设置
3.read
函数原型:ssize_t read(int fd, void *buf, size_t count);
功能:通过文件描述符读取文件中的数据
参数:fd :文件描述符
buf : 存放数据空间的首地址
count:要读到数据的字节个数
返回值:成功 读到数据的个数
失败 -1
读到文件结尾返回0
注意:read读出来的数据,不是字符串,如果要输出字符串,需要单独进行处理。4.lseek //fseek, rewind ftell
函数原型: off_t lseek(int fd, off_t offset, int whence);
功能: 定位文件的位置
参数:fd:文件描述符
offset:偏移量正:向后偏移
负:向前偏移
零:不偏移
whence:SEEK_SET SEEK_CUR SEEK_END
返回值:成功 偏移量
失败 -1
空洞文件:
1.偏移 2.写操作 --------------------------------------------------------------------
1.fileno
函数原型:int fileno(FILE *stream);
功能:获得一个文件流指针中的文件描述符 FILE* fp -> int fd
参数:stream:文件流指针
返回值:
成功返回文件描述符
失败返回-1
2.fdopen
函数原型:FILE *fdopen(int fd, const char *mode);
功能: 将文件描述符转化为文件流指针 int fd -> FILE* fp
参数:fd:已经打开的文件描述符
mode:"r" "r+" "w" "w+" "a" "a+";
返回值:
成功返回文件流指针
失败返回NULL
文件IO与标准IO的比较:文件IO 用于底层设备相关的开发,但是
效率和安全性以及移植性没有标准IO方便。如果是纯上层开发,优先选择使用标准IO。
-----------------------------------------------------------------
目录也是文件:
类似标准IO 目录文件 ----> 目录流指针 ----> 提供给相关函数操作
目录文件 -----> 流 (目录流指针)
01-打开目录 -- opendir
02-读目录 -- readdir
03-关闭目录 -- closedir mkdir tmp
cd tmp
touch file.txt 文件属性,目录 inode,name ls 123
1.打开目标目录
2.读取目录
3.关闭目录
目录 当文件看,只不过操作函数和操作文件函数不一样。
1.opendir
DIR * opendir(const char *name); //cd /home/linux/tmp
功能:
打开一个目录获得一个目录流指针
参数:
name:目录名
返回值:
成功 返回目录流指针
失败 返回NULL
2.readdir
struct dirent *readdir(DIR *dirp);
功能:
从目录流中读取文件信息并将保存信息的结构体
地址返回
参数:
dirp:目录流指针
返回值:
成功 包含文件信息的结构体指针
出错或者读到目录流末尾返回 NULL3、关闭目录
int closedir(DIR *dirp);
功能:关闭之前已经打开的目录流对象
参数:opendir的返回结果中目录流对象
返回值: 成功 0 失败 -1;
目录:
cd
mkdir
rmdir
3.chdir
chdir ("/home/linux"); "../../"
fopen("1.mp4")
int chdir(const char *path);// /home/linux
功能:
改变当前程序的工作路径
参数:
path:改变到的路径
返回值:
成功返回0
失败返回-1
/home/linux/Desktop/Music
"file.txt"
chdir("/root");
"file.txt"
4.getcwd //pwd
char *getcwd(char *buf, size_t size);
功能:获得当前的工作路径
参数:buf:保存工作路径空间的首地址
size:保存路径空间的长度
返回值:成功返回包含路径空间的字符串首地址;失败返回NULL
5.mkdir
函数原型:int mkdir(const char *pathname, mode_t mode);//777 666 --x--x--x
功能:创建一个目录 666-
参数: pathname:路径
mode:mode & ~umask 0002
返回值:成功返回0;失败返回-1
6.rmdir rm -fr rmdir
函数原型:int rmdir(const char *pathname);
功能:删除一个空目录文件
参数:pathname:目录文件的名字
返回值:成功返回0 失败返回-1
drwxrwxr-x 2 linux linux 4096 Mar 22 19:31 ./
说明:
d rwx rwx r-x 2 linux linux 4096 Mar 22 19:31 ./
文件类型 相关权限 目录 所有者 所在组 文件大小 最后被修改的
【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
获取文件属性信息
stat
fstat
lstat --- 软链接文件本身信息
1. 文件的类型 和 权限 ---- st_mode
2. 文件的硬链接数 ---- st_nlink
3. 文件所有者 ---- st_uid + getpwuid
4. 文件所属组 ---- st_gid + getgrgid
5. 文件大小信息 ---- st_size
6. 文件的最后修改的时间---- st_ctime + localtime()/ctime()
7. 文件的名字
目录操作:
1.opendir -->DIR * 目录流指针
2.readdir()
3.closedir()
-------------------------
4.chdir //cd
5.getcwd //pwd
6.mkdir //mkdir
7.rmdir
-------------------------
1.目录文件
opendir
readdir
closedir
2.其它目录操作
chdir
getcwd
mkdir
rmdir //删除的目录必须为空
linux操作系统编程:
实现一个 用户程序
(1).库函数 --来实现
(2).系统调用
文件编程:
1.标准IO --- 库函数的方式
2.文件IO --- linux操作系统提供的 --系统调用了
标准IO库
1. printf/scanf/gets /getchar
#include <stdio> //std--io --- input & output 文件操作:
文本文件,mp3,jpeg,png ,mp4,avi
文件:一组相关数据的有序集合
文件名:这组相关数据的一个名称----------------------------------------------------------------------
#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 * fp 流指针
(1).流
FILE * fp;//流指针------关联一个文件
FILE * 实际上是指向了一块内存空间(缓存,fileno)
标准io; stdio.h
1.标准io的概念
1975 Dennis r IO库,
从C语言的标准,ANSI c
IO input output
I: 键盘是标准输入设备 ====》默认输入就是指键盘 /dev/input
O: 显示器是标准输出设备 ==》默认输出就是指显示器
Linux操作系统当中IO都是对文件的操作
C一部分,任何支持标准C的系统都可使用标准IO实现文件存储
标准IO在UNIX上是对文件IO的封装
一般都是对普通文件操作是一种有缓存的IO 在文件IO和用户程序之间,
加入缓冲区,可以有效减少系统调用的次数,节省系统IO调度资源
说明:
标准IO库,不单单是linux上有,在windows,Mac os上都有。
很多操作系统都实现了标准IO库。
都是依据IOS C标准实现的。
所以基本保证了可移植性。
但是因为标准和具体实现之间的差异,
未必敢保证所有的函数在都可以相互通用。
标准IO都干了些啥?
标准IO处理了很多细节:
(1).处理缓冲区分配 (缓存--提高效率 --- 慢速 快速)
(2).读写IO的块长度的优化
(3).对系统调用进行了封装,内部对应的"文件描述符"
好处:
用户使用方便,不必再担心如何选择正确的块长度。
//地位:
标准I/O库是由Dennis Ritchie在1975年左右编写的。
它是Mike Lesk编写的可移植I/O库的主要修改版本。
令人惊讶的是,35年来,几乎没有对标准I/O库进行修改。
【Linux中文件的类型】
7种,d ,-,l,p管道,s, ,c,b 用命令演示
b c d - l p s
b (block) 块设备文件 /dev/sd
c (char) 字符设备文件
d (directory) 目录文件
- (regular) 普通文件
l (link) 软连接文件
p (pipe) 管道文件
s (socket) UNIX域套接字文件
4.io的分类
标准io,
stdio.h
Dennis Ritchie
标准IO:
ANSI C 设计的一组用文件IO 封装的操作库函数
头文件: stdio.h ==》标准输入输出头文件
/usr/include/stdio.h
<> 是系统库函数,默认路径在/usr/include/
eg : ====》stdio.h ===>stdio.c==>libc.so ==>/usr/lib
"" 是用户自定义函数,默认是当前路径
eg : ===>xxx.h ===>xxx.c
man man ==>所有man的帮助
man xxx == man 1 xxx ===>查看当前xxx命令
man 2 xxx ===>查看xxx对应的系统调用函数
man 3 xxx ===》查看xxx对应的标准库函数
注意:
如果没有命令则直接man xxx 会显示其函数
如果没有系统调用则显示系统库函数帮助
printf scanf
sprintf
getchar putchar gets puts\n
getc putc fgets fputs fread fwrite ftell
rewind fseek
文件io,系统调用,底层软件
文件内容的分类, 文本文件,二进制文件
流:
FILE*
数据从文件当中流入和流出所体现出来的字节
流叫做流
流的分类:
二进制流: 2001 \n
二进制数据的流
文本流:
ASCII码数据的流 \n \t
FILE 结构定义的对象 FILE * 称之为流对象,也叫文件流指针。
流对象 ===》头 《===数据====》尾
5.函数说明:
//稍后说明 ---一组函数介绍完
行缓冲,1k, terminal,主要用于人机交互stdout
缓存区满或者遇到\n刷新 1024
行缓存多是关于终端的一些操作
1.遇到\n刷新
2.缓存区满刷新
3.程序结束刷新
4.fflush刷新 fflush(stdout);
全缓冲,4k,主要用于文件的读写
缓存区满刷新缓存区 4096
对普通文件进行标准IO操作,建立
的缓存一般为全缓存
刷新条件:
1.缓存区满刷新
2.程序结束刷新
3.fflush来刷新 fflush(fp);
无缓冲,0k 主要用于出错处理信息的输出 stderr
不对数据缓存直接刷新
printf();==>>stdout
fprintf(strerr,"fopen error %s",filename);
界面交互 出错处理
使用gdb查看,FILE结构体,或使用写入数据测试缓冲区。
缓冲区的大小是可以设置
6.函数API接口
//fopen --打开文件
FILE *fopen(const char *path, const char *mode);
功能:
打开一个文件并建立一个流
参数:
path:
要打开文件的 文件名 (可以指定路径) --本质是个字符串
mode:
r 只读 文件不存在报错 文件存在则只读打开
r+ 读写 文件不存在报错 文件存在则读写打开
w 只写 文件不存在则创建 文件存在则清0只写打开
w+ 写读 文件不存在则创建 文件存在则清0写读打开
a 追加可写 文件不存在则创建 文件存在则追加只写打开
a+ 追加读写 文件不存在则创建 文件存在则追加读写打开
返回值:成功返回建立的文件流指针;失败返回NULL
//三类函数:
//1.按字符读写
//2.按行读写
//3.按对象读写
//按字符读写 fgetc - fputc
fputc()
fputc()
int fputc(int c, FILE *stream);
功能:向流中写入一个字符
参数:c:要写入的字符
stream:文件流指针
返回值:成功返回写入的字符ASCII码值;失败返回EOF
fgetc()
函数原型:int fgetc(FILE *stream);
功能:从流中读取一个字符
参数:stream:文件流指针
返回值:成功返回读到字符的ASCII码值;读到文件末尾返回EOF;失败返回EOF -1
默认的流指针:
stdin --- 标准输入
stdout --- 标准输出
stderr --- 标准出错 --- 屏幕
feof()
函数判断
函数原型:int feof(FILE *stream);
功能:判断当前参数stream的文件流指针是否到达文件结尾。如果到达文件结尾则返回真,否则返回假 注意:该操作一定要在一次IO操作之后判断。
参数:stream 要判断结尾的文件流对象
返回值:成功到达结尾是 真 ;否则 是假
fgets()
函数原型:char *fgets(char *s, int size, FILE *stream);
功能:从stream流对象关联的文件中获取size大小字节的文本数据并存储到s对应的本地内存(栈区数组,堆区内存)
参数: s 要存储数据的本地内存
size 要获取的数据长度,单位字节。
stream 要获取的目标文件流对象,可以是stdin ,程序会阻塞等待如果是普通文件fp 则指向文件第一行数据
返回值:成功 返回指向有效数据的首地址,一般等于s的地址;失败或者文件末尾 NULL;
fgets读取结束的条件:
1.EOF 文件结束
2.\n 读到 "换行符" 则读取结束
注意:
会被保存到 buffer(保存数据的这块内存中)
3.size-1 个字符
'\0' //按字符串读写
fputs()
函数原型:int fputs(const char *s, FILE *stream);
功能:从s所在的本地内存中获取一行数据,并写入stream对应的文件流对象。
参数: s 要写的信息,一般是固定的字符串或者有数据的数组。
stream 要写入的目标文件流对象
返回值:成功 nonnegative number on success ;失败 -1;
gets和fgets的区别:
1.gets是危险的,因为没有规范读 到数据的上限
2.gets会去掉从终端读入的\n字符
3.fgets会读到n个数据,如果n个数据中存在\n字符则立即停止当前的读取操作
4.fgets不会去掉从流中读到的\n字符char buf[1024];
5.fgets(buff, sizeof(buff), stdin);gets(buff);
fread()
函数原型:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从指定的stream流对象中获取nmemeb个大小为size字节的数据块到ptr
所在的本地内存中。
参数:ptr 要存储数据的本地内存一般是数组或者结构体指针
size 单个数据块的元数据大小。最小单元的大小
nmemb 要获取的数据块的个数,拷贝的数据块个数。
stream 要获取数据的源文件流对象,如果是stdin表示从
键盘获取数据,如果是fp文件则表示从普通文件获取。
返回值:成功 小于等于nemeb的整数,表示获取的数据长度;失败 小于0,结尾 0;
fwrite()
函数原型:size_t fwrite(const void *ptr,size_t size,size_t nmemb,FILE *stream);
功能:从ptr所在本地内存中取出nmemb个大小为size的数据块写入到stream流对应的文件流对象中。
参数:ptr 要写的数据块地址,一般是数组或者结构体指针
size 要写的数据块元数据大小,单位是字节
nmemb 要写的数据块的个数
stream 要写的目标文件流对象。如果是stdout则表示数据会
返回值:成功 小于等于nmemb 的个数。失败 <0
fseek()
函数原型:int fseek(FILE *stream, long offset, int whence);
功能:将stream流文件中的文件指针从whence位置开始偏移offset字节的长度。
参数:stream 要移动文件指针的目标文件流对象。
注意:不支持设备文件,一般用于普通文件。
offset 要在文件内偏移的距离,单位字节。
如果值为整数,则向文件末尾偏移
如果值为负数,则向文件开头偏移
whence 偏移的起始位置,由系统定义的三个宏开始。
SEEK_SET 文件的开头位置
SEEK_CUR 文件的当前位置
SEEK_END 文件的末尾位置
返回值:成功: 返回 0 失败: -1;
如果从文件的指定位置向后偏移过程中已经超过了文件的当前末尾位置,则会自动以'\0'来填充文件内容,从而形成一种被称为"空洞文件" 的特殊文件
rewind()
等效于:fseek(stream,0L,SEEK_SET);long ftell(FILE *stream);
函数原型:rewind(fp);
功能:获取当前文件流指针的具体位置,一般以文件开头到当前指针的字节数为返回值。
参数:stream 要返回指针距离的文件流对象
返回值:成功 获取到的距离长度,单位是字节;失败 -1;
学习产出:
通过fgets/fputs实现一个文件的拷贝。
使用fread和fwrite方式完成任意普通文件的拷贝。
使用read,write复制文件