linux 文件I/O操作

版权声明:原创文章,转载请注明出处 https://blog.csdn.net/hza419763578/article/details/83994643

目录

一、linux系统文件和文件系统

1.1文件类型

1.2 system函数

1.3linux文件权限

1.4 设置系统文件、目录初始默认权限

1.5文件其他属性


一、linux系统文件和文件系统

003vPl7Rty6E8kZRlAEdc&690

  • /bin
    bin是Binary的缩写, 这个目录存放着最经常使用的命令。包括用户管理员命令,如:cat,chmod,cp,date,ls

  • /boot:
    这里存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件。

  • /dev :
    dev是Device(设备)的缩写, 该目录下存放的是Linux的外部设备,在Linux中访问设备的方式和访问文件的方式是相同的。

  • /etc:
    这个目录用来存放所有的系统管理所需要的配置文件和子目录。

  • /home
    用户的主目录,在Linux中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的。

  • /lib
    这个目录里存放着系统最基本的动态连接共享库,其作用类似于Windows里的DLL文件。几乎所有的应用程序都需要用到这些共享库。如:c/c++等库文件 其他大部分文件存放在/usr/lib下

  • /lost+found
    这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件

  • /media
    linux系统会自动识别一些设备,例如U盘、光驱等等,当识别后,linux会把识别的设备挂载到这个目录下。双系统windows下的磁盘和插入的u盘都会在'media/用户名/' 目录下   

  • /mnt
    系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在/mnt/上,然后进入该目录就可以查看光驱里的内容了。

  • /opt
     这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的。应用商店里的好多软件包括deepinwine都在这里。(通过deepinwine安装的windows软件也在下面)

  • /proc
    这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。
    这个目录的内容不在硬盘上而是在内存里,我们也可以直接修改里面的某些文件,比如可以通过下面的命令来屏蔽主机的ping命令,使别人无法ping你的机器:

    echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
  • /root
    该目录为系统管理员,也称作超级权限者的用户主目录。

  • /sbin
    s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序。

  • /selinux
     这个目录是Redhat/CentOS所特有的目录,Selinux是一个安全机制,类似于windows的防火墙,但是这套机制比较复杂,这个目录就是存放selinux相关的文件的。

  • /srv
     该目录存放一些服务启动之后需要提取的数据。

  • /sys

     这是linux2.6内核的一个很大的变化。该目录下安装了2.6内核中新出现的一个文件系统 sysfs 。

    sysfs文件系统集成了下面3种文件系统的信息:针对进程信息的proc文件系统、针对设备的devfs文件系统以及针对伪终端的devpts文件系统。

    该文件系统是内核设备树的一个直观反映。

    当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。

  • /tmp
    这个目录是用来存放一些临时文件的。

  • /usr
     这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于windows下的program files目录。

  • /usr/bin:
    系统用户使用的应用程序。

  • /usr/sbin:
    超级用户使用的比较高级的管理程序和系统守护程序。

  • /usr/src:
    内核源代码默认的放置目录。

  • /var
    这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。

  • /run
    是一个临时文件系统,存储系统启动以来的信息。当系统重启时,这个目录下的文件应该被删掉或清除。如果你的系统上有 /var/run 目录,应该让它指向 run。

在 Linux 系统中,有几个目录是比较重要的,平时需要注意不要误删除或者随意更改内部文件。

/etc: 上边也提到了,这个是系统中的配置文件,如果你更改了该目录下的某个文件可能会导致系统不能启动。

/bin, /sbin, /usr/bin, /usr/sbin: 这是系统预设的执行文件的放置目录,比如 ls 就是在/bin/ls 目录下的。

值得提出的是,/bin, /usr/bin 是给系统用户使用的指令(除root外的通用户)而/sbin, /usr/sbin 则是给root使用的指令

/var: 这是一个非常重要的目录,系统上跑了很多程序,那么每个程序都会有相应的日志产生,而这些日志就被记录到这个目录下,具体在/var/log 目录下,另外mail的预设放置也是在这里。

1.1文件类型

普通文件(-)
目录文件(r)
符号链接文件(l)
字符设备文件(c)
块设备文件(b)
管道文件(p)
socket文件(s)

1.2 system函数

头文件:#include<stdlib.h>
函数功能:在进程中开始另一个进程
函数原型:int system(const char* string)
函数传入值:系统变量 shell命令
函数返回值:执行成功返回执行shell命令后的返回值;调用/bin/sh失败返回127;
                     其他原因失败则返回-1,;参数string为空(null),则返回非0值
