Linux下对文件进行输入输出操作有三种编程方式:
一种是调用C库中的文件的I/O函数,一种是使用Linux的系统调用和C++文件流操作。
概念
I/O就是输入输出,它是主存储器和外存之间的复制过程,其中数据从设备到内存的过程称为输入,数据从内存到设备的叫作输出。
LinuxI/O编程
文件描述符
Linux下所有对文件或设备的操作都是通过文件描述符进行的。当打开或创建一个文件的时候,内核向进程返回一个文件描述符。操作时只需要通过该文件描述符。
当一个进程启动时,默认打开3个文件,标准输入,标准输出,标准错误,对应0、1、2。
将文件转化为描述符的函数如下:
int fileno(FILE* stream);
描述符转化为文件的函数:
FILE *fdopen(int fd,const char* mode);
打开或创建文件
Linux提供open函数来打开或创建文件:
#include<unistd.h>
int open(const char* pathname,int falgs);
int open(const char* pathname,int falgs,mode_t mode);
关于falgs和mode的宏如下:
文件的访问权限是umask&~mode得出来的
关闭文件
可以用函数close来关闭文件
#include<unistd.h>
int close(int fd);
读取文件中的数据
#include<unistd.h>
ssize_t read(int fd,void* buf,size_t count);
写入数据
#include<unistd.h>
ssize_t write(int fd,const void* buf,size_t count);
文件锁定
当多个用户共同使用、操作同一个文件时,Linux采用的方法是给文件上锁来避免竞争状态。
文件锁分为建议性锁和强制性锁。
建议性锁是只在文件上上锁,其他进程可以读到锁的存在,但是这个锁不能阻止其他进程对这个文件操作。
强制性锁是上锁后直接阻塞后来的进程,直到第一个进程将锁解开。
对文件加锁是原子性的。子进程不继承父进程的锁。
#include<fcntl.h>
#include<unistd.h>
int fcntl(int fd,int cmd,struct flock* lock);
其中的l_type有3个选项:
F_RDLCK共享锁,只读用,多个进程可以同时建立读取锁
F_WRLCK独占锁,在任何时刻只能有一个进程建立写入锁
F_UNLCK解除锁定
l_wheence只能是以下几个值
SEEK_SET:文件开始位置
SEEK_CUR:文件当前位置
SEEK_END:文件末尾
l_start为开始偏移量:l_len:加锁的长度 l_pid:当前操作文件的进程ID号
文件和内存映射
就是将普通文件映射到内存中,普通文件被映射到内存后,进程就可以像访问普通内存一样访问文件,不需要再调用read和write
void* mmap(void* start,size_t length,int prot,int falgs,int fd,off_t offset);
prot表示映射区保护方式:
PROT_EXEC:映射区可被执行
PROT_READ:可读取
PROT_WRITE:写入
PROT_NONE:不可访问
falgs用来指定映射对象的类型、是否共享:
MAP_FIXED MAP_SHARED MAP_RIVATE MAP_ANONYMOUS MAP_LOCKED MA_DENYWRITE
MMAP和共享内存对比
共享内存允许两个或多个进程共享一个给定的存储区。因为数据不需要来回复制,是最快的进程间通信机制。
mmap机制:
优点是存储量很大(多于主存)
缺点是进程间读取和写入速度比主存慢
shm机制:
优点是进程间访问速度比磁盘快
缺点是存储量不能非常大
C++方式文件I/O
流的概念
对标准输入设备和标准输出设备的输入输出简称为标准I/O。
简称文件I/O,对内存中的字符串的输入输出简称为I/O.
C++流是指信息从外部输入设备向计算机内部输入和从内存向外部输出设备进行输出的过程。
3种输入输出流:
标准I/O流,文件I/O流,字符串I/O流
流的类库
打开文件
void open(const char* filename,ios::openmode mode);
mode:文件打开方式
关闭文件
void close();
写入文件
用<<向ofstream和fstream对象写入
读取文件
用>>向ifsteam和fstream对象读取
小实验
#incldue<fstream>
#include<iostream>
using namespace std;
int main (){
char data[100];
//以写模式打开文件
ofstream outfile;
outfile.open ("afile.dat");
cout <"Writing to the file"<endl;
cout <"Enter your name:";
cin.getline(data,100);
//向文件写入用户输入的数据
outfile <data <endl;
cout <"Enter your age:"
cin >data;
cin.ignore();
//再次向文件写入用户输入的数据
outfile <<data <<endl;
//关闭打开的文件
outfile.close();
//以读模式打开文件
ifstream infile;
infile.open ("afile.dat");
cout <"Reading from the file"<<endl;
infile >data;
//在屏幕上写入数据
cout <<data <<endl;
//再次从文件读取数据,并显示它
infile >>data;
cout <<data <endl;
//关闭打开的文件
infile.close();
return 0;
}
文件位置指针
int fseek(FILE* fp,LONG offset,int orgin);
offset的三种情况:SEEK_SET,SEEK_CUR,SEEK_END
创建和删除文件目录项
目录文件存放的是文件名和对应的inode,统称目录项。link和unlink用来创建和删除硬链接。删除文件的真正含义是文件的连接数为0
int link(const char* oldpath,const char* newpath);
int unlink(const char* pathname);
当删除一个文件的时候,系统并不一定会释放inode节点的内容,当满足
iNode节点记录指向该节点的硬链接数为0
没有进程打开指向该文件的文件
所以unlike并不一定会释放inode节点
小实验
最后把所有知识点串起来做个试验
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
‸ int fd;
struct stat buf;
stat ("test.txt",&buf)
printf("1.link=%d\n",buf.st_nlink);//1.未打开文件之前测试链接数
fd=open("test.txt",O_RDONLY);//2.打开已存在的文件test.txt
stat ("test.txt",&buf);
printf("2,1ink=%d\n",buf.st_nlink);//测试链接数
close(fd);//3.关闭文件test.txt
stat ("test.txt",&buf);
printf("3.link=%d\n",buf.st_nlink);/测试链接数
link("test.txt","test2.txt");//4.创建硬链接test2.txt
stat ("test.txt",&buf);
printf("4.link=%d\n",buf.st_nlink);//测试链接数
unlink("test2.txt");//5.删除test2.txt
stat ("test.txt",&buf);
printf("5.link=%d\n",buf,st_nlink);//测试链接数
//6,重复步骤2 //重新打开test.txt
td=open("test.txt",O_RDONLY);//打开己存在的文件test.txt
stat ("test.txt",sbuf);
printf("6.link=%d\n",buf.st_nlink);//测试链接数
unlink("test,txt");//7.删除test,txt
fstat(fd,&buf);
printf("7.link=%d\n",buf.st_nlink);//测试链接数
close(fd);//8.此步骤可以不显式写出,因为进程结束时,打开的文件自动被关闭
}