Linux下文件IO系统调用

一、文件和文件描述符

(一)linux文件扩展名
在linux中,扩展名是用来区分不同的文件。

  • .tar,.tar.gz,.tgz,.zip,.tar.bz表示压缩文件,创建命令为tar,gzip,unzip等
  • .sh 文件表示shell脚本文件
  • .pl 表示perl语言文件
  • .py 表示python语言文件
  • .conf 表示系统服务的配置文件
  • .c 表示C文件
  • .h 表示头文件
  • .cpp 表示C++源文件
  • .so 表示动态库文件
  • .a 表示静态库文件
  • .html,.php 表示网页相关文件

(二)文件类型
Linux系统把一切都看作文件,Linux有7种文件类型:普通(regular file)文件、目录(directory)文件、符号(Link)链接、字符(character)设备文件、块(block)设备文件、管道(pipe)文件、嵌套字(socket)文件。
其中文件、目录、符号链接会占用磁盘空间来存储,而块设备、字符设备、套接字、管道是伪文件,并不占用磁盘空间。

1.普通文件(regular file)第一个字符为[ - ]
包括:
①纯文本档(ASCII):这是Linux系统中最多的一种文件类型,称为纯文本档。是因为内容为我们人类可以直接读到的数据,例如数字、字母等等。
②二进制文件(binary): 你的Linux中的可执行文件(scripts, 文字型批处理文件不算)就是这种格式的。
③数据格式文件(data):有些程序在运作的过程当中会读取某些特定格式的档案,那些特定格式的档案可以被称为数据文件 (data file)。一般用cat看到的都是乱码。

2.目录(directory): 第一个字符为[ d ]

3.连接文件(link)第一个字符为[ l ]
关于软链接
软链接文件有点类似于Windows的快捷方式。它实际上是特殊文件的一种。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

1.产生软链接的语法
# ln -s 源文件或目录 目标文件或目录

2.软链接也叫符号链接,它和硬链接有所不同,软链接文件只是其源文件的一个标记。当我们删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但我们却不能查看软链接文件的内容了。
值得我们注意的是:当我们修改链接文件的内容时,就意味着我们在修改源文件的内容。当然源文件的属性也会发生改变,链接文件的属性并不会发生变化。当我们把源文件删除后,链接文件只存在一个文件名,因为失去了源文件,所以软链接文件也就不存在了。这一点和硬链接是不同的;

3.示例
touch f1(创建一个f1的文件)
ln f1 f2 创佳一个f2的硬连接
ln -s f1 f3 创建一个f3的软连接
此时如果删除f3,对f1,f2无影响;如果删除f2,对f1,f3也无影响,如果删除f1,那么因为f2也应用f1,所以并不影响f2节点的,touch 创建的文件仍然存在;但是此时f3因为是软连接,导致f3失效。如果删除f1,f2 ,那么touch 创建的文件会被删除

4.设备和设备文件
快设备文件,即一些存储文件,如硬盘、软盘等,第一个字符为[ b ]
(注意:设备文件最好不要随便修改,链接文件说白了就是win下的快捷方式。)
字符设备文件,即一些串行端口的接口文件,如键盘、鼠标等,第一个字符为[ c ]

5.套接字(sockets)第一个字符为[ s ]
还被称为数据接口文件,这种类型的文件通常被用在网络上的数据连接。我们可以启动一个程序来监听客户端的请求,而客户端就可以通过数据接口文件来进行数据通信。

6.管道(FIFO,pipe)第一个字符为[ p ]
FIFO也是一种特殊的文件类型,他主要的目的解决多个程序同时访问一个文件所造成的错误问题,first-in-first-out。
Linux下文件IO系统调用_第1张图片
(三)文件描述符
文件描述符(file descriptor,fd)是Linux内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所执行I/O操作的系统调用都通过文件描述符。
程序在开始运行时,系统会自动打开三个文件描述符,0是标准输入,1是标准输出,2是标准出错。
POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码,因此第一次打开的文件描述符一定是3。
Linux下文件IO系统调用_第2张图片

二、文件I/O操作

open()系统调用
int open(const char *path,int oflag,.../*mode_t mode*/);
open()系统调用用来打开一个文件,并返回一个文件描述符(file description),并且该文件描述符是当前进程最小、未使用的文件描述符数值。
1. 参数

  • path:要打开的文件、设备的路径
  • oflag: 由多个选项进行 “或” 运算构造oflag参数。
    必选: O_RDONLY(只读)、O_WRONLY(只写)、O_PDWR(读写)
    可选: O_APPEND 每次写时都追加到文件的尾端。
    O_CREAT 文件不存在则创建它,使用该选项需要第三个参数mode。
    O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;
    O_NONBLOCK 如果path是一个FIFO、块设备、字符特殊文件则此选项为文件本次打开和后续的I/O操作。

2.设置非租塞模式方式

  • O_EXEC、O_SEARCH、O_CLOEXEC、O_NOCTTY…
    mode: oflag带O_CREAT选项时可以用来创建文件,这时必须带该参数用来指定创建文件的权限模式,如066。否则不需要。使用示例代码
int fd;
fd = open(“text.txt”, O_RDWR|O_CREAT|O_TRUNC, 0666);
fd = open(“text.txt”, O_WRONLY|O_APPEND);

create()系统调用

int creat(const char *path, mode_t mode);

此函数用来创建一个新文件并返回其fd。它等价于open(path,O_WRONLY|O_CREAT|O_TRUNC, mode);

int fd;
fd=creat(“text.txt”, 0644);

close()系统调用

int close(int 	fd);

该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核将会自动关闭它所有打开的文件。
write()系统调用

ssize_t	write(int 	fd,	const void *buf,size_t nbytes);

write()函数用来往打开的文件描述符fd指向的文件中写入buf指向的数据,其中nbytes指定要写入的数据大小。如果返回值<0则说明写入出错,譬如尝试往一个只读的文件中写入则会抛错,错误的原因系统会保存到errno变量中去。如果>0则为实际写入的数据大小。

lseek()系统调用

off_t lseek(int fd, off_t offset, int whence);

我们在从文件里读出内容,或往文件写如内容的时候都有一个起始地址,这个起始地址就是当前文件偏移量,当我们对文件进行读写的时候都会使文件偏移量往后偏移。这点就类似于我们打开记事本开始编辑文本时的光标,我们读或写入时从光标所在位置开始读写,每读写一个字节都会使光标往后偏移。
通过lseek()这个函数我们可以调整文件偏移量的地址。

whence可以是一下三个值:
Linux下文件IO系统调用_第3张图片
而offset就是相对于whence 的偏移量,譬如:
lseek(fd, 0, SEEK_SET); 将文件偏移量设置到了文件开始的第一个字节上;
lseek(fd, 0, SEEK_END); 将文件偏移量设置到文件最后一个字节上;
lseek(fd, -1, SEEK_END); 将文件偏移量设置到文件最后的倒数第一个字节上;

read()系统调用

ssize_t read(int fd, void *buf, size_t nbytes);

read()函数用来从打开的文件描述符对应的文件中读取数据放到buf指向的内存空间中去,最多不要超过nbytes个字节,这里的nbytes一般是buf剩余的空间大小。如read成功,则返回实际读到的字节数(由nbytes或读到文件尾决定,其中EOF宏用来判断是否到了文件尾),如果返回值小于0则表示出错,如尝试读一个没有权限读的文件时就会抛错。

dup()和dup2()系统调用

int dup(int fd);
int dup2(int fd, int fd2);

这两个函数都可以用来复制一个新的文件描述符来指向fd对应的文件。这两个系统调用经常用在标准输入、标准输出、标准出错重定向。
dup()返回的新文件描述符一定是当前可用文件描述符中的最小数值;
dup2可以用fd2参数来指定新的文件描述符。如果fd2已经打开,则先关闭。如fd等于fd2, 则dup2返回fd2, 而不关闭它。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char *argv)
{
	int fd = -1;
	fd = open("std.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
	if(fd < 0)
	{
		printf("Open file failure: %s\n", strerror(errno));
		return ;
	}
	dup2(fd, STDIN_FILENO); //标准输入重定向到 std.txt 文件中去
	dup2(fd, STDOUT_FILENO); //标准输出重定向到 std.txt 文件中去
	dup2(fd, STDERR_FILENO); //标准出错重定向到 std.txt 文件中去
	printf("fd=%d\n", fd);
	close(fd);
}

三、示例代码

#include 
#include 
#include 
#include 
#include 
#include 

#define BUFSIZE 1024
#define MEG_STR "hello world\n"

int main(int argc,char **argv)
{
    int     fd = -1;
    int     rv = -1;
    char    buf[BUFSIZE];

    fd=open("/home/wyz/work/test.txt",O_RDWR|O_CREAT|O_TRUNC,0666);
    if(fd < 0)
    {
        printf("open/create file test.txt failure");
        perror("message");
        return 0;
    }
    printf("open file returned file Description [%d]\n",fd);

    if( (rv=write(fd,MEG_STR,strlen(MEG_STR))) < 0 )
    {
        printf("write %d bytes into file faliure: %s\n",rv,strerror(errno));
        goto cleanup;
    }
    
    memset(buf,0,sizeof(buf));
    lseek(fd,0,SEEK_SET);
    if( (rv=read(fd,buf,sizeof(buf))) < 0)
    {
        printf("read data from file failure: %s\n",strerror(errno));
        goto cleanup;
    }

    printf("read %d bytes data from file:\n%s\n",rv,buf);

cleanup:
    close(fd);

    return 0;
}

运行结果:
Linux下文件IO系统调用_第4张图片
在这里插入图片描述

你可能感兴趣的:(linux)