Linux 基于文件描述符的文件操作 open,close,read,write,lseek,stat,fstat,ftruncate

文件操作详解
本文深入解析文件操作的基础知识,包括文件的打开、创建、关闭、读写、改变大小、定位及获取信息。通过代码示例详细介绍了open、creat、close、read、write、ftruncate、lseek、stat和fstat函数的使用方法。

打开、创建和关闭文件

#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);//文件名  打开方式  权限 
int creat(const char *pathname, mode_t mode);  //文件名  权限   
creat 函数等价于open(pathname,O_CREAT|O_TRUNC|O_WRONLY,mode); 

open()函数出错时返回-1,相关参数如下:
flags 和 mode 都是一组掩码的合成值,flags 表示打开或创建的方式,mode 表示文件的访问权限。 mode参数只有在建立新文件时才会生效(flags中包含O_CREAT),表示新建文件的权限,但最终所建文件的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。
flags 的可选项有

O_RDONLY     以只读的方式打开 
O_WRONLY     以只写的方式打开 
O_RDWR       以读写的方式打开 
O_CREAT      如果文件不存在,则创建文件 
O_EXCL       仅与 O_CREAT 连用,如果文件已存在,则强制 open 失败 
O_TRUNC      如果文件存在,将文件的长度截至 0 
O_APPEND     已追加的方式打开文件, 每次调用 write 时,文件指针自动先移到文件尾,用于多进程写一个文件的情况。 
O_NONBLOCK   非阻塞方式打开,无论有无数据读取或等待,都会立即返回进程之中。 
O_NODELAY    非阻塞方式打开 
O_SYNC       同步打开文件,只有在数据被真正写入物理设备设备后才返回 

mode的可选项有:

mode 的可选项有: 
S_IRWXU 00700 权限,代表该文件所有者具有可读、可写及可执行的权限。 
S_IRUSR 00400 权限,代表该文件所有者具有可读取的权限。 
S_IWUSR 00200 权限,代表该文件所有者具有可写入的权限。 
S_IXUSR 00100 权限,代表该文件所有者具有可执行的权限。 
 
S_IRWXG 00070 权限,代表该文件用户组具有可读、可写及可执行的权限。 
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。 
S_IWGRP 00020 权限,代表该文件用户组具有可写入的权限。 
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。 
 
S_IRWXO 00007 权限,代表其他用户具有可读、可写及可执行的权限。 
S_IROTH 00004 权限,代表其他用户具有可读的权限 
S_IWOTH 00002 权限,代表其他用户具有可写入的权限。 
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。

close 用于文件的关闭:

int close(int fd);    //fd 表示文件描述符,是先前由 open 或 creat 创建文件时的返回值。 

文件使用完毕后,应该调用 close 关闭它,一旦调用 close,则该进程对文件所加的锁全都被释放,并且使文件的打开引用计数减 1,只有文件的打开引用计数变为 0 以后,文件才会被真正的关闭。

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd;
    fd = open(argv[1],O_RDWR);
    ERROR_CHECK(fd, -1, "open");
    printf("fd=%d\n",fd);
    close(fd);
    return 0;
}
#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd;
    fd = open(argv[1],O_RDWR|O_CREAT,0666);
    ERROR_CHECK(fd, -1, "open");
    printf("fd=%d\n",fd);
    return 0;
}

读写文件

#include <unistd.h> 
ssize_t read(int fd, void *buf, size_t count);    //文件描述符  缓冲区  长度 
ssize_t write(int fd, const void *buf, size_t count); 

fd:文件描述符 buf:写入的字符串,传入指向字符串的指针 count:写入的字节数
对于read函数同理,buf为读出的缓冲区,count为读出的字节数
read 和 write 函数,出错返回-1,读取完了之后,返回 0, 其他情况返回读写的个数

read.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd;
    fd = open(argv[1],O_RDWR);
    ERROR_CHECK(fd, -1, "open");
    printf("fd=%d\n",fd);
    char buf[128]={0};
    int ret = read(fd,buf,sizeof(buf));
    printf("buf=%s,ret=%d\n",buf,ret);
    close(fd);
    return 0;
}

write.c

#include <func.h>

int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd;
    fd = open(argv[1],O_RDWR);
    ERROR_CHECK(fd, -1, "open");
    printf("fd=%d\n",fd);
    int ret = write(fd,&fd,sizeof(int));
    printf("write count = %d\n",ret);
    close(fd);
    return 0;
}

