概述
在Linux系统下,通常以一个非负整数来代指一个打开的文件,这些文件可以包括终端,socket,设备,普通文件等等。规定的三个标准的文件描述符为0,1,2下面分别介绍(在交互式shell中,这些文件描述符通常指向shell运行所在的终端):
文件描述符0:
用途:标准输入
POSIX名称: STDIN_FILENO文件描述符1:
用途:标准输出
POSIX名称STDOUT_FILENO文件描述符2
用途:标准错误
POSIX名称:STDERR_FILENO
注:推荐使用
常用的标准函数
fd = open(pathname,flags,mode)
fd即为文件描述符, flags参数指定了文件的打开方式,mode指定了创建文件的访问权限,若open函数没有创建文件,则此参数可以忽略。
numread = read(fd, buffer,count)
从文件描述符fd所指代的文件中读取count个数据到buffer中,返回值即为读取到的字节数。
numwritten = write(fd,buffer,count)
与read函数类似
status = close(fd)
输入与输出操作完成之后,调用次函数以释放资源。
一个简单的I/O操作如下,实现了对文件内容的复制:
#include <iostream>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
using namespace std;
int main(int argc, char *argv[])
{
int inputFd, outputFd, openFlags;
mode_t filePerms;
ssize_t numRead;
char buf[BUF_SIZE];
/*确保在终端输入了正确的文件路径*/
if (argc != 3 || strcmp(argv[1], "--help") == 0)
cout<<"param error??"<<endl;
/*打开输入文件*/
inputFd = open(argv[1], O_RDWR);
if (inputFd == -1)
cout<<"open file"<<argv[1]<<"failed!!"<<endl;
openFlags = O_CREAT | O_WRONLY | O_TRUNC;
filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
/*打开输出文件*/
outputFd = open(argv[2], openFlags, filePerms);
if(outputFd == -1)
cout<<"open file"<<argv[2]<<"failed!!"<<endl;
/*复制文件内容*/
while ((numRead = read(inputFd, buf, BUF_SIZE)) > 0)
if (write(outputFd, buf, numRead) != numRead)
cout<<"couldnot wrire whole buffer"<<endl;
if (numRead == -1)
cout<<"read wrong!!"<<endl;
/*关闭两个文件*/
if (close(inputFd) == -1)
cout<<"can not close input file!!"<<endl;
if (close(outputFd) == -1)
cout<<"can not close output file!!"<<endl;
return 0;
}
g++ main.cpp -o io_test
好玩的是,例如下面的命令:
./io_test /dev/tty a.txt
会接受开启程序之后用户在终端的输入,知道使用Ctrl+c结束程序之前,用户的输入会一直记录到a.txt当中。反之亦然。
open函数
fd = open(pathname,flags,mode)
mode参数只在创建新文件时有用,主要有以下几个参数可供选择:
- O_RDONLY:只读方式打开文件
- O_WRONLY:只写方式打开文件
- O_RDWR: 读写方式打开文件
flags参数较多且经常使用,下面介绍各种参数的用途:
- O_RDONLY:只读方式打开
- O_WRONLY:只写方式打开
- O_RDWR:读写方式打开
- O_CREAT:若文件不存在则创建,注意要加入mode参数
- O_DIRECT:无缓冲的输入输出
- O_DIRECTORY:若pathname不是文件目录则失败
- O_EXCL:结合O_CREAT参数使用,用于创建文件,若文件已经存在,则不会打开文件且报错
- O_NOATIME:读取文件时,不修改最近访问时间
- O_NOCTTY:不让pathname所指向的文件成为控制终端
- O_NOFOLLOW:对符号链接不予解引用
- O_TRUNC:截断已有文件,使其长度为0
- O_APPEND:总在文件末尾追加数据
- O_NONBLOCK:以非阻塞方式打开
- O_SYNC:以同步方式打开文件
read()函数
read函数从文件描述符代指的文件中读取数据。buffer参数通过用来存放输入数据的内存缓冲区地址。read成功将返回读取的字节数。当然也可以使用上述提到的标准文件描述符,直接从终端读取数据
numread = read(STDIN_FILENO, buffer, MAX_READ)
注意,由于直接从终端读取,读取的数据类型不确定,read函数无法在读取的数据末尾加上结尾字符’\0’,因此需要人为添加
buffer[numread] = '\0'
才能正确显示输入的数据。
改变文件偏移量
off_t lseek(int fd, offt_t offset, int whence)
off_t数据类型为有符号整数型,whence参数表明依照哪个基点来结束offset参数
- SEET_SET:文件头部
- SEET_CUR:当前文件偏移量
- SEET_END:文件尾部,offset参数从文件最后一个字节的下一个字节开始
打印错误信息
采用linux系统读写函数时,经常出现文件不存在或者访问权限的问题,要知道出现的是什么错误,可以使用perror函数
perror(string)
这个函数可以打印上一次函数的错误信息,string主要为了显示错误的同时显示一些描述性的信息