系统文件操作开发

1、系统文件读写

任务描述:

编写程序,读取linux系统文件"/etc/passwd"内容,并输出到屏幕上.同时在程序目录新建文件passwd,将"/etc/passwd"系统文件内容复制到新建的passwd中

main.c:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#define N 1000

int main(void)
{
    int fp1,fp2,num;
    char *file1,*file2;
    char buf[N];
    file1="/etc/passwd";
    file2="passwd";
    if(( fp1=open(file1,O_RDONLY))==-1){            
        printf("can't open %s\n",file1);
        return 1;
    }
    if((fp2=open(file2,O_CREAT|O_WRONLY))==-1){
        printf("can't create %s\n",file2);
        return -1;
    }
    while((num = read(fp1,buf,N))>0){
        printf("%s\n",buf);
        if(write(fp2,buf,num) == -1 ){
            printf("can't write to %s\n",file2);
            return -1;
        }
    }   

    close(fp1);close(fp2);
    return 0; 
}

 

2、文件内容统计操作

任务描述:

  • 给定系统文件filesystem.manifest(dpkg-query -W --showformat='${Package} ${Version}\n'>filesystem.manifest)
  • 目前文件每一行格式为"软件包名 版本号",要求输出每一行的格式为"软件包名"(去除版本号相关信息)到文件filesystem.manifest.name
  • 在第一步基础上,进一步去除换行符号,使整个文件的输出为一行(不同包名用空格分割),格式为"软件包1 软件包2 软件包3...",输出到文件filesystem.manifest.name.oneline
  • 目前每一行格式为"软件包名 版本号",找到文件中软件包名有"ubuntu"字样的软件包,并直接输出其个数(不能人工查找,需直接输出其个数)

相关知识:

①cut 命令可以从一个文本文件或者文本流中提取文本列。
  命令用法:
    cut -b list [-n] [file ...]
    cut -c list [file ...]
    cut -f list [-d delim][-s][file ...]
  上面的-b、-c、-f 分别表示字节、字符、字段(即 byte、character、field);
  list 表示-b、-c、-f 操作范围,-n 常常表示具体数字;
  file 表示的自然是要操作的文本文件的名称;
  delim(英文全写:delimiter)表示分隔符,默认情况下为 TAB;
  -s 表示不包括那些不含分隔符的行(这样有利于去掉注释和标题)
  上面三种方式中,表示从指定的范围中提取字节(-b)、或字符(-c)、或字段(-f)。

xargs 是一条 Unix 和类 Unix 操作系统的常用命令。它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题。

例如,下面的命令:
rm `find /path -type f`如果 path 目录下文件过多就会因为“参数列表过长”而报错无法执行。但改用 xargs 以后,问题即获解决。
find /path -type f -print0 | xargs -0 rm
本例中 xargs 将 find 产生的长串文件列表拆散成多个子串,然后对每个子串调用 rm。这样要比如下使用 find 命令效率高的多。
find /path -type f -exec rm '{}' \;
上面这条命令会对每个文件调用"rm"命令。当然使用新版的"find"也可以得到和"xargs"
命令同样的效果:
find /path -type f -exec rm '{}' +
xargs 的作用一般等同于大多数 Unix shell 中的反引号,但更加灵活易用,并可以正确处理输入中有空格等特殊字符的情况。对于经常产生大量输出的命令如 find、locate 和 grep 来
说非常有用。

#!/bin/bash

dpkg-query -W --showformat='${Package} ${Version}\n'>filesystem.manifest
cat filesystem.manifest|cut -d ' ' -f 1 >filesystem.manifest.name
cat filesystem.manifest.name|xargs >filesystem.manifest.name.oneline
cat filesystem.manifest|grep "ubuntu"|wc -l
#-d ' '表示以空格为字符 -f 1表示输出第一列
#xargs表示将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题

 

3、文件描述符获取

任务描述:

  • 打印输入设备,输出设备,标准错误输出设备的文件描述符
  • 任意打开一个存在文件a,打印其文件描述符
  • 不关闭文件a,定义新的文件描述符重新打开a,打印其文件描述符
  • 关闭文件a,定义新的文件描述符重新打开a,打印文件描述符

