系统文件操作函数

系统级文件操作

执行程序时会自动打开三个文件:标准输入,标准输出和标准错误输出。在C标准库中分别用FILE *stdin,stdout,stderr表示。这三个文件的描述符分别是0,1和2,保存在FILE结构体中,头文件unistd.h定义了三个文件描述符。

#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

1. unlink

#include <unistd.h>;

int unlink(const char *pathname);

unlink()删除一个name从文件系统,假如那个name是文件的最后链接且没有进程打开它,该文件将被删除。

unlink()  deletes  a name from the filesystem.  If that name was the last link to a file and no processes have the file open the file is deleted and the space it was using is made available  for  reuse.
If  the  name  was  the last link to a file but any processes still have the file open the file will remain in existence until the last file descriptor referring to it is closed.
If the name referred to a symbolic link the link is removed.
If the name referred to a socket, fifo or device the name for it is removed but processes which have the object open may continue to use it.

2. open&close

#include <fcntl.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/stat.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

int close(int fd);

pathname确省为当前路径下面。

flags:一个值或几个值的组合。

O_RDONLY:以只读的方式打开文件.

O_WRONLY:以只写的方式打开文件.

O_RDWR:以读写的方式打开文件.

O_APPEND:以追加的方式打开文件.

O_CREAT:假如文件不存在,创建一个文件。文件存在,不截短文件,要截短文件需指定O_TRUNC。

O_EXCL:如果使用了 O_CREAT 而且文件已经存在,就会发生一个错误。此外,若O_CREAT与O_EXCL同时设置,并且将要打开的文件为符号连接,则将导致打开文件失败。

O_NOBLOCK:以非阻塞的方式打开一个文件.

O_TRUNC:如果文件已经存在,则删除文件的内容.

O_LARGEFILE:大文件(>2G),2^31~=2G(采用64位偏移)。若不指定,文件大小达到2G时,出错退出。

前面三个标志只能使用任意的一个。如果使用了 O_CREATE 标志,那么我们要使用 open 的第二种形式。还要指定 mode 标志,用来表示文件的访问权限.mode 可以是以下情况的组合.


S_IRUSR 用户可以读 S_IWUSR 用户可以写 S_IXUSR 用户可以执行 S_IRWXU 用户可以读写执行


S_IRGRP 组可以读 S_IWGRP 组可以写 S_IXGRP 组可以执行 S_IRWXG 组可以读写执行


S_IROTH 其他人可以读 S_IWOTH 其他人可以写 S_IXOTH 其他人可以执行 S_IRWXO 其他人可以读写执行


S_ISUID 设置用户执行 ID S_ISGID 设置组的执行 ID (s)


我们也可以用数字(八进制0)来代表各个位的标志.Linux 总共用 5 个数字来表示文件的各种权限. 00000.第一位表示设置用户 ID.第二位表示设置组 ID,第三位表示用户自己的权限位,第四位表示组的权限,最后一位表示其他人的权限.

每个数字可以取 1(执行权限),2(写权限),4(读权限),0(什么也没有)或者是这几个值的和。

比如我们要创建一个用户读写执行,组没有权限,其他人读执行的文件.设置用户 ID 位那么 我们可以使用的模式是--1(设置用户 ID)0(组没有设置)7(1+2+4)0(没有权限,使用缺省) 5(1+4)即 10705:

open("temp",O_CREAT,10705);

同时注意:文件的最终权限,需要与umask相与。

The letters rwxXst select file mode bits for the affected users: read (r), write  (w),  execute  (or search  for  directories) (x),

execute/search only if the file is a directory or already has execute permission for some user (X),

set user or group ID on execution (s),  restricted  deletion  flag  or sticky bit (t).

注:文件即使不关闭,程序执行完后,也会回收系统资源,称为隐式回收系统资源。

3. read&write

#include <unistd.h>;

ssize_t read(int fd, void *buffer,size_t count);
ssize_t write(int fd, const void *buffer,size_t count);

返回读写的字节数。

注:read读普通文件,读到文件尾时返回0。 write写多个字节时,要么出错,要么返回多个字节,不会返回0。两函数都可能由于信号中断而读取到少量数据。

读写常规文件,read/write都不会阻塞;设备文件时才阻塞。

示例,复制文件

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

#define BUF_SIZE  1024

