文件指令+基础io

回顾标准io接口:stdout(显示器) stdin(键盘) stderr(显示器)标出标准输入标准错误为FILE*结构体(文件指针)
接口:fopen(打开文件) fclose(关闭文件) fwrite(文件中写入数据) fread(文件中读取数据) fseek(跳转读写位置)
fgets(获取一行数据) fprintf(文件中格式化写入数据)sscanf
fopen:打开模式: r(只读,只读在起始位置)r+(可读可写,读写也在起始位置)w(截断文件成为0长度或者创建一个文件用于只写,也是从文件的起始位置写入)
截断文件:文件原来有则清空原有内容或者文件不存在则创建这个文件
w+打开一个文件以可读可写方式打开如果文件不存在则创建,否则则截断,也是从文件的起始位置开始)
a:追加写每次都是写到文件末尾如果文件不存在则创建,写则写到文件末尾
a+;以可读并且追加的方式打开一个文件如果文件不存在则创建,并且初始换文件的读写位置读是在文件的起始位置写一直写入到文件的末尾

#include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 int main(){
5 int ret;
6 FILE fp=NULL;
7 fp=fopen("./tmp.txt",“a”);
8 if(fp==NULL){
9 perror(“fopen error”);
10 return -1;
11 }
W> 12 char
ptr=“nihaoa!!”;
13 // size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE stream);
14 //第一个是写入的数据,size_t size数据块大小(一块数据有多大),
15 //size_tnmemb有多少块 FILE
stream文件流指针
E> 16 ret=fwrite(ptr,strlen(ptr),1,fp);
17 printf(“fwrite item:%d\n”,ret);
18 //读
19 char buf[1024]={0};
20 //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ret=fread(buf,1023,1,fp);//不能给1024,字符串有结尾标志\0要打印字符串接受了1024
22 //则字符串没有\0则打印出来会有可能乱码
23 printf(“read buf:[%s]-ret:[%d]\n”,buf,ret);
24 return 0;
25 }
[chenyongjie@localhost linux]$ ./baseio
fwrite item:1
read buf:[]-ret:[0]
,则发现没有读到数据但是已经创建了一个文件并且将数据写进去了
: tmp.txt  ⮀ ⮂
1 nihaoa!! 创建了一个tmp.txt,写入了你好啊
会发现write item 写 了1块为整体字符串的长度读数据的时候什么都没有读到并且返回值为0(表示读到文件末尾),如果向文件写入一串数据那么文件读写位置已经在文件末尾,以a方式打开文件本身就在文件末尾读一个数据读不到

