Linux文件及文件I/O

在Linux下,一切皆文件。这是咱们嵌入式Linux开发与应用这门课的老师常常挂在嘴边的一句话。足以体现出在Linux操做系统中,对于一切资源的管理都是对文件的操做。shell

Linux系统中每个分区都是一个文件系统,都有本身的目录层次。Linux会将这些在不一样分区的,单独的文件系统按必定的方式造成一个系统的总目录层次结构。数组

Linux下能够经过shell命令来操做文件,可是功能有必定限制;咱们也能够经过系统调用或者C语言的库函数对文件进行操做socket

  1. Linux下的文件主要包括两方面的数据:文件自己所包含的数据,以及文件属性,也称为元数据。函数

  2. 目录在Linux下也是文件,称为目录文件。目录文件的内容是该目录的目录项,目录项是该目录下的文件和目录相关的信息。每当建立一个新目录的时候,OS会自动建立两个目录项——“.”和“..”测试

  3. Linux采用的是标准的目录结构——树形结构(B树家族)spa

Linux既然采用了树形结构的目录形式,整个OS只有一棵文件树,这样方便OS对文件进行统一管理。Linux操做系统中的这颗文件树的树根叫作根文件系统,用“/”表示,能够经过使用cd /命令直接到达根目录。各个磁盘是经过挂载以文件夹的形式访问操作系统

根文件系统:3d

  • /bin:该目录下存放供用户使用的完成基本维护任务的命令.指针

  • /boot:该目录下存放着和OS启动时使用的一些核心文件。code

  • /dev:该目录中包含全部的系统设备文件。从该目录能够访问各类系统设备,它还包含了建立设备文件的MAKEDEV.

  • /home:该目录存储普通用户的我的文件,每一个用户的主目录均在/home下以用户名命名的文件夹。

  • /etc:该目录包含系统和应用软件的配置文件。

  • /lib:该目录存放着系统最基本的共享连接库(至关于Windows下的DLL)和内核模块。

  • /lib64:若是是64位系统,它会有这个,存放64程序的共享连接库,同时也会有一个lib32.

  • /media:可移动设备的挂载点,OS一般把U盘等设备自动挂载到该目录下。

  • /opt:第三方的软件默认安装到这个位置。并非每一个Linux发行版都会建立这个目录。

  • /mnt:临时用于挂载文件系统的。通常状况下这个目录下是空的,在咱们挂载分区的时候会在该目录下建立目录。

  • /proc:存在于内存中的虚拟文件系统,里面保存了内核和进程的状态信息。

  • /root:这是root(超级管理员)用户的主目录,于/home下的普通用户目录类型。

  • /sbin:供root用户使用的可执行文件,可能是系统管理命令。

  • /usr:静态的用户级应用程序。

  • /tmp:该目录用于保存临时文件。

Linux文件分类:

  1. 普通文件:用户和OS的数据,程序等信息文件

  2. 目录文件:Linux文件系统将文件索引节点号和文件名同时保存在目录中,因此目录就是一张表。OS能够修改目录文件,用户只能读目录文件

  3. 设备文件:Linux下一切皆文件,设备也是文件。每一种I/O设备对应一个设备文件,存放于/dev下。

  4. 管道文件:这是Linux用于进程之间通讯的文件,一个进程在管道这一段写入数据,另外一个进程在管道的另外一端读取数据。管道文件通常是FIFO文件。

  5. 连接文件:又被称做符号连接文件,它提供了一种共享文件的方式。它包含了指向文件的指针。

经过ls -l能够查看文件类型和属性

结果分多行显示,距离说明一下每行显示的意义。例如第一行exec这个文件的信息行。首先,咱们看到这行以“-”开头,表示exec是一个普通文件。同时注意到第三行以d开头,这说明new是一个目录文件。

  • -:表示普通文件
  • d:表示目录文件
  • l:表示连接文件
  • c:表示字符设备
  • b:表示块文件
  • p:表示管道文件
  • f:表示堆栈文件

接着看第一个符号后面的信息,注意到后面仍旧有9个字符。这9个字符分红3组,即每3个一组,”w"表示可写,“r”表示可读,“x”表示可执行。第一组3个符号表示的是文件拥有者对该文件的权限;第二组3个符号表示该文件所在组的其余拥有者对该文件的权限;第3组表示系统其余用户对该文件的权限。

继续能够看到有个数字,对于普通文件,这个数字表示连接数,对于目录文件来讲这个数字表示第一级子目录数。接下来的两组信息分别是用户名和组名,而后是文件大小(单位是字节),接着是文件最后的修改日期,最后就是文件名。

Linux文件描述符

在Linux下当一个进程打开文件的时候,OS会返回相应的文件描述符,程序为了处理该文件必须使用这个文件描述符。文件描述符是一个正整数。通常而已,当一个进程启动的时候,他会打开3个文件:标准输入,标准输出,标准错误。这3个文件对应的文件描述符分别是0,1,2.一般使用宏:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO.文件描述符是一个索引,指向内核中打开文件的记录表。

Linux操做系统给咱们提供了6个系统调用create,open,write,close,read,lseek。系统调用是不带缓冲区的。他们是POSIX标准提供的。这些函数须要的头文件#include<fcntl.h>,#include<sys/types.h>,#include<sys/stat.h>。

