标签:否则 ror 假设 开始 道具 查看 trunc 偏移量 默认
从CPU到文件是Output的一个过程,从文件到CPU是一个Input的过程,这个过程是以CPU为点的
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd = 0;
fd = open("./file.txt", O_RDWR);
if(-1 == fd) {
printf("open fail\n");
return 1;
}else {
printf("open ok\n");
}
char buf[] = "Steve Yu, today is nice";
write(fd, (void *)buf, strlen(buf));
lseek(fd, SEEK_SET, 0);
char buf2[30] = {0};
read(fd, buf2, sizeof(buf));
puts(buf2);
close(fd);
return 0;
}
记录打开文件信息
open函数会申请一段内存空间(内核缓存)
open为啥要开辟内存缓存空间?
内存读写 > 磁盘读写,我们会省时间
open仅仅开辟了内存缓存空间,并没有数据,只有读写数据的时候
先将数据读到内核缓存中,之后下层会让内存缓存和磁盘数据进行交换
读写的时候,数据的流动?
硬件 -> 驱动缓存 -> 内核缓存 -> 应用程序中的数组
(仅掌握open函数,其余函数已经过时)
以上三个不可以用 | 进行宏运算,而可以与以下进行宏运算
flag参数之O_CREAT、O_EXCL
可以使用O_RDWR|O_CREAT进行组合,那么可以不存在进行创建,存在不打开的功能
文件描述符指向打开的文件,后面read/write/close等操作,都是基于文件描述符进行操作
每个程序运行起来后,就是一个进程,系统给每个进程分配01023的描述符的范围,返回的文件描述符,是在01023的某个数字
open返回的文件描述符是规则的:
open返回文件描述符池中,返回当前没用的最小的一个
进程运行起来,0/1/2会默认使用,最小没用的是3
fopen是C库标准io函数
fopen成功后,FILE*的文件指针,打开了文件
fopen成功后,返回的是FILE*文件指针,指向打开的文件
Linux中,如果像上述中,打开失败,那么就直接失败,遇到比较难排查的错误原因,难以查处具体错误
errno我们查看man 3 errno中,可以看到,一系列错误宏定义,我们include "errno.h"即可
printf("%d: open error", errno);
这样即可发现17:open error
,打开错误
2.具体错误
我们仅仅知道错误号,不知道具体错误,怎么办呢?
perror函数:我们通过man 3 perror,可以查看到错误号的具体使用
perror可以打印的错误号以及具体错误
perror("open fail");
我们可以知道,控制台打印:open fail: File exists
3.使用man 2 open
进行查看ERRORS下错误号
比如EACCES,不允许访问
我们因为记不住错误号,也记不住宏定义,所以,我们有了perror
close(fd):不主动关闭,应用也会自动关闭fd,但是我们得进行手动关闭
open打开的时候会在task struct中创建结构体空间,如果文件关闭,那么该结构体空间被释放
类似free(空间地址)
malloc和free是给C调用的库看书,Linux在释放的时候,有自己的释放函数
好习惯必须关闭,否则我们在生产环境,容易内存溢出
结构体在存在在运行的进程中,在task struct是程序在运行的时候进行开辟
进程运行结束,linux系统会调用自己的系统函数,进行释放task struct
有关0/1/2文件描述符
键盘->键盘驱动缓存->内核缓存->应用缓存
#include <unistd.h>
#include <stdio.h>
int main() {
int ret = 0;
char buf[30] = {0};
ret = read(0, (void *)buf, 30);
if(-1 == ret) {
perror("read fail");
return -1;
}
puts(buf);
return 0;
}
scanf底层调用read(0, buf, size)这个,这样就能兼容不同操作系统
答案是不可以,用perror打印,会得到bad description的
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
int fd = 1, ret = 0;
char buf[] = "steve\n";
write(fd, buf, sizeof(buf));
close(fd);
return 0;
}
假设我们write(1, &a, sizeof(a))
, a是一个int值,那么会打印一个(char)a进行
printf不能工作
使用2文件描述符也能进行打印
1打印普通信息,2打印报错信息
perror是通过2进行打印,如果close(2),则不能进行perror
0:STDIN_FILENO
1:STDOUT_FILENO
2:STDERR_FILENO
lseek用来调整读写的位置,调用成功返回偏移量,调用失败返回-1
我们可以通过lseek获取文件大小
1.fd:打开文件
2.whence:粗定位
SEEK_SET:起始位置
SEEK_CUR:当前读写位置
SEEK_END:文件末尾位置
3.offset:微调
进行偏移,正数向前移动,负数向后
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
int fd = 0, ret = 0;
fd = open("./file.txt", O_RDONLY);
if(-1 == fd) {
perror("file open failed");
exit(-1);
}
ret = lseek(fd, 0, SEEK_END);
printf("文件大小%d\n", ret);
return 0;
}
4.使用od -c filename,可以查看以字符进行显示字符
进程表:task_struct
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
void print_error(char* str) {
perror(str);
exit(-1);
}
int main() {
int fd1, fd2;
fd1 = open("./file.txt", O_RDWR);
if(-1 == fd1) print_error("open fail");
fd2 = open("./file.txt", O_RDWR);
if(-1 == fd2) print_error("open fail");
// 写入操作
return 0;
}
存在相互覆盖的关系
解决方案:使用O_APPEND进行追加
gcc share_op_file.c -o a
gcc share_op_file.c -o b
./a
./b
那么会出现覆盖情况
解决方案:也使用O_APPEND进行追加
在unistd.h中
dup用来复制文件描述符,得到一个新的文件描述符,指向原来的文件,指向最小没用的那一个
fd2 = dup(fd1)
fd2 = (fd1, 4)
实现文件共享操作,不使用APPEND也不会出现文件覆盖。使用dup或dup2的时候,永远只有一个文件表。
步骤:
打开文件fd
close(1)
进行复制fd到1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int fd1;
fd1 = open("data.txt", O_RDWR|O_CREAT);
close(1);
dup(fd1);
printf("Hello World");
return 0;
}
当我们文件描述符写死了,那么可以进行文件重定位来进行,linux底层的重定位>是使用dup/dup2作为底层的支持
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl是文件控制函数(file control)
fd:指向打开文件
cmd:控制命令
先掌握前两个F_DUPFD
和F_GETFL、F_SETFL
模拟DUP:
fcntl(fd, F_DUPFD, 0);// 第三个参数没有,用0表示
模拟DUP2:
fcntl(fd, F_DUPFD, 1);// 模拟DUP2,进行用1
设置
fcntl(fd, F_SETFL, O_RDWR|O_APPEND); // 修改打开时的Flag,返回新设置的标志
保留原标志,加新标志
flag = fcntl(fd, F_GETFL); // 获取
fcntl(fd, F_SETFL, flag|O_APPEND); // 叠加
标签:否则 ror 假设 开始 道具 查看 trunc 偏移量 默认
原文地址:https://www.cnblogs.com/littlepage/p/12637233.html