int main(int argc, char **argv) {
int ret;
int infd, outfd;
int bytes_read, bytes_write, bytes_left;
char buf[BUF_SIZE];
char *ptr;
if(argc != 3){
    printf("Usage: %s fromfile tofile\r\n", argv[0]);
    exit(1);
}
outfd = open(argv[1], O_RDONLY);
if(outfd < 0){
    perror("open error");
    exit(1);
}

infd = open(argv[2], O_CREAT|O_RDWR , S_IRUSR | S_IWUSR);   
if(infd < 0){
    perror("open error");
    exit(1);
}

// read return 0, then file has finished.

while(bytes_read = read(outfd, buf, BUF_SIZE)){
    if(bytes_read == -1){
        if(errno == EINTR){ // return 0 because of SIGINT, read again   
            continue;
        } else {
            perror("read error");
            exit(1);
        }
    } else if(bytes_read > 0){
        ptr = buf;
        while(bytes_write = write(infd, ptr, bytes_read)){
            if(bytes_write == -1){ 
                if(errno == EINTR){
                    continue;
                } else {
                    perror("write error");
                    exit(1);
                }
            } else if(bytes_write < bytes_read){
                bytes_read -= bytes_write;  
                ptr += bytes_write;
                continue;
            } else if(bytes_write == bytes_read){
                break;
            } //for regular file, can't return 0;
        }           
    }
}

printf("file copy over.\n");
close(outfd);
close(infd);
return 0;
}

4. fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ...);

F_SETFL改写文件打开方式。

F_GETFL获取文件打开方式。

F_SETFL需第三参数,参数为文件打开标志,成功0,失败-1。

F_GETFL不需要第三参数,成功:文件打开标志,失败-1。

    flags = fcntl(fd, F_GETFL);
    flags |= O_NONBLOCK;
    fcntl(fd, F_SETFL, flags);

5. lseek

#include <sys/type.h>
off_t lseek(int fd, off_t offset, int whence);

设备文件是不可以设置偏移量的。如果不支持lseek,则lseek返回-1. 成功返回当前偏移量。 off_t =>int 从0计数偏移量。

whence:SEEK_SET, SEEK_CUR, SEEK_END

注:不可越界开头,可越界文件未。 可用于求当前偏移量,文件长度。 偏移量允许超过文件末尾,这种情况下,对该文件的下一次写操作将延长文件,中间空洞的地方读出来都是0。

6. truncate

扩展文件长度

    #include <sys/types.h>
    int truncate(const char *path, off_t length);
    int ftruncate(int fd, off_t length);

=>truncate a file to a specified length. 将文件改为指定长度,可清空文件(length = 0)。

7. access

int access(cosnt char *pathname, int mode);

mode: R_OK | W_OK | X_OK 或 F_OK测试文件或路径存在性。

F_OK tests for the existence of the file. R_OK, W_OK, and X_OK test whether the file exists and grants read, write, and execute permissions, respectively.

8. stat

#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf);
int fstat(int fds, struct stat *buf);
struct stat {
dev_t st_dev; /* 设备 */
ino_t st_ino; /* 节点 */
mode_t st_mode; /* 模式 */
nlink_t st_nlink; /* 硬连接 */
uid_t st_uid; /* 用户 ID */
gid_t st_gid; /* 组 ID */
dev_t st_rdev; /* 设备类型 */
off_t st_off; /* 文件字节数 */
unsigned long st_blksize; /* 块大小 */
unsigned long st_blocks; /* 块数 */
time_t st_atime; /* 最后一次访问时间 */
time_t st_mtime; /* 最后一次修改时间 */
time_t st_ctime; /* 最后一次改变时间(指属性) */

};

stat用来判断没有打开的文件,而fstat用来判断打开的文件。使用最多的属性是st_mode,用下面的宏判断:

S_ISLNK(st_mode):是否是一个连接;

S_ISREG(st_mode):是否是一个常规文件;

S_ISDIR(st_mode):是否是一个目录;

S_ISCHR(st_mode):是否是一个字符设备;

S_ISBLK(st_mode):是否是一个块文件;

S_ISFIFO(st_mode):是否是FIFO文件;

S_ISSOCK(st_mode):是否是SOCKET文件。

注:stat也用来判断文件是否存在。

static int create_open_file(int * fd,char * name)
{
    int err;
    struct stat file_status;
    if(stat(name, &file_status) < 0)//文件不存在    
    {        
        *fd = open(name, O_WRONLY | O_CREAT,0755);    
        if(*fd < 0)            
        {            
            return -1;        
        }        
    }    
    else    
    {        
        *fd = open(name, O_WRONLY|O_APPEND ,0755);    
        if(*fd < 0)        
        {            
            return -1;        
        }    
    }
        
    if(lseek(*fd,0, SEEK_END) < 0)//定位到文件尾端    
    {    
        close(*fd);        
        return -1;
    }    
    return 0;    
}     