备注:system()调用fork()产生子进程,子进程调用/bin/sh -c string来执行参数
          string字符串所代表的命令,此命令执行完毕后随即返回原调用的进程。如果调用
          成功,返回shell命令后的返回值可能也是127(该shell命令就返回数字结果127),
          因此,最好能检查error来确定执行情况。

eg1:列出当前目录和系统目录'/dev/sda1' '/dev/lp0'下的信息

#include<stdio.h>
#include<stdlib.h>
int main(){
	int newret;
	printf("列出当前目录下的文件信息:\n");
	newret=system("ls -l");
	printf("列出'/dev/sda1'下的文件信息:\n");
	newret=system("ls /dev/sda1 -l");
	printf("列出'/dev/lp0'下的文件信息:\n");
	newret=system("ls /dev/lp0 -l");
	return 0;
}

运行结果:

eg2:编写一个c程序,用system函数调用一个shell函数,完成某文件中某一个字符的查找

/*完成某文件中某一字符串的查找*/ 
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main(){
	char a[100],b[100],cmd[100];
	printf("请输入文件名:\n");
	scanf("%s",a);
	printf("请输入字串:\n");
	scanf("%s",b);
	strcpy(cmd,"./substr ");
	strcat(cmd,a);
	strcat(cmd," ");
	strcat(cmd,b);
	printf("执行命令:%s\n",cmd);
	system(cmd);
	return 0;
}

运行结果:

eg3:编写c程序,用system函数调用另一个c程序

#include<stdio.h>
#include<stdlib.h>
int main(){
	system("./5-1-1");
	return 0;
}

运行结果:同eg2 就是调用eg2的c程序

1.3linux文件权限

四种权限:可读r,可写w,可执行x,无权限-

头文件:#include<sys/types.h>
      #include<sys/stat.h>
函数功能:改变文件权限 (注意这是c语言函数 不是shell命令)
函数原型:int chmod(const char* path,mode_t mode)
函数传入值:依参数mode的权限来更改参数path 指定文件的权限
函数返回值:权限改变成功返回0,失败返回-1,错误返回errno

mode参数说明
参数 说明
S_IRUSR 所有者具有读权限
S_IWUSR 所有者具有写权限
S_IXUSR 所有者具有执行权限
S_IRGRP 组具有读权限
S_IWGRP 组具有写权限
S_IXGRP 组具有执行权限
S_IROTH 其他用户具有读权限
S_IWOTH 其他用户具有写权限
S_IXOTH 其他用户具有执行权限

