1、系统文件I/O
系统文件I/O相关接口
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int close(int fd);
//pathname:需要打开或创建的目标文件
//flags:打开文件的参数,多个采用‘或’运算O_RDONLY|O_WRONLY|O_RDWR|O_CREAT|O_APPEND
//mode:创建文件时的文件权限
//返回值为新打开文件的文件描述附,失败返回-1
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
实例:
#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<cstring>
using namespace std;
const char * msg = "This is a system I/O test!\n";
void sys_write_file()
{
umask(0);
int fd = open("sys_wr_file", O_WRONLY|O_CREAT, 0644);
if(fd < 0)
{
cout<<"Error"<<endl;
return;
}
int count = 10;
while(count)
{
write(fd, msg, strlen(msg));
count--;
}
close(fd);
}
void sys_read_file()
{
int fd = open("sys_wr_file", O_RDONLY);
if(fd < 0)
{
cout<<"Error"<<endl;
return;
}
char buf[1024] = {};
while((read(fd, buf, strlen(msg))) > 0)
{
cout<<buf;
}
close(fd);
}
int main()
{
sys_write_file();
sys_read_file();
return 0;
}
2、文件描述附fd
linux进程默认打开的三个缺省文件描述附:
0:标准输入 --> 键盘
1:标准输出 --> 显示器
2:标准错误 --> 显示器
文件描述附是从0开始的小整数,打开文件时,操作系统在内存中要创建相应的数据结构描述目标文件,用file结构体表示一个已经打开的文件对象。进程执行open系统调用时,需要让进程和文件关联起来,每个进程都有一个指针*files,指向一张表files_struct,该表包含一个指针数组,每个元素都是一个指向打开文件的指针,下标就是文件描述附。
分配规则:在files_struct数组中找到当前未被使用的最小的一个下标,作为新文件描述附
#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
using namespace std;
int main()
{
int fd;
fd = open("sys_wr_file", O_RDONLY);
if(fd < 0)
{
cout<<"Error"<<endl;
return 0;
}
cout<<fd<<endl;
close(fd);
close(0);
fd = open("sys_wr_file", O_RDONLY);
if(fd < 0)
{
cout<<"Error"<<endl;
return 0;
}
cout<<fd<<endl;
close(fd);
close(2);
fd = open("sys_wr_file", O_RDONLY);
if(fd < 0)
{
cout<<"Error"<<endl;
return 0;
}
cout<<fd<<endl;
close(fd);
return 0;
}
3、重定向
#include<iostream>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
using namespace std;
int main()
{
close(1);
int fd = open("re_dx", O_WRONLY|O_CREAT, 0644);
if(fd < 0)
{
cout<<"Error"<<endl;
return 0;
}
cout<<fd<<endl;
fflush(stdout);
close(fd);
return 0;
}
以上代码关闭了文件描述附1,本来输入到显示器的内容,输出到了打开的文件中,fd=1。这种现象叫重定向。(>、>>、<)
dup2系统调用:复制文件描述附
#include <unistd.h>
int dup(int oldfd)
int dup2(int oldfd, int newfd);
在shell的重定向功能中,(输入重定向”<”和输出重定向”>”)就是通过调用dup或dup2函数对标准输入和标准输出的操作来实现的。
4、FILE
IO相关函数与系统调用接口对应,库函数封装系统调用。本质上,文件都是通过文件描述附fd访问的。FILE结构体内部必定封装了fd。
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<unistd.h>
using namespace std;
int main()
{
const char * msg0 = "cout\n";
const char * msg1 = "fwrite\n";
const char * msg2 = "write\n";
cout<<msg0;
fwrite(msg1, strlen(msg1), 1, stdout);
write(1, msg2, strlen(msg2));
return 0;
}
5、动态库和静态库
静态库(.a):程序在编译链接时把库的代码链接到可执行文件中,程序运行时不再需要静态库
动态库(.so):程序运行时才需要链接动态库代码,多个程序共享使用库的代码
- 一个动态库链接的可执行文件仅仅包含他用到的函数入口地址的一个表,而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接
- 动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间