您的位置:首页 > 运维架构 > Linux

Linux 应用开发_03.1Posix 磁盘文件内容管理

2015-01-17 00:40 295 查看
//简单的文件拷贝
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char *argv[])
{
if(argc !=3 )
{
printf("pls input message format as:%s src_file des_file\n",argv[0]);
exit(EXIT_FAILURE);
}
int fd_src,fd_dst;
fd_src = open(argv[1],O_RDONLY|O_CREAT,0644);

if(-1 == fd_src)
{
perror("open");
exit(EXIT_FAILURE);
}

fd_dst = open(argv[2],O_WRONLY|O_CREAT,0644);
if(-1 == fd_dst)
{
perror("open");
exit(EXIT_FAILURE);
}

char buf[1024];
int ret = 0;
memset(buf,'\0',1024);

while(1)
{
ret = read(fd_src,buf,1024);
if(ret == -1)
{
perror("read");exit(EXIT_FAILURE);
}
else if(ret == 0)
break;
else
write(fd_dst,buf,ret);
}

close(fd_src);
close(fd_dst);
return 0;
}


守望者成才网(http://watchmen.cn/)

本课目标

(1)编程目标:实现磁盘文件的拷贝操作。cp

(2)理解系统调用、文件描述符以及对文件及文件描述符操作。

主要知识点

(1)认识系统调用与内核对象。

(2)如何访问磁盘文件内容。

(3)磁盘文件内容的操作。

(4)对文件描述符的操作。

课程内容

一、内核空间与用户空间,文件描述符

Linux 操作系统内核态(空间)与用户态(空间)。

磁盘文件也是由 OS 来管理,因此,要访问需要通过系统调用来实现。怎么让一个程序(进程)与

要操作的文件建立联系。Watchmen 成才网(版权所有)http://www.watchmen.cn

01_Linux 高级程序设计 配套视频 Watchmen 出品@版权所有

Posix 磁盘文件内容管理 修订时间:2014-05-10 V0.9 页码 2/7

要去访问磁盘的文件,必须通过系统调用来返回一个与该文件相关联的 ID,这个 ID 就是文件描述

符 file descriptor。

Linux 操作系统提供了 open 系统调用,任何的进程要去访问一个文件,首先使用 open 打开这个文

件,系统将返回一个编号,即与这个文件相关联的文件描述符。

(1)用户程序从用户空间向内核空间提交了打开申请。

(2)操作系统会在内核中去检查请求是否合法,如果合法,在内核中申请这个打开文件相关的信

息(读写位置,在磁盘中的位置…..全用 struct files 来存储)。并且添加到当前进程的 PCB 块中的打开文

件列表数组中。对应的这个数组下标即文件描述符值。

(3)将这个文件描述符返回给用户空间,用户空间接下来对这个文件进行读写就通过这个编号

值。

系统默认为每个进程打开了三个文件:

printf/scanf

文件描述符 0(标准输入,键盘 STDIN_FILENO),1(标准输出,显示器 STDOUT_FLIENO),2

(标准错误输出,显示器 STDERR_FILENO)

二 、IO 系统调用函数

建立与断开联系 open/close

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, //打开文件路径

int flags); //打开的方式等 flags

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

int creat(const char *pathname, mode_t mode);

只读方式 O_READONLY

只写方式 O_WRITEONLY

读写方式 O_RDWR

追加方式 O_APPEND

/* open/fcntl - O_SYNC is only implemented on blocks devices and on files

located on an ext2 file system */

#define O_ACCMODE 0003

#define O_RDONLY 00

#define O_WRONLY 01

#define O_RDWR 02

#define O_APPEND 02000

#define O_CREAT 0100 /* not fcntl */

#define O_EXCL 0200 /* not fcntl */

#define O_NOCTTY 0400 /* not fcntl */

#define O_TRUNC 01000 /* not fcntl */

#define O_NONBLOCK 04000

#define O_NDELAY O_NONBLOCK

#define O_SYNC 010000

#define FASYNC 020000 /* fcntl, for BSD compatibility */

#define O_DIRECT 040000 /* direct disk access hint - currently ignored */

#define O_LARGEFILE 0100000 //大于 2G 的文件

#define O_DIRECTORY 0200000 /* must be a directory */

#define O_NOFOLLOW 0400000 /* don't follow links */

#define O_ATOMICLOOKUP 01000000 /* do atomic file lookup */

O_CREAT|O_RDWR

如果创建文件, 这个新文件的权限是什么?怎么来描述?Watchmen 成才网(版权所有)http://www.watchmen.cn

01_Linux 高级程序设计 配套视频 Watchmen 出品@版权所有

Posix 磁盘文件内容管理 修订时间:2014-05-10 V0.9 页码 4/7

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

新创建一个文件的真正权限是 mode & ~umask