相关知识:

  任何打开的文件都将被分配一个唯一标识该打开文件的文件描述符,为一个大于等于 0的整数。系统启动后,默认打开的文件流有标准输入设备(STDIN)、标准输出设备(STDOUT)和标准错误输出设备(STDERR),其文件描述符分别为 0、1、2。以后打开的文件的文件描述符分配依次增加。使用 fileno()函数可以返回一个流对应的文件描述符。

main.c:

#include <stdio.h>

int main()
{
    FILE *fp1,*fp2,*fp3,*fp4;
    int fd;
    fd=fileno(stdin);
    printf("stdin is :%d\n",fd); fd=fileno(stdout);
    printf("stdout is :%d\n",fd); fd=fileno(stderr);
    printf("stderr is :%d\n",fd);
  printf("open file and open again before it closed\n");
  fp1=fopen("test.c", "r");
  fd=fileno(fp1);
    printf("main.c is %d\n", fd);
  fp2=fopen("test.c","r");
  fd=fileno(fp2);
    printf("main.c is %d\n",fd);
  fclose(fp1);fclose(fp2);

    printf("open file and open again after it closed\n");
    fp3=fopen("test.c","r");
    fd=fileno(fp3);
      printf("main.c is %d\n",fd);
    fclose(fp3);
    fp4=fopen("test.c","r");
    fd=fileno(fp4);
      printf("main.c is %d\n",fd);
    return 0;
}

 

4、检测文件读写权限

任务描述:

  • 检测文件当前读写权限,如果文件具有读权限,则打印可读信息,如果有写权限,则打印可写信息,否则返回错误信息
  • 用fcntl函数实现

相关知识:

fcntl 功能描述:根据文件描述词来操作文件的特性。
文件控制函数:fcntl -- file control
函数原型:
#include <fcntl.h>;
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
描述: fcntl()针对(文件)描述符提供控制.参数 fd 是被参数 cmd 操作(如下面的描述)的描述符。针对 cmd 的值,fcntl 能够接受第三个参数 int arg。
fcntl 函数有 5 种功能:
1.复制一个现有的描述符(cmd=F_DUPFD).
2.获得/设置文件描述符标记(cmd=F_GETFD 或 F_SETFD).
3.获得/设置文件状态标记(cmd=F_GETFL 或 F_SETFL).
4.获得/设置异步 I/O 所有权(cmd=F_GETOWN 或 F_SETOWN).5.获得/设置记录锁(cmd=F_GETLK,F_SETLK 或 F_SETLKW).

main.c:

#include<stdio.h>
#include<fcntl.h>

int main(void)
{ 
    FILE *fp;  
    int val,acc,a;
    if(( fp=fopen("test.c","r+")) == NULL){  
        printf("can't open the file\n");
        return 1;
    }
    a=fileno(fp);
    val=fcntl(a,F_GETFL,0);//获得文件状态标记
    acc=val&O_ACCMODE;//把不是关于r、w、x的文件状态标记屏蔽掉
    if (acc==O_RDONLY)
        printf("read only\n");
    if (acc==O_WRONLY)
        printf("write only\n");
    if (acc==O_RDWR)
        printf("read write\n");
    fclose(fp);
    return 0;
}

 

5、锁定/解锁文件

任务描述:

  • 用fcntl函数实现锁定文件test_lock的两个区域,锁定类型均为以文件开头为锁定的起始位置,区域1锁定为供读取用,起始偏移量为10,长度为20;区域2锁定为供写入用,起始偏移量为40,长度为10.
  • 当进程锁定文件指定区域时,输出"process locking file",停顿10秒钟,关闭文件描述符,输出"process closing file"
  • 使用flock数据结构,使用fcntl函数