9. 目录操作

char *getcwd(char *buffer, size_t size);
int mkdir(const char *path, mode_t mode);
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dir);
void rewinddir(DIR *dir);
void seekdir(DIR *dir, off_t off);
int closedir(DIR *dir);
/*
 * 在path目录下查找包含filter字符串的文件名,保存到result中
 */
bool findFile(const char* path, char *filter, char *result, int size)
{
    struct dirent *ent = NULL;
    DIR *dir = opendir(path);
    if(dir == NULL){
        printf("Open directory %s error!\n", path);
        return false;
    }

    while((ent = readdir(dir))!= NULL){
        if(strstr(ent->d_name, filter)){
            strncpy(result, ent->d_name, size);
            return true;
        }
    }

    return false;
}
递归创建目录
int checkVideoPath(char *path)
{
        int i = 0, ret = 0;
        char cbuf[128] = {0}, *pend = NULL;

        for(;i <5; i++){
                if(access(path, F_OK) == 0){
                        return 0;
                }
                ret = mkdir(path, 00777);
                if((ret < 0) && (errno == ENOENT)){
                        strncpy(cbuf, path, strlen(path));
                        if(cbuf[strlen(cbuf)-1] = '/')
                                cbuf[strlen(cbuf)-1] = 0;
                        pend = strrchr(cbuf, '/');
                        if(pend == NULL){
                                printf("Prefix is not directory: %s\n", cbuf);
                                return -1;
                        }
                        *pend = 0;
                        ret = checkVideoPath(cbuf);
                        if(ret < 0){
                                break;
                        }
                }
        }

        printf("mkdir path %s error(%d): %s\n", path, errno, strerror(errno));
        return -1;
}

10. 注意

vi编译器在文件尾加“\n",当文件有内容时。

open文件时,文件已缓冲到内存中,内核内存缓冲4K~8K(最小)。 库函数有缓冲区。 库函数读写时间<系统调用读写时间。

strings示例

打印文件中可打印字符,类似strings,超过拷贝区后有两种实现方案:拷贝检测到的打印字符复制到缓冲区;倒退文件当前偏移量。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

#define     BUF_SIZE 128    

int main(int argc, char **argv)
{
    if(argc < 3){ 
        printf("Usage: %s filename num\n", argv[0]);
        exit(1);
    }   

    int ret = 0;
    int fd = 0;
    char buf[BUF_SIZE] = {0};
    int num = 0;
    int i = 0, j = 0, cs_num = 0;
    int able_p = atoi(argv[2]); 
    int flag = 0;
    off_t buf_of = 0, tmp_of = 0, off = 0;

    if(able_p <= 2){ 
        able_p = 2;
    }   
    ret = access(argv[1], F_OK);
    if(ret != 0){
        printf("%s doesn't exist or have permission.\n", argv[1]);
        exit(1);
    }

    fd = open(argv[1], O_RDONLY);
    if(fd < 0){
        perror("open");
        exit(1);
    }

    buf_of = 0;
    while((num = read(fd, buf + buf_of, sizeof(buf) - buf_of)) > 0){
        tmp_of = buf_of;
        buf_of = 0;
        for(i = tmp_of; i < num+tmp_of; i++){
            if( (buf[i]>= ' ') && (buf[i] <= '~')){
                if(flag == 1){
                    putchar(buf[i]);
                    continue;
                } else {
                    cs_num++;
                }
            } else {
                if(flag == 1){
                    putchar('\n');
                    flag = 0;
                }
                cs_num = 0;
            }

            if(cs_num >= able_p){
                for(j = 1; j <= cs_num; j++){
                    putchar(buf[i-cs_num + j]);
                }
                flag = 1;
                cs_num = 0;
                buf_of = 0;

            } else if(i == num - 1){
//#if 0
                    off = lseek(fd, 0, SEEK_CUR);
                    if(off == (off_t)-1){
                        perror("lseek");
                        exit(1);
                    }
                    off = lseek(fd, off-cs_num, SEEK_SET);
                    if(off == (off_t)-1){
                        perror("lseek");
                        exit(1);
                    }
                    buf_of = 0;
                    cs_num = 0;
//#endif 
#if 0
                    for(j = 1; j <= cs_num; j++){
                        buf[j-1]=buf[i-cs_num+j];
                //      printf("[[[0x%x]]]",(char)buf[j-1]);
                    }
                    buf_of = cs_num;
#endif

            }
        }
    }

    close(fd);
    return 0;
}

 

posted @ 2015-12-10 21:31  yuxi_o  阅读(412)  评论(0编辑  收藏  举报