#include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 int main(){
5 int ret;
6 FILE fp=NULL;
7 fp=fopen("./tmp.txt",“a+”);//a+可读,但是a不能读
8 if(fp==NULL){
9 perror(“fopen error”);
10 return -1;
11 }
W> 12 char
ptr=“nihaoa!!”;
13 // size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE stream);
14 //第一个是写入的数据,size_t size数据块大小(一块数据有多大),
15 //size_tnmemb有多少块 FILE
stream文件流指针
E> 16 ret=fwrite(ptr,strlen(ptr),1,fp);
17 printf(“fwrite item:%d\n”,ret);
18 //int fseek(FILE *stream, long offset, int whence);
19 fseek(fp,0,SEEK_SET);//从文件起始位置偏移量为0
20 //第一个参数是文件流指针,第二个为偏移值第三个为偏移的起始位置(从哪偏移)
//第一个参数是文件流指针,第二个为偏移值第三个为偏移的起始位置(从哪偏移)
21 //从哪偏移:SEEK_SET(从文件的起始位置偏移),
22 //SEEK_CUP(从文件当前读写位置偏移),SEEK_END(从文件的末尾)
23 //读
24 char buf[1024]={0};
25 //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
26 ret=fread(buf,1023,1,fp);//不能给1024,字符串有结尾标志\0要打印字符串接受了1024
27 //则字符串没有\0则打印出来会有可能乱码
28 perror(“fread error”);//看系统给的错误原因为坏的文件描述符:a表示以追加写的方式
29 //打开不能读数据,但是a+可以
30 printf(“read buf:[%s]-ret:[%d]\n”,buf,ret);
fclose(fp);
31 return 0;
32 }
[chenyongjie@localhost linux]$ ./baseio
fwrite item:1
fread error: Success
read buf:[nihaoa!!
如果改为r+
在写入数据之前
fp=fopen("./tmp.txt",“r+”);//a+可读,但是a不能读
8 if(fp==NULL){
9 perror(“fopen error”);
10 return -1;
11 }
E> 12 fseek(fp,-10,SEEK_SET);

fseek(fp,-10,SEEK_SET);//从文件起始位置向前偏移10个位置
W> 13 char* ptr=“chenyongji\n”;//刚好10个字节
发现打印结果为
[chenyongjie@localhost linux]$ ./baseio
fwrite item:1
fread error: Invalid argument
read buf:[chenyongji

hhhh!nihaoa!!nihaoa!!nihaoa!!
]-ret:[0]

在tmp.txt中
chenyongji
2
3 hhhh!nihaoa!!nihaoa!!nihaoa!!
chenyongji写入进去但是下面会有一行空行为什么?
相当于chenyongjie\n
第二行也有一个\n
再次运行发现还是一行没有成为两行
[chenyongjie@localhost linux]$ ./baseio
fwrite item:1
fread error: Invalid argument
read buf:[chenyongji

hhhh!nihaoa!!nihaoa!!nihaoa!!
]-ret:[0]
以读写r+模式读写的起始位置是从文件的起始位置开始是以覆盖的形式写入,但是并不会清空文件内容也不会追加到文件末尾,而是从文件的起始位置读和覆盖式写入
将原来 的数据覆盖了chenyongji\n\n第二个\n到下一行然后打印空白行
fseek(fp,-10,SEEK_SET);没有影响依然从文件的起始位置开始写的
fseek(fp,10,SEEK_END);//从文件末尾再往后偏移10个字节进行写入
fwrite item:1
fread error: Success
read buf:[chenyongji

hhhh!nihaoa!!nihaoa!!nihaoa!!
]-ret:[0]
发现没有读出来但是写出来了
chenyongji
2
3 hhhh!nihaoa!!nihaoa!!nihaoa!!
4 @@@@@@@@@@chenyongji
~@表示为空没办法显示这个数据已近读到但是为什么没有显示字符串结尾标志位\0这个(@)就是\0就是空,当读到第一个@之后就显示不出来但是读到了
当处理大批量数据读数据用了strlen用srlen处理会出错,因为文件里面可以写入空数据但是处理字符串以\0为止之后就不在处理所以strlen在查找find以\0为止,就会导致后面有数据没有处理到,若读的文件有空数据就会截止后面并没有处理,用memcmp一个字节一个字节开始比较以字符串多长比较
最后记得关闭fcolse(fp)
fgets获取一行数据
fprintf(格式化文件字符串可以写到任意的文件流指针可以向文件写入数据) sprintf(格式化字符串后放到char str中) snprintf(字符串连接函数(字符串数字格式化函数),把一堆数字放到buf然后进行处理) printf(对多个字符串进行格式化打印)
标准款IO接口的操作句柄为:FILE
—文件流指针通过文件流指针对文件操作
stdout stdin stderr —都为FILE*文件流指针
在哪里查看
vim /usr/include/stdio.h

/stdin
extern struct _IO_FILE stdin; / Standard input stream. */
169 extern struct _IO_FILE stdout; / Standard output stream. */
170 extern struct _IO_FILE *stderr;

struct _IO_FILE;
45
46 __BEGIN_NAMESPACE_STD
47 /* The opaque type of streams. This is the definition used elsewhere. */
48 typedef struct _IO_FILE FILE;
是一个文件流指针结构体被定义为FILE
系统调接口:
open write read close lseek(跳转读写位置)
man open 可以看到open头文件为<fcntl.h>
int open(const char *pathname, int flags, mode_t mode)
名字
选项标志(flag)
flags 是通过 O_RDONLY, O_WRONLY 或 O_RDWR (指明 文件 是以 只读 , 只写或 读写 方式 打开的
mode_t mode在linux中如果文件不存在打开文件则创建,则创建这个文件linux系统调用接口需要给与权限,如果不给,则读写操作不了
grep -R ‘O_RDONLY’ /usr/include/找一下定义o-rdonly

#define O_ACCMODE 0003
43 #define O_RDONLY 00
44 #define O_WRONLY 01
45 #define O_RDWR 02
umask看掩码
设置umask在主程序中umask(0);
//系统调用接口
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <stdlib.h>
7 int main(){
8 // int open(const char *pathname, int flags, mode_t mode)
9 // pathname文件路径名
10 // flags:选项标志
11 // 必选项必选其一:O_RDONLY只读O_WRONLY只写O_RDWR可读可写为数字,位图标记
12 // 可选项:O_CREAT文件不存在则创建,存在则打开
13 // O_EXCL与O_CREAT同时用时,若文件存在则报错
14 // O_TRUNC 打开文件同时截断文件长度为0
15 //O_APPEND写追加,写数据追加到文件末尾
16 //mode_t mode 创建文件时给定权限(8进制数字)
17 //mode&(~umask)
18 //返回值:文件描述符-正整数,错误:-1
E> 19 umask(0);//只针对当前调用进程
20 //int fd=open("./tmp.txt",O_RDWR | O_CREAT | O_TRUNC,0777);
//可读可写方式打开文件并且文件不存在能够创建,文件数据已经有了截断它,最后
22 //给的权限为0777,前面这个0必须要有
23 int fd=open("./tmp.txt",O_RDWR | O_CREAT | O_APPEND,0777);
24 //文件可读可写没有创建然后使写追加模式
25 if(fd<0){
26 perror(“open error”);
27 return -1;
28 }
29 //ssize_t write(int fd,const void *buf,size_t count);ssize_t有符号的长整
30 型数据 size_t无符号长整型数据
31 //fd:打开文件所返回的文件描述符
32 //buf:要向文件写入的数据
33 //count:要写入的数据长度
34 //返回值:实际的写入字节数,错误而:-1
35 char buf[1024]=“nihao~~~!!\n”;
36 int ret=write(fd,buf,strlen(buf));
37 if(ret<0){
38 perror(“ret error”);
39 return -1;
}
41
42 //ssize_t read(int fd,const void buf,size_t count);ssize_t有符号的长整
43 型数据 size_t无符号长整型数据
44 //fd:打开文件所返回的文件描述符
45 //buf:对读取到的数据进行存储的位置
46 //count:要读取的数据长度
47 //返回值:实际的读取字节数,错误而:-1读到0个字节表示读到文件末尾
48 //off_t lseek(int fd,off_t offset,int whence)
49 //fd:打开文件返回描述符
50 //offset:偏移量
51 //whence:偏移位置
52 //返回值:放回当前位置到文件起始位置的偏移量
53 //可以用:将文件读写位置跳转到文件末尾然后通过返回值获取下这个值就是文件长度
54 //SEEK_END,SEEK_CUR,SEEK_SET
55 lseek(fd,0,SEEK_SET);
56 memset(buf,0x00,1024);//初始化内存数据将buf的起始位置的这块内存进行初始化
57 //内容初始化为0从buf开始1024个字节
58 ret=read(fd,buf,1023);//虽然想读1023但是通过返回值直到实际读了多少
59 if(ret<0){
perror(“read error”);
61 return -1;
62 }
63 printf(“read buf:[%s]\n”,buf);//但是没有读到,写成功了因为用了O_APPEND
64 //写数据时候直接读写位置跑到文件末尾再读就文件末尾读读不到
65 //所以读之前要跳转
66
67 //int close(fd);
68 close(fd);
69 }
./sysio
read buf:[nihao~~~!!
nihao~~~!!
nihao~~~!!
]
然后看有么有写入
nihao~~~!!
2 nihao~~~!!
3 nihao~~~!!
~
也写入了
系统调用接口:
open write read close lseek
flag 参数:必选 O_RDONLY O_WRONLY O_RDWR
其他O_CREAR O_TRUNC O_APPEND O_EXCL
ftruncate:通过文件名将文件长度截断为指定长度
man 2 unlink通过文件名称删除一个文件
fileno参数为文件流指针功能:通过文件流指针返回一个数字描述符
文件描述符和文件流指针的关系
标准库接口使用文件流指针FILE

系统调用接口使用文件描述符 int :数字
库函数与系统调用接口关系:上下级调用关系
fwrite("nihao"fp)—>write(“hello”,fd)(内部调用fd)
通过文件流指针找到相应的文件描述符才能使用系统调用接口使用数据
通过fwrite向文件里写入数据在frwite中调用writefp中包含了文件描述符fp指向flieno就是fd,这样就实现了通过系统调用写数据
缓冲区在哪里?
printf打印数据的时候如果没有刷新缓冲区数据并不会直接写入文件而是先写入缓冲区,缓冲区在哪里是谁的缓冲区?
标准输入标准输出 标准错误
stdin(0)使用的宏STDIN_FILENE
stdout(1) STDOUT_FILENO
stderr(2) STDERR_FILENO
write 直接打印剩下的三秒后打印
//缓冲区的体会
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 int main(){
6 printf(“printf”);
7 fwrite(“fwrite”,6,1,stdout);
8 fprintf(stdout,“fprintf”);
9 write(1,“write”,5);//标准输出//write(STDOUT_FILENO,“write”,5);
10 sleep(3);
11 return 0;
12 }
意味着系统调用接口在向文件中写入数据的时候它并没有写入缓冲区直接写入文件,缓冲区是(标准库)库接口的缓冲区
在哪里呢?每一个文件都有一个缓冲区(针对每个文件),缓冲区在文件流指针当中,文件流指针是一个结构体,缓冲区就是 char *_IO_read_ptr;
char *_IO_read_end;
char *_IO_read_base;//end和base描述了一个区域
char *_IO_write_ptr;char *_IO_write_base;char *_IO_write_end;
char *_IO_buf_base;char *_IO_buf_end;等待都是缓冲区额
stdout()包含了读缓冲区和写缓冲区当调用pritf(hello)写到写缓冲区,当缓冲区满了之后或者刷新缓冲区的时候才会写入到文件,写入文件的时候要用系统调用接口,系统调用接口是fd,缓冲区满了后或刷新通过stdout得到一个fd通过write接口进行写入,然后在写入一个标准输出文件里面就有了hello,系统调用接口使用的是文件描述符所以直接写入到文件,所以没有经过数据缓冲这个过程,缓冲是在用户态完成的
write(hell,1,5),直接写入不经过缓冲区
文件流指针这个结构体包含了文件描述符,当我们使用标准库接口进行io,则最终是通过文件流指针找到文件描述符进而对文件进行操作
我们所说的缓冲区实际上是文件流指针为每个文件所维护的一个缓冲区(用户态缓冲区)
内核态用户态
在虚拟地址空间中从上到下上半部分1G是内核空间,然后下面是 用户空间,
判断一个程序运行在用户态还是内核态
内核态就是当前程序需要完成的功能由操作系统内核完成(发起系统调用之后这个操作就由操作系统完成就说这个程序功能完成是在内核态,运行在内核态)
进程运行在内核态发生调用之后由操作系统内核完成
用户态:进程运行在用户态更多是我们自己写的数据这些操作并没有涉及到内核的核心操作.
memorycopy拷贝数据将数据拷贝到一个buffer中,这个buffer的地址是用户态空间内的是栈内地址用户空间的地址,这时候buffer这块内存在用户空间
内核完成某个功能是将数据交给内核在内核中维护,在内核中运行使用的地址叫内核空间
printf操作数据是在用户空间地址,是用户态空间,操作都在用户态;
用户态:进程运行在用户态指的是当前操作,操作的空间是用户空间
内核态:进程运行在内核态值的是当前完成功能是操作系统内核完成操作在内核空间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值