相关知识:

  Linux 支持的文件锁技术主要包括劝告锁(advisory lock)和强制锁(mandatory lock)这两种。此外,Linux 中还引入了两种强制锁的变种形式:共享模式强制锁(share-mode mandatory lock)和租借锁(lease)。
  在 Linux 中,不论进程是在使用劝告锁还是强制锁,它都可以同时使用共享锁和排他锁(又称为读锁和写锁)。多个共享锁之间不会相互干扰,多个进程在同一时刻可以对同一个文件加共享锁。但是,如果一个进程对该文件加了排他锁,那么其他进程则无权再对该文件加共享锁或者排他锁,直到该排他锁被释放。所以,对于同一个文件来说,它可以同时拥有很多读者,但是在某一特定时刻,它只能拥有一个写者

  flock 函数用于实现对文件的锁定和解锁操作。此函数只能锁定整个文件,不能锁定某个区域。要锁定某个区域,则需要使用 fcntl()函数。

  int fcntl(int fd, int cmd, struct flock *lock);参数lock指针为flock 结构指针,定义如下:

  struct flock{
    short int l_type;
    short int l_whence;
    off_t l_start;
    off_t l_len;
    pid_t l_pid;
  };
  l_type 有三种状态:
    F_RDLCK 建立一个供读取用的锁定
    F_WRLCK 建立一个供写入用的锁定
    F_UNLCK 删除之前建立的锁定
  l_whence 也有三种方式:
    SEEK_SET 以文件开头为锁定的起始位置。
    SEEK_CUR 以目前文件读写位置为锁定的起始位置
    SEEK_END 以文件结尾为锁定的起始位置。
  l_start 表示相对l_whence位置的偏移量,两者一起确定锁定区域的开始位置。
  l_len表示锁定区域的长度,若果为0表示从起点(由l_whence和 l_start决定的开始位置)开始直到最大可能偏移量为止。即不管在后面增加多少数据都在锁的范围内。

  main.c:

#include<stdio.h>
#include<fcntl.h>

int main(void)
{
    int re,fd;
    fd=open("test_lock",O_RDWR|O_CREAT,0644);
    struct flock z1;
    z1.l_type=F_RDLCK;//建立一个供读取用的锁定
    z1.l_whence=SEEK_SET;//以文件开头为锁定的起始位置
    z1.l_start=10;
    z1.l_len=20;
    printf("Process %d locking file\n",getpid());
    if((re=fcntl(fd,F_SETLK,&z1))==-1){
        printf("failed to lock z1");
    }
    struct flock z2;
    z2.l_type=F_WRLCK;//建立一个供写入用的锁定
    z2.l_whence=SEEK_SET;//以文件开头为锁定的起始位置
    z2.l_start=40;
    z2.l_len=10;
    if((re=fcntl(fd,F_SETLK,&z2))==-1){
        printf("failed to lock z2");
    }
    sleep( 10);
    printf("Process %d closing file\n",getpid());
    close(fd);
    return 0;
}

 

6、使用 chmod()函数修改文件权限

任务描述:

  • 首先使用touch命令新建3个临时文件:test1,test2,test3
  • 查看最原始文件权限情况(是否为拥有者可读写,所有其他人可读)
  • 设置test1为拥有者可读写,同组用户可读写,其他人可读;test2为拥有者可读写,同组用户可读写可执行,其他人可读;test3为拥有者可读写,同组用户可写不可读、其他用户可写不可读
  • 采用stat数据结,chmod函数
  • 输出修改权限前和修改权限后的文件属性

相关知识:

文件权限知识:

  Linux 系统中的每个文件和目录都有访问许可权限,用它来确定谁可以通过何种方式对文件和目录进行访问和操作。
  文件或目录的访问权限分为只读,只写和可执行三种。以文件为例,只读权限表示只允许读其内容,而禁止对其做任何的更改操作。可执行权限表示允许将该文件作为一个程序执行。文件被创建时,文件所有者自动拥有对该文件的读、写和可执行权限,以便于对文件的阅读和修改。用户也可根据需要把访问权限设置为需要的任何组合。有三种不同类型的用户可对文件或目录进行访问:文件所有者,同组用户、其他用户。
  所有者一般是文件的创建者。所有者可以允许同组用户有权访问文件,还可以将文件的访问权限赋予系统中的其他用户。在这种情况下,系统中每一位用户都能访问该用户拥有的文件或目录。
  每一文件或目录的访问权限都有三组,每组用三位表示,分别为文件属主的读、写和执行权限;与属主同组的用户的读、写和执行权限;系统中其他用户的读、写和执行权限。当用 ls -l 命令显示文件或目录的详细信息时,最左边的一列为文件的访问权限。

main.c:

#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>

int main(void)
{
    chmod("test01",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
    chmod("test02",S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH);
    chmod("test03",S_IRUSR|S_IWUSR|S_IWGRP|S_IWOTH);
    return 0;
}

 

posted @ 2015-08-25 19:44  没错我就是菊花侠  阅读(511)  评论(0编辑  收藏  举报