Linux 文件编程
来源:互联网 发布:mac相册照片怎么导出 编辑:程序博客网 时间:2024/05/29 19:00
Linux 系统的文件系统是Linux 内核非常核心的组成部件,它不仅将硬盘抽象成文件系统,还将所有的设备都抽象成文件,让用户在操作设备时仿佛就是在操作一个文件。但是这里讨论的仍然是传统的文件系统操作。当然我们所做都是在应用层的工作,因此基本上都是和系统调用或者函数库打交道。函数库编程放在下一篇文章,这里讨论系统调用的方法进行文件编程。所谓文件编程无非就是写程序创建文件、打开文件、关闭文件、写入文件、读出数据、重定位读写位置等等。因此我们的目标就很明确了:学习函数的使用方法,然后使用函数对文件进行操作。学习函数的使用方法无非要关注函数的原型,了解函数的返回值、参数、功能、以及所用到的头文件。要了解这些信息,最好的方法就是在Linux 系统中通过man 工具查询到函数的信息。当然在此之前肯定要了解相关的背景知识,这些知识来源于经典书籍,这里笔者使用的是APUE。这本书里介绍了相关的背景知识,甚至函数的说明都列举出来了,可以说是一本非常好的编程书籍。废话不多说,直接进入学习的阶段。
一、背景知识介绍
APUE的第三章讲的就是系统调用文件编程的知识。翻开目录,可以看到它也是先介绍了相关的背景知识:文件描述符,然后进入函数学习的阶段。可见笔者的学习方法是正确的。
文件描述符:笔者是这样理解的:内核为了记录进程所打开的文件,必须有一种机制能让它了解到该信息。最直接的方法就是给进程建立一个”打开文件表“,进程所打开的每个文件都占据一个表项,这样内核就能够记录下进程所打开的每个文件。事实上这个表的每一项就是文件描述符,而且它的本质就是一个非负的整数。这样就清晰了,该表就是一个元素为非负整数的数组(这是笔者的理解,有待考证),每个打开的文件就占据一个元素作为它的“身份证”。当我们打开一个文件时,内核就返回给用户该文件的描述符,以后 要操作该文件,就要使用到该文件描述符。
事实上内核在拿到用户传递进来的文件描述符后是经过一系列的查找,以找到用户要操作的文件。具体的过程以后再撰文细说。这里只要知道进程的文件描述符就对应着要操作的文件。
二、函数学习
从APUE可以看出,我们需要学习的文件操作包括:open、create、close、lseek、read、write等。这里笔者希望在学完所有的函数以后写一个copy程序,因此这些函数基本都会用到。
1、open
1.1、函数功能:打开/创建文件
1.2、原型: #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.3、参数:pathname:文件路径;flag:打开的方式;mode:要创建的文件的属性
1.4、返回值:成功:文件描述符;失败:-1
这个函数有两个原型,当参数 flag 包含 O_CREAT 字段时就要加上第三个参数,当没有该字段,就使用前两个参数即可。每个参数能取的值定义在头文件中。
2、creat
2.1、函数功能:创建文件
2.2、原型:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
2.3、参数:pathname:文件路径;mode:文件属性
2.4、返回值:成功:文件描述符;失败:-1
该函数其实就是 open 函数加上 O_CREAT 字段以后的版本。
3、close
3.1、函数功能:关闭一个文件
3.2、原型: #include <unistd.h>
int close(int fd);
3.3、参数:fd:要关闭的文件描述符
3.4、返回值:成功:0;失败:-1
该函数关闭一个打开的文件,关闭一个文件后加在文件上的文件锁就会被释放。当一个进程结束后即使没有显式地调用该函数,内核也会关闭所有打开的文件。
4、lseek
4.1、函数功能:重定位读写指针
4.2、原型: #include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
4.3、参数:fd:要改变指针的文件;offset:偏移的长度;whence:偏移的起始位置
4.4、返回值:成功:操作成功后的偏移地址;失败:-1
内核为进程每个打开的文件提供一个描述结构 file,该结构里就有一个当前读写的”位置指针“,读写的操作都要根据该字段进行,lseek函数实际上就是改变该字段。
5、write
5.1、函数功能:写数据到文件中
5.2、原型: #include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
5.3、参数:fd:要写入的文件描述符;buf:待写入的内容指针;count:本次期望写入的字节数
5.4、返回值:成功:本次实际写入的字节数;失败:-1
6、read
6.1、函数功能:从文件中读回数据
6.2、原型: #include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
6.3、参数:fd:待读文件描述符;buf:读回所放的位置;count:此次希望读回的字节数
6.4、返回值:成功:本次读回的字节数;失败:-1
三、范例代码
介绍完文件编程的基本函数后就可以写一个小程序来测试所学的函数。这里笔者写了一个简单的copy 程序。程序功能很简单,复制一个已存在的文件。代码如下:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#define count 50int main(int argc, char *argv[]){ int source_fd = 0; int dest_fd = 0; char buf[256] = {0}; int read_size = 0; int flag = 0; if(argc!=3) { printf("numberof args error!\n"); return 0; } /** 1. open source file **/ if((source_fd = open(argv[1],O_RDONLY))==-1) { printf("No such file:%s",argv[1]); return 0; } /** 2. crete dest file **/ if((dest_fd = open(argv[2],O_RDWR|O_CREAT|O_APPEND,0666))==-1) { printf("Creating file error:%s",argv[2]); return 0; } while(1) { /** 3. read datas from source file **/ if((read_size = read(source_fd, buf, count))<count) { flag = 1; } /** 4. write datas to dest file **/ write(dest_fd,buf,read_size); if(flag==1) break; } /** 5. close source file and dest file **/ close(source_fd); close(dest_fd); printf("Copying completed!\n"); return 0;}
经过测试,本程序可以成功复制一个已存在的文件。
这里介绍的仅仅是完成一个复制程序的的一小部分编程函数,还有很多关于文件操作的函数没有涉及到,往后应该会对文件属性操作的函数进行讲解。
- 【Linux库函数编程】文件编程
- linux编程_Makefile文件
- linux编程_Makefile文件
- Linux文件编程实例
- linux文件编程
- linux文件编程
- Linux文件编程
- Linux文件编程
- Linux文件IO编程
- LINUX文件编程基础知识
- Linux文件编程
- linux文件编程
- linux文件编程
- linux 文件编程
- linux文件编程
- linux文件编程
- linux文件编程
- Linux文件编程
- 浅析C#数据类型转换的几种形式
- Sql server 的表值函数是返回一个Table类型,table类型相当与一张存储在内存中的一张虚拟表。
- sessionStorage和localstorage,globalstorage 的区别
- BFPRT(线性查找)算法
- Django框架搭建个人博客网站实例
- Linux 文件编程
- Codeforces Round #327 (Div. 2)
- 前端优良习惯集锦
- 以B2C物流的前世今生,看未来电商物流的决胜之道
- 深度优先搜索(DFS) 算法
- JSON.parse()和JSON.stringify()
- 九、股票成交方式
- java中的枚举类型
- opencv-第六章-图像变换之sobel算子