create函数用于建立一个文件,它的功能能够被open函数取代,open函数由3个参数的时候,就能够当作create函数使用,这时若是文件不存在,open就会建立这样一个文件。例如:open(path,O_WRONLY|O_CREAT|O_TURNC,mode);而且open弥补了create的一个不足之处是:create建立的文件是以只写方式打开所建立的文件,因此当须要读取的时候,须要先close,而后在open一次。如今则能够这样:open(path,O_RDWR|O_CREAT|O_TRUNC,mode);

mode值包含了对文件的访问权限位。正如上面描述的同样,每一个文件有9个访问权限位,而且能够分为3组。

mode

含义
S_IRUSR 用户读
S_IWUSR 用户写
S_IXUSR 用户执行
S_IRGRP 组读
S_IWGRP 组写
S_IXGRP 组执行
S_IROTH 其余读
S_IWOTH 其余写
S_IXOTH

其余执行

若是打开的文件是在某个目录文件下,那么该目录应该是可执行的,由于对于目录文件而言,可执行表明着搜索位,咱们能够找该目录下的文件。目录的读只表明咱们能够读取该目录的文件列表,不能进行其余操做。若是当前打开了一个文件,若是是root用户的进程,那么它确定能访问该文件。若是进程是文件全部者执行的,那么对文件的权限取决于第一组的权限;若是进程是文件全部者所在组或者附属组之一,那么对文件的权限取决于第二组权限。若进程是其余用户执行的,那么对文件的操做取决于第三组权限。

在使用open函数打开一个文件的时候,最经常使用的三个参数是:O_WRONLY(只写),O_RDONLY(只读),O_WRRD(可读可写)

另外两种是:O_EXEC(执行),O_SEARCH(搜索,应用于目录)。另外open打开的文件,返回的文件描述符必定是最小的未使用描述符。path所指定的路径能够是绝对路径,也能够是相对路径。

read函数用于从已打开的文件中读取数据

若是read成功,返回读取到的字节数。若已到达文件尾端,返回0。读取出错返回-1.

write函数用于讲数据写入已打开的文件中

若是写入成功,返回以写字节数,不然,返回-1.

close函数用于关闭文件

关闭一个文件并释放该进程加在该文件上的全部锁。当一个进程终止的时候,会自动关闭它打开的全部文件。全部有时候并不显式的使用close关闭文件。返回0表示成功,返回-1表示错误。

lseek函数用于移动文件的读写位置。

每一个打开文件都有一个与其相关联的“当前文件偏移量”。用于计算从文件开始处的字节数。一般,读写都是从当前文件偏移量处开始的,并使用偏移量增长所读写的字节数。系统默认该偏移量为0。可使用lseek函数来指定一个打开文件的偏移量。

一个简单的例子以下:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
    int fd,size;
    int l;
    char str[] = {"This is My Schoolnumber:1507050314"};
    char tmp[51] = {0};
    fd = creat("hello.txt",(S_IRUSR|S_IWUSR));     //在当前目录建立一个hello.txt文件,他是可读可写的。
    write(fd,str,strlen(str));    //写入This is My Schoolnumber:这句话
    close(fd);                        //关闭文件
    open("hello.txt",O_RDONLY);       //以只读方式打开文件
    read(fd,tmp,strlen(str));      //读文件
    close(fd);              //关闭文件 
    printf("%s\n",tmp);

    return 0;
}

打印结果以下:

须要注意的是,tmp数组须要所有初始化为0,'\0'的ASCII就是0.这样将打开的文件中读取的文本信息打印的时候才能正常打印,不会乱码。不然不知道在哪儿终止,将会产生乱码。

注意:在使用Linux的系统调用操做文件的时候,是无缓冲的,这点很重要。当你在作少许,大批次写入的时候效率会很低。所以注意使用缓冲(用数组的之类的暂时保存一下),能提升I/O效率。

另一个测试程序以下:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>

int main()
{
    int fd,size;
    int l;
    char str1[] = {"This is My Schoolnumber:1507050314\n"};
    char str2[] = {"This is My Schoolnumber:1507050316\n"};
    char tmp[51] = {0};
    fd = creat("hello.txt",(S_IRUSR|S_IWUSR));     //在当前目录建立一个hello.txt文件,他是可读可写的。
    write(fd,str1,strlen(str1));    //写入This is My Schoolnumber:这句话
    close(fd);                        //关闭文件
    open("hello.txt",O_RDWR|O_APPEND);       //以可读可写,写追加方式打开文件
    lseek(fd,5,SEEK_CUR);            //更改文件偏移量,从5这个位置开始计算偏移量
    read(fd,tmp,strlen(str1));      //读文件
    write(fd,str2,strlen(str2));    //写文件
    close(fd);              //关闭文件 
    printf("%s",tmp);
    return 0;
}

运行结果以下:

打印的是“is My Schoolnumber”,没有了This。说明更改这个当前文件偏移量成功了。使用cat命令打印Hello.txt文件的内容,能够看到写入也是成功的。

lseek不能够用于管道,FIFO,socket文件。另外lseek的文件偏移量的大小能够大于当前文件的长度,在这种情形下,对该文件的下一次写将加长该文件,并在文件中构成一个空洞。文件空洞并不要求在磁盘上占据空间。

相关文章
相关标签/搜索