eg1:将~/test/a.txt文件的权限设置为所有者可读可写,其他用户只读

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<stdlib.h>
int main(){
	printf("修改前 ~/test/a.txt 的权限:\n");
	system("ls -l ~/test/a.txt");
	chmod("/home/hanzhuan/test/a.txt",S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	printf("修改后 ~/test/a.txt 的权限:\n");
	system("ls -l ~/test/a.txt");
	return 0;
}

运行结果:

1.4 设置系统文件、目录初始默认权限

所需头文件:#include<sys/types.h>
                     #include<sys/stat.h>
函数功能:设置建立新文件时的权限掩码(但是返回的是原来的权限掩码)
函数原型:mode_t umask(mode_t mask);
函数传入值:4位8进制数
函数返回值:原先系统的权限掩码(umask值)
备注:建立文件时,该文件的真正权限为(0666-mask)
           建立文件夹时,该文件夹的真正权限为(0777-mask)
           值范围为0~7 开头的0表示8进制 

eg1:设计一个程序,应用umask函数设置系统文件与目录的权限掩码.要求:新建文件的权限分别是0000和0222

/*设计一个程序,应用umask函数设置系统文件与目录的权限掩码*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
int main(){
	mode_t new_umask,old_mask;
	new_umask=0666;
	old_mask=umask(new_umask);//设置新权限掩码为0666(新文件权限为0000 新文件夹权限为0111) 返回旧权限
	printf("系统原来的权限掩码是:%o\n",old_mask);
	printf("系统新的权限掩码是:%o\n",new_umask);
	printf("系统新的文件权限是:%o\n",0666-new_umask);
	printf("系统新的文件夹权限是:%o\n",0777-new_umask);
	system("touch file1");
	system("mkdir dir1");
	printf("创建了文件file1\n");
	printf("创建了文件夹dir1\n");
	new_umask=0444;
	old_mask=umask(new_umask);//设置新权限掩码为0444(新文件权限为0222 新文件夹权限为0333)
	printf("系统原来的权限掩码是:%o\n",old_mask);
	printf("系统新的权限掩码是:%o\n",new_umask);
	printf("系统新的文件权限是:%o\n",0666-new_umask);
	printf("系统新的文件夹权限是:%o\n",0777-new_umask);
	system("touch file2");
	system("mkdir dir2");
	printf("创建了文件file2\n");
	printf("创建了文件夹dir2\n");
	system("ls file1 -l");
	system("ls -l | grep dir1");
	system("ls file2 -l");
	system("ls -l | grep dir2");
	chmod("file2",S_IWUSR|S_IXOTH);
	printf("强制改为w-x:\n");
	system("ls file2 -l");
	return 0;
}

运行结果:

1.5文件其他属性

强大的stat结构体

在使用这个结构体和方法时,需要引入:

<sys/types.h>

<sys/stat.h>

struct stat这个结构体是用来描述一个linux系统文件系统中的文件属性的结构。

可以有两种方法来获取一个文件的属性:

1、通过路径:

int stat(const char *path, struct stat *struct_stat);

int lstat(const char *path,struct stat *struct_stat);

两个函数的第一个参数都是文件的路径,第二个参数是struct stat的指针。返回值为0,表示成功执行。

执行失败是,error被自动设置为下面的值:

EBADF: 文件描述词无效

EFAULT: 地址空间不可访问

ELOOP: 遍历路径时遇到太多的符号连接

ENAMETOOLONG:文件路径名太长

ENOENT:路径名的部分组件不存在,或路径名是空字串

ENOMEM:内存不足

ENOTDIR:路径名的部分组件不是目录

这两个方法区别在于stat没有处理字符链接(软链接)的能力,如果一个文件是符号链接,stat会直接返回它所指向的文件的属性;而lstat返回的就是这个符号链接的内容。这里需要说明一下的是软链接和硬链接的含义。我们知道目录在linux中也是一个文件,文件的内容就是这这个目录下面所有文件与inode的对应关系。那么所谓的硬链接就是在某一个目录下面将一个文件名与一个inode关联起来,其实就是添加一条记录!而软链接也叫符号链接更加简单了,这个文件的内容就是一个字符串,这个字符串就是它所链接的文件的绝对或者相对地址。

2、通过文件描述符

int fstat(int fdp, struct stat *struct_stat);  //通过文件描述符获取文件对应的属性。fdp为文件描述符

下面是这个结构的结构

struct stat {
        mode_t     st_mode;       //文件对应的模式,文件,目录等
        ino_t      st_ino;       //inode节点号
        dev_t      st_dev;        //设备号码
        dev_t      st_rdev;       //特殊设备号码
        nlink_t    st_nlink;      //文件的连接数
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者对应的组
        off_t      st_size;       //普通文件,对应的文件字节数
        time_t     st_atime;      //文件最后被访问的时间
        time_t     st_mtime;      //文件内容最后被修改的时间
        time_t     st_ctime;      //文件状态改变时间
        blksize_t st_blksize;    //文件内容对应的块大小
        blkcnt_t   st_blocks;     //伟建内容对应的块数量
      };

stat结构体中的st_mode 则定义了下列数种情况:

    S_IFMT   0170000    文件类型的位遮罩
    S_IFSOCK 0140000    scoket
    S_IFLNK 0120000     符号连接
    S_IFREG 0100000     一般文件
    S_IFBLK 0060000     区块装置
    S_IFDIR 0040000     目录
    S_IFCHR 0020000     字符装置
    S_IFIFO 0010000     先进先出

    S_ISUID 04000     文件的(set user-id on execution)位
    S_ISGID 02000     文件的(set group-id on execution)位
    S_ISVTX 01000     文件的sticky位

    S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限
    S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限
    S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限

    S_IRGRP 00040             用户组具可读取权限
    S_IWGRP 00020             用户组具可写入权限
    S_IXGRP 00010             用户组具可执行权限

    S_IROTH 00004             其他用户具可读取权限
    S_IWOTH 00002             其他用户具可写入权限
    S_IXOTH 00001             其他用户具可执行权限

    上述的文件类型在POSIX中定义了检查这些类型的宏定义:

    S_ISLNK (st_mode)    判断是否为符号连接
    S_ISREG (st_mode)    是否为一般文件
    S_ISDIR (st_mode)    是否为目录
    S_ISCHR (st_mode)    是否为字符装置文件
    S_ISBLK (s3e)        是否为先进先出
    S_ISSOCK (st_mode)   是否为socket

eg1:编写程序实现输出指定文件的大小、最后一次访问时间和最后一次修改时间

/*获取文件大小 最后一次访问时间 最后一次修改时间*/
#include<stdio.h>
#include<time.h>
#include <unistd.h>
#include<sys/stat.h>
int main(){
	struct stat buf;
	char a[100];
	struct tm *p1,*p2;
	printf("输入文件完整路径+文件名:");
	scanf("%s",a);
	stat(a,&buf);
	p1=localtime(&buf.st_atime);//获取当地时间 并按现在的时间日期来表示
	p2=localtime(&buf.st_mtime);//struct tm *p=localtime(&time_t); tm强大结构体 
	printf("文件名:%s\n",a);
	printf("大 小:%d\n",buf.st_size);
	printf("最后一次访问时间: %d年%d月%d日 %d:%d:%02d\n",1900+p1->tm_year,p1->tm_mon+1,p1->tm_mday,p1->tm_hour,p1->tm_min,p1->tm_sec);
	printf("最后一次修改时间: %d年%d月%d日 %d:%d:%02d\n",1900+p2->tm_year,p2->tm_mon+1,p2->tm_mday,p2->tm_hour,p2->tm_min,p2->tm_sec);
	return 0;
}

运行结果:

二、不带缓存的文件I/O操作

不带缓存的文件I/O操作用到的主要API函数
函数 作用
creat 创建文件
open 打开或创建文件
close 关闭文件
read 读文件
write 写文件
lseek 移动文件的读写位置
flock 锁定文件或解除锁定(用于文件加建议性锁)
fcntl 文件描述符操作(用于文件加强制性锁)

2.1文件的创建

所需头文件:#include<sys/types.h>
                      #include<sys/stat.h>
                      #include<fcntl.h>
函数功能:创建文件
函数原型:int creat(const char* pathname,mode_t mode);
函数传入值:建立文件的访问路径,用来设置新增文件的权限
                     参数mode见1.3linux文件权限
函数返回值:由内核返回一个最小可用的文件描述符,出错返回-1
 

eg1:编程实现在~/test/Io/目录下创建一个名为io.txt的文件,并将此文件的权限设置为所有者具有只读权限,最后显示此文件的信息。

/*c程序创建文件 并指定权限*/
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
int main(){
	int fd;
	fd=creat("/home/hanzhuan/test/IO/io.txt",S_IRUSR);
	system("ls /home/hanzhuan/test/IO/io.txt -l");
	return 0;
}

运行结果:

 

2.2 文件的打开和关闭

open函数说明:

所需头文件:#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);
函数传入值:建立文件的访问路径,用来设置新增文件的权限
                     建立文件的访问路径,指定访问文件的命令模式,用来设置新增文件的权限
函数返回值:由内核返回一个最小可用的文件描述符,出错返回-1

flag参数说明如下:
O_RDONLY:以只读模式打开
O_WRONLY:以写入模式打开
O_RDWR:以读写模式打开
O_APPEND:在文件尾写入数据
O_TRUNC:设置文件的长度0,并舍弃现存的数据
O_CREAT:建立文件,可用mode参数设置访问权限
O_EXCL:与O_CREAT一起使用,若所建立的文件已存在,则打开失败

close函数说明如下:
所需头文件:#include<unistd.h>
函数功能:关闭文件
函数原型:int close(int fd);
函数传入值:整型
函数返回值:文件顺利关闭返回0,发生错误返回-1
备注:当一个进程终止时,它所有已打开的文件都由内核自动关闭
         虽然如此,但:还是建议人工关闭文件,并检查返回值

eg:在/home/hanzhuan/test/IO目录下以可读写方式打开一个文件,若不存在创建此文件;若存在,清空后关闭

(原来目录下有io1.txt且有内容 无io2.txt)

/*打开文件*/
#include<stdio.h>
#include<stdlib.h>/*system*/
#include<fcntl.h>/*open*/
#include<unistd.h>/*close*/
int main(){
	int fd;
	if((fd=open("/home/hanzhuan/test/IO/io1.txt",O_CREAT|O_TRUNC|O_WRONLY,0600))<0){
		/*O_CREAT:b不存在建立文件 
		  O_TRUNC:设置文件的长度0,并舍弃现存的数据
		  O_WRONLY:以写入模式打开
		  0600:所有者rw权限
		  出错返回-1<0		  
		*/
		perror("打开文件出错!");
		exit(1);
	}else{
		printf("打开(创建)文件 io1.txt ,文件描述符为:%d\n",fd);
	}
	if(close(fd)<0){
		perror("关闭文件出错!");
		exit(1);
	}
	system("ls /home/hanzhuan/test/IO/io1.txt -l");
	return 0;
}

运行结果:

2.3 文件的读写操作

猜你喜欢

转载自blog.csdn.net/hza419763578/article/details/83994643
今日推荐