案例:将 aaa.txt 中的内容复制到 bbb.txt 中,其中 bbb.txt 起初不存在

#include <stdio.h> 
#include <stdlib.h>       //包含 exit 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <errno.h>              //用 perror 输出错误 
#include <unistd.h> 
#define FILENAME1 "./aaa.txt"     //用宏定义文件的路径
#define FILENAME2 "./bbb.txt"
int main() 
{ 
    char buf[512] = {0}; 
    int fo1 = open(FILENAME1, O_RDONLY);  //fo1,fo2 都是文件描述词 
	int fo2 = creat(FILENAME2, 0755);     //创建文件 
	//int fo2 = open(FILENAME2, O_WRONLY | O_CREAT); 
    if( (-1 == fo1) || (-1 == fo2) ) 
	{ 
     	perror("open failed!\n"); 
		//用于输出错误信息.类似于:fputs(”open failed\n”,stderr); 
      	exit(-1); 
    } 
    int fr = 0; 
	while( (fr = read(fo1, buf, sizeof(buf))) > 0 ) 
	//如果 read 读取成功,返回的是长度,否则,返回-1 
    { 
        int fw = write(fo2, buf, fr); 
     	if( -1 == fw ) 
        { 
            perror("write failed!"); 
      		exit(-1); 
        } 
    } 
    close(fo1); 
    close(fo2); 
} 

改变文件大小

#include <unistd.h> 
int ftruncate(int fd, off_t length); 

函数 ftruncate 会将参数 fd 指定的文件大小改为参数 length 指定的大小。参数 fd 为已打开的文
件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数 length 大,则超过的
部分会被删去。
返回值 执行成功则返回 0,失败返回-1。

#include <func.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
    ARGS_CHECK(argc, 2);
    int fd;
    fd = open(argv[1],O_RDWR);
    ERROR_CHECK(fd, -1, "open");
    printf("fd=%d\n",fd);
    int ret = ftruncate(fd,50);
    ERROR_CHECK(ret,-1,"ftruncate");
    close(fd);
    return 0;
}
int main() 
{ 
    int fd = open("a.txt", O_WRONLY); 
    ftruncate(fd, 1000); 
    close(fd); 
    return 0; 
} 

文件定位

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

函数 lseek 将文件指针设定到相对于 whence,偏移值为 offset 的位置
whence 可以是下面三个常量的一个

SEEK_SET 从文件头开始计算 
SEEK_CUR 从当前指针开始计算 
SEEK_END 从文件尾开始计算 

利用该函数可以实现文件空洞(对一个新建的空文件,可以定位到偏移文件开头 1024 个字节的地
方,在写入一个字符,则相当于给该文件分配了 1025 个字节的空间,形成文件空洞)通常用于多
进程间通信的时候的共享内存。

int main() 
{ 
    int fd = open("c.txt", O_WRONLY | O_CREAT); 
    lseek(fd, 1024, SEEK_SET); 
    write(fd, "a", 1); 
    close(fd); 
    return 0; 
} 

获取文件信息

可以通过 fstat 和 stat 函数获取文件信息,调用完毕后,文件信息被填充到结构体 struct stat变量中,函数原型为:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
int stat(const char *file_name, struct stat *buf);    //文件名  stat 结构体指针 
int fstat(int fd, struct stat *buf);      //文件描述符   stat 结构体指针

结构体 stat 的定义为:

struct stat { 
           dev_t         st_dev;      /*如果是设备,返回设备表述符,否则为 0*/ 
           ino_t         st_ino;      /* i 节点号 */ 
           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_size;     /* 文件大小,字节表示 */ 
           blksize_t     st_blksize;  /* 块大小*/ 
           blkcnt_t      st_blocks;   /* 块数 */ 
           time_t        st_atime;    /* 最后访问时间*/ 
           time_t        st_mtime;    /* 最后修改时间*/ 
           time_t        st_ctime;    /* 最后权限修改时间 */ 
    };

对于结构体的成员 st_mode,有一组宏可以进行文件类型的判断:

S_ISLNK(mode)  判断是否是符号链接 
S_ISREG(mode)  判断是否是普通文件 
S_ISDIR(mode)  判断是否是目录 
S_ISCHR(mode)  判断是否是字符型设备 
S_ISBLK(mode)  判断是否是块设备 
S_ISFIFO(mode) 判断是否是命名管道 
S_ISSOCK(mode) 判断是否是套接字 
#include<sys/stat.h> 
#include<unistd.h> 
int main() 
{ 
	struct stat buf; 
	stat (/etc/passwd”,&buf); 
	printf(/etc/passwd file size = %d \n”,buf.st_size);//st_size 可以得到文件大小 
	return 0;
} 
//如果用 fstat 函数实现,如下:  
int fd = open (/etc/passwd”,O_RDONLY);  //先获得文件描述符
fstat(fd, &buf);  
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <time.h> 
 
int main() 
{ 
    int fd = open("/home/wangxiao/0926/a.txt", O_RDONLY); 
    if(fd == -1) 
    { 
        perror("open error"); 
        exit(-1);
        } 
  
    struct stat buf; 
    int iRet = fstat(fd, &buf); 
    if(iRet == -1) 
    { 
        perror("fstat error"); 
        exit(-1); 
    } 
  
    if(S_ISREG(buf.st_mode)) 
    { 
        printf("regular file!\n"); 
    } 
    if(S_ISDIR(buf.st_mode)) 
    { 
        printf("directory!\n"); 
    } 
    if(S_ISLNK(buf.st_mode)) 
    { 
        printf("link file!\n"); 
	} 
	printf("the size of file is : %d\n", buf.st_size); 
 
	time_t tt = buf.st_atime; 
	struct tm *pT = gmtime(&tt); 
	printf("%4d-%02d-%02d   %02d:%02d:%02d\n", (1900+pT->tm_year), (1+pT->tm_mon), 
pT->tm_mday, (8+pT->tm_hour), pT->tm_min, pT->tm_sec); 
	printf("the last access time is : %d\n", buf.st_atime); 
	close(fd); 
	return 0; 
} 
os.access(path, mode) 检验权限模式 2 os.chdir(path) 改变当前工作目录 3 os.chflags(path, flags) 设置路径的标记为数字标记。 4 os.chmod(path, mode) 更改权限 5 os.chown(path, uid, gid) 更改文件所有者 6 os.chroot(path) 改变当前进程的根目录 7 os.close(fd) 关闭文件描述符 fd 8 os.closerange(fd_low, fd_high) 关闭所有文件描述符,从 fd_low (包含) 到 fd_high (不包含), 错误会忽略 9 os.dup(fd) 复制文件描述符 fd 10 os.dup2(fd, fd2) 将一个文件描述符 fd 复制到另一个 fd2 11 os.fchdir(fd) 通过文件描述符改变当前工作目录 12 os.fchmod(fd, mode) 改变一个文件的访问权限,该文件由参数fd指定,参数mode是Unix下的文件访问权限。 13 os.fchown(fd, uid, gid) 修改一个文件的所有权,这个函数修改一个文件的用户ID和用户组ID,该文件由文件描述符fd指定。 14 os.fdatasync(fd) 强制将文件写入磁盘,该文件由文件描述符fd指定,但是不强制更新文件的状态信息。 15 os.fdopen(fd[, mode[, bufsize]]) 通过文件描述符 fd 创建一个文件对象,并返回这个文件对象 16 os.fpathconf(fd, name) 返回一个打开的文件的系统配置信息。name为检索的系统配置的值,它也许是一个定义系统值的字符串,这些名字在很多标准中指定(POSIX.1, Unix 95, Unix 98, 和其它)。 17 os.fstat(fd) 返回文件描述符fd的状态,像stat()。 18 os.fstatvfs(fd) 返回包含文件描述符fd的文件的文件系统的信息,Python 3.3 相等于 statvfs()。 19 os.fsync(fd) 强制将文件描述符为fd的文件写入硬盘。 20 os.ftruncate(fd, length) 裁剪文件描述符fd对应的文件, 所以它最大不能超过文件大小。 21 os.getcwd() 返回当前工作目录 22 os.getcwdb() 返回一个当前工作目录的Unicode对象 23 os.isatty(fd) 如果文件描述符fd是打开的,同时与tty(-like)设备相连,则返回true, 否则False。 24 os.lchflags(path, flags) 设置路径的标记为数字标记,类似 chflags(),但是没有软链接 25 os.lchmod(path, mode) 修改连接文件权限 26 os.lchown(path, uid, gid) 更改文件所有者,类似 chown,但是不追踪链接。 27 os.link(src, dst) 创建硬链接,名为参数 dst,指向参数 src 28 os.listdir(path) 返回path指定的文件夹包含的文件或文件夹的名字的列表。 29 os.lseek(fd, pos, how) 设置文件描述符 fd当前位置为pos, how方式修改: SEEK_SET 或者 0 设置从文件开始的计算的pos; SEEK_CUR或者 1 则从当前位置计算; os.SEEK_END或者2则从文件尾部开始. 在unix,Windows中有效 30 os.lstat(path) 像stat(),但是没有软链接 31 os.major(device) 从原始的设备号中提取设备major号码 (使用stat中的st_dev或者st_rdev field)。 32 os.makedev(major, minor) 以major和minor设备号组成一个原始设备号 33 os.makedirs(path[, mode]) 递归文件夹创建函数。像mkdir(), 但创建的所有intermediate-level文件夹需要包含子文件夹。 34 os.minor(device) 从原始的设备号中提取设备minor号码 (使用stat中的st_dev或者st_rdev field )。 35 os.mkdir(path[, mode]) 以数字mode的mode创建一个名为path的文件夹.默认的 mode 是 0777 (八进制)。 36 os.mkfifo(path[, mode]) 创建命名管道,mode 为数字,默认为 0666 (八进制) 37 os.mknod(filename[, mode=0600, device]) 创建一个名为filename文件系统节点(文件,设备特别文件或者命名pipe)。 38 os.open(file, flags[, mode]) 打开一个文件,并且设置需要的打开选项,mode参数是可选的 39 os.openpty() 打开一个新的伪终端对。返回 pty 和 tty的文件描述符。 40 os.pathconf(path, name) 返回相关文件的系统配置信息。 41 os.pipe() 创建一个管道. 返回一对文件描述符(r, w) 分别为读和写 42 os.popen(command[, mode[, bufsize]]) 从一个 command 打开一个管道 43 os.read(fd, n) 从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串。 44 os.readlink(path) 返回软链接所指向的文件 45 os.remove(path) 删除路径为path的文件。如果path 是一个文件夹,将抛出OSError; 查看下面的rmdir()删除一个 directory。 46 os.removedirs(path) 递归删除目录。 47 os.rename(src, dst) 重命名文件或目录,从 src 到 dst 48 os.renames(old, new) 递归地对目录进行更名,也可以对文件进行更名。 49 os.rmdir(path) 删除path指定的空目录,如果目录非空,则抛出一个OSError异常。 50 os.stat(path) 获取path指定的路径的信息,功能等同于C API中的stat()系统调用。 51 os.stat_float_times([newvalue]) 决定stat_result是否以float对象显示时间戳 52 os.statvfs(path) 获取指定路径的文件系统统计信息 53 os.symlink(src, dst) 创建一个软链接 54 os.tcgetpgrp(fd) 返回与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组 55 os.tcsetpgrp(fd, pg) 设置与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组为pg。 56 os.tempnam([dir[, prefix]]) Python3 中已删除。返回唯一的路径名用于创建临时文件。 57 os.tmpfile() Python3 中已删除。返回一个打开的模式为(w+b)的文件对象 .这文件对象没有文件夹入口,没有文件描述符,将会自动删除。 58 os.tmpnam() Python3 中已删除。为创建一个临时文件返回一个唯一的路径 59 os.ttyname(fd) 返回一个字符串,它表示与文件描述符fd 关联的终端设备。如果fd 没有与终端设备关联,则引发一个异常。 60 os.unlink(path) 删除文件路径 61 os.utime(path, times) 返回指定的path文件的访问和修改的时间。 62 os.walk(top[, topdown=True[, onerror=None[, followlinks=False]]]) 输出在文件夹中的文件名通过在树中游走,向上或者向下。 63 os.write(fd, str) 写入字符串到文件描述符 fd中. 返回实际写入的字符串长度 64 os.path 模块 获取文件的属性信息。 65 os.pardir() 获取当前目录的父目录,以字符串形式显示目录名。 66 os.replace() 重命名文件或目录。 帮我整理为md格式,相同类别分为二级标题,例如:文件信息类、路径类,路径下又分为:判断、创建等类别,我要你以md文件形式返回
最新发布
07-30
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值