这个文件打开成功,将返回一个新的文件描述符值,后面针对这个文件的操作就使用这个文件描述

符。

读写文件内容 read/write

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

//从 fd 所指向的文件中读取 count 字节到 buf 为首地址的内存空间中。

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

//往 fd 所指向的文件中写入 count 字节,这个内容存放在 buf 为首地址的内存空间中。

文件位置的修改 lseek

对当前文件的读写位置进行定位。可以在文件中添加空洞。

off_t lseek(int fd, off_t offset, int whence);

SEEK_SET

The offset is set to offset bytes.

SEEK_CUR

The offset is set to its current location plus offset bytes.

SEEK_END

The offset is set to the size of the file plus offset bytes.

也可以用这个函数来实现文件大小的获取。把文件的读写位置设置为文件结束,因为这个函数返回

当前读写位置距离文件头的偏移字节数。

lseek+write=pwrite

lseek+read =pread

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

三、 文件描述符操作

(1)复制功能。用处,第 9 章管道时会提到重定向的应用 cat test>test.txt。

复制后,两个文件描述符都指向同一个文件表项,即使用这两个文件描述符中的一个就会影响读写

相关的信息。

dup/dup2/fcntl

int dup(int oldfd); //复制 oldfd 这个文件描述符,返回在调用此函数前最小未使用的文件描述符Watchmen 成才网(版权所有)http://www.watchmen.cn

01_Linux 高级程序设计 配套视频 Watchmen 出品@版权所有

Posix 磁盘文件内容管理 修订时间:2014-05-10 V0.9 页码 5/7

值。

close(0);

dup(3);

这个代码可以实现输入的重定向。默认从 0 读数据,现在 0 指向的表项被复制为 3,这样从 0 读实

际上就是从 3 指向的文件读,也就实现的输入的重定向。

int dup2(int oldfd, int newfd);

把 oldfd 复制为 newfd,如果 newfd 已经对应一个打开的文件,则先关闭它。

dup2(3,0);

int fcntl(int fd, int cmd, ... /* arg */ );

cmd:F_DUPFD.

fd_dup = fcntl(new_copy_fd, F_DUPFD);

(2)锁定功能。并发的环境下,除了使用并发的工具来保护共享文件外,也可以使用文件锁。

flock

int flock(int fd, int operation);

LOCK_SH Place a shared lock. More than one process may hold a shared lock for a given file at a

given time.共享读。

LOCK_EX Place an exclusive lock. Only one process may hold an exclusive lock for a given file at a

given time.排它锁。

LOCK_UN Remove an existing lock held by this process.

LOCK_NB 非阻塞式申请。

强调一下,这里指的是锁定文件描述符。锁定这个文件表项。防止被其它的进程访问,锁整个文

件。

如果要锁定某一部分,可以使用 fcntl 函数。

fcntl(fd,F_SETLKW,struct flock*);

第三个参数如下定义:

struct flock {

...

short l_type; /* Type of lock: F_RDLCK,

F_WRLCK, F_UNLCK */

short l_whence; /* How to interpret l_start: 类似于 lseek 函数

SEEK_SET, SEEK_CUR, SEEK_END */

off_t l_start; /* Starting offset for lock */ 起始位置偏移

off_t l_len; /* Number of bytes to lock */ 结束位置偏移

pid_t l_pid; /* PID of process blocking our lock 进程号

(F_GETLK only) */

...

}; Watchmen 成才网(版权所有)http://www.watchmen.cn

01_Linux 高级程序设计 配套视频 Watchmen 出品@版权所有

Posix 磁盘文件内容管理 修订时间:2014-05-10 V0.9 页码 6/7

(3)属性控制。权限状态,拥有者等。

fcntl:当前的读写状态,当前文件描述符所在的进程等系列信息。参阅书上的 5.2.7 内容。

(4)提高效率,同步磁盘。

因此,可以使用 mmap 函数来将某个打开的文件映射到虚拟地址空间,以后操作这个虚拟地址空间

就类似于操作这个文件。具体在第 2 章的内存管理视频中已经介绍。

fcntl 锁定文件示例

进程 A 进程 B

都需要对同一个文件进行写入操作

为了让定入操作是排它的,使用文件锁操作。

本章示例代码:实现大于 2G 的文件的拷贝操作。如果文件大于 2G,偏移超过 int_32 类型的限制,

为了实现大文件的拷贝,必须使用宏。

(1)在所有的头文件包含加加上

#define _LARGEFILE_SOURCE

#define _FILE_OFFSET_BITS 64

(2)在编译时,加上宏

gcc –D_LARGEFILE64_SOUCR –D_FILE_OFFFSET_BITS=64

编程作业

(1)获取当前系统信息。包括 cpu 的频率,内存利用率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: