本文主要是介绍Unix高级编程:文件的基本操作、mmap将文件映射虚拟地址、文件描述符的复制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、文件的基本操作"open"(2)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags,...); //正确写法,真正原型
以写入的方式打开文件,如果文件不存在,则创建文件,指定文件的权限为 664
open(filename, O_RDWR|O_CREAT|O_TRUNC, mode); //mode 0664
/*代码参见 file1.c */ "优先代码框架"
#include <stdio.h>
#include <unistd.h> //close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
int fd;
int flags = O_RDWR|O_CREAT|O_TRUNC;
//打开文件
fd = open("filename", flags, 0664);
if(fd == -1) {
perror("open");
return 1;
}
printf("open success...\n");
//关闭文件
close(fd);
return 0;
}
补充:
1)"文件权限"
[d][rwx][rwx][rwx] 2 tarena tarena 4096 12月4 11:40 mmap.c
[1][234][567][890] 节点 | 拥有人 | 群组 | 大小 | 修改日期 | 文件名
[1] 文件类型
"d" 目录directory
"-" 文件file
"l" 链接文件link file
"s" 通讯文件socket
"p" 管道文件
"b" 区块设备文件,文件里可供存储的接口设备block
"c" 字符设备文件,串行端口设备,如键盘、鼠标character
"rwxrwxrwx" 有权限有字母,无权限为"-"
[234]:属主("u")user
[567]:属组("g")group
[890]:其他人("o")other
[2~0]:所有人("a")all
权限更改:
chgrp :改变档案所属群组,格式:chgrp [-R] tarena hello.c
chown :改变档案所属人,格式:chown [-R] users hello.c
chmod :改变档案的属性,格式:chmod [-R] rwx 档案或目录
"chmod" change mode 改变权限
使用chmod让所有人拥有执行权限格式:"chmod a+x (文件名)"//固定格式类推
使用chmod让其他人去除执行权限格式:"chmod o-x (文件名)"//固定格式类推
权限更改:八进制数字 r:4 w:2 x:1
"chmod 664 (文件名)"
rw-rw-r-- 0664 (210210210 二进制次方)
rwxr-xr-x 0755 (0代表普通权限,不用考虑)
u +(加入) r
chmod g -(除去) w 档案/目录
o =(设定) x
a
2)"权限掩码" //指定创建文件的时候,所要拿掉的权限,即权限掩码
获取权限掩码:"umask" 0002 -------w- 对应 -rw-rw-r-- //默认创建无x
更改umask:umask 0033 ----wx-wx 对应 -rw-r--r--
"touch file1"
-rw-rw-r-- 1 tarena tarena 0 12月 5 09:57 file1
"tarena"(1)这个文件归谁所有————属主("u")
"tarena"(2)属主指定的组————属组("g")
"close"(2)
(上次笔记)
"read"(2)
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
功能:从fd指定的文件描述符读取内容
参数:
"fd" open(2)的返回值,指定了要从这个文件描述符里读取
"buf" 存储读取内容空间的首地址
"conunt" 本次读取的最大字节数
返回值:
成功 - 返回读取的字节数(也会比count小),0 代表读取到了文件的末尾
失败 - 返回 -1 ,errno被设置
/*举例验证文件读取,代码参见 mycat.c */
#include <stdio.h>
#include <unistd.h> //close
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <strings.h> //bzero
int main(int argc, char *argv[]) {
int fd, size;
char arr[128] = {0};
int flags = O_RDWR;
fd = open(argv[1], flags);
if(fd == -1) {
perror("open");
return 1;
}
printf("open success...\n");
bzero(arr, 128); //把arr开始的地址对应数据全部设置为0
while((size = read(fd, arr, 127)) > 0) {
printf("%s", arr);
bzero(arr, 128); //把arr开始的地址对应数据全部设置为0
}
printf("read success...\n");
close(fd);
return 0;
}
gcc mycat.c -o mycat
sudo mv mycat /bin //将mycat程序在任何路径下都可以实现命令行执行其功能
sudo mv /bin/mycat . //将mycat程序移出到当前目录下
"write"(2)
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
功能:向fd指定的文件描述符写入内容
参数:
"fd" open(2)的返回值,指定了要写入文件的描述符
"buf" 从buf指定地址的空间里读取数据
"count" 最多向文件中写入的字节数
返回值:
成功 - 返回实际写入文件的字节数(也会比count小),0 代表没有内容被写入了
失败 - 返回 -1,errno被设置
/*举例验证文件写入,代码参见 write.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(void) {
char buf[128] = "hello,world!welcome!";
int fd = open("file1.c", O_WRONLY|O_CREAT|O_TRUNC, 0664);
if(fd == -1) {
perror("open");
return 1;
}
write(fd, buf, strlen(buf)); //写入有效字符个数
close(fd);
return 0;
}
0 标准输入 STDIN_FILENO
1 标准输出 STDOUT_FILENO
2 标准错误输出 STDERR_FILENO
"lseek"(2)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
功能:重新设置文件读写的位置
参数:
"fd" 指定了文件。open(2)的返回值
"offset" 相对与位置的偏移字节数
"whence"
SEEK_SET 文件的头部
SEEK_CUR 文件的当前位置
SEEK_END 文件的尾部
返回值:
成功 - 返回相对文件头的字节数
失败 - 返回 -1,errno被设置
/*举例验证lseek的使用,代码参见 lseek.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
int fd;
char buf;
fd = open("aaa.txt", O_RDWR); //aaa.txt内容:tarenaesd1610
if(fd == -1) {
perror("open");
return 1;
}
//要直接读取出第7个字符
lseek(fd, 6, SEEK_SET);
int r = read(fd, &buf, 1);
write(1, &buf, r); //1 == STDOUT_FILENO
write(STDOUT_FILENO, "\n", 2); //\n是字符串,包含\0,c
off_t var_f = lseek(fd, 0, SEEK_CUR);//获取当前读写位置
printf("%lu\n", var_f); //无符号长整形 7
close(fd);
return 0;
}
二、使用mmap将文件直接映射到进程的虚拟地址空间里,然后在内存里更新文件内容,直接反映到文件里
MAP_SHARED 对内存的操作反映的文件里
MAP_PRIVATE 只对内存操作,不反映到文件里
命令行:"od -tx1 -tc aaa.txt" //显示文件当中的偏移量及ASCII码
0000000 74 61 72 65 6e 61 0a
t a r e n a \n
0000007
/*举例验证,代码参考 mmap_file.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main(void) {
//以读写方式打开文件aaa.txt
int fd = open("aaa.txt", O_RDWR);
if(fd == -1) {
perror("open");
return 1;
}
//将文件映射到进程的虚拟地址空间里
void *p = mmap(NULL,6,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED) { //映射失败
perror("mmap");
return 2;
}
printf("mmap success...\n");
close(fd);
int *q = p; //类型转换
q[0] = 0x30313233; //十六进制转换为十进制的数,就是ASCII码
munmap(p, 6); //解除映射
return 0;
}
命令行:"od -tx1 -tc aaa.txt"
0000000 33 32 31 30 6e 61 0a
3 2 1 0 n a \n
0000007
三、文件描述符的复制
"文件重定向"
使用文件描述符的复制,可以改变进程的输入源或输出目的文件。
这样就改变的文件流的流向,这就是文件的输入/输出(I/O)"重定向"。
输入重定向
输出重定向
《鸟哥linux私房菜》——晚自习:专门看这块儿内容。
"dup"(2)
#include <unistd.h>
int dup(int oldfd);
功能:复制一个文件描述符
参数:"oldfd" 源描述符
返回值:
成功 - 返回一个新的文件描述符,未被使用的、最小的数字
失败 - 返回 -1,errno被设置
"dup2"(2)
int dup2(int oldfd, int newfd);
功能:复制一个新的文件描述符
参数:
"oldfd" 旧的文件描述符
"newfd" 新的文件描述符
返回值:
成功 - 返回一个新的文件描述符,未被使用的、最小的数字
失败 - 返回 -1,errno被设置
/*举例说明文件描述符的复制,代码参见 dup.c*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(void) {
int fd, s_fd;
char msg[20] = "hello,world!";
fd = open("hello", O_RDWR|O_CREAT, 0664); //fd(hello)->3
if(fd == -1) {
perror("open");
return 1;
} //s_fd(临时)->4
s_fd = dup(1); //STDOUT_FILENO->4
dup2(fd, 1); //fd(hello)->1
close(fd); //3不被使用,不再指向hello
write(1, msg, strlen(msg));
printf("\n");
dup2(s_fd, 1); //STDOUT_FILENO->1,回原位,hello无指向,释放
write(1, msg, strlen(msg));
write(1, "\n", 2);
close(s_fd); //4不被使用,不再指向STDOUT_FILENO
return 0;
}
cp 源文件 目标文件 (不要求拷贝文件夹,仅文件即可)
使用今天的open/read/write编写程序完成cp命令的功能,生成可执行文件mycp
/*库函数实现:代码*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
FILE *p_old, *p_new;
int size = 0;
char buf[128] = {0};
p_old = fopen(argv[1], "rb");
if(!p_old) {
printf("文件打开失败!\n");
return 1;
}
p_new = fopen(argv[2], "wb");
if(!p_new) {
printf("文件打开失败!\n");
fclose(p_old);
p_old = NULL;
return 2;
}
while(1) {
size = fread(buf, sizeof(char), 128, p_old);
fwrite(buf, sizeof(char), size, p_new);
if(!size) {
break;
}
}
fclose(p_old);
p_old = NULL;
fclose(p_new);
p_new = NULL;
return 0;
}
/*系统调用函数实现:代码*/ "老王标准答案"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*
function: 实现文件内容的拷贝
parameter:
s 源文件描述符
d 目标文件描述符
return value:
void
author:Jan
date:2016.12.07
*/
void copy_file(int s, int d) {
char buf[128];
int r, w;
char *tmp;
while((r = read(s, buf, 128)) > 0) {
tmp = buf;
while(1) { //将一次读出的内容,完全写入
w = write(d, tmp, r); //w实际写入可能会比r小
r = r - w; //未写入内容的字节数
if(!r) {
break;
}
tmp += w; //tmp往后挪
}
}
return;
}
int main(int argc, char *argv[]) {
int s_fd, d_fd;
s_fd = open(argv[1], O_RDONLY);
if(s_fd == -1) {
perror("open source");
return 1;
}
d_fd = open(argv[2], O_RDWR|O_CREAT, 0664);
if(d_fd == -1) {
perror("open dest");
close(s_fd);
return 2;
} //文件内容拷贝:
copy_file(s_fd, d_fd);
close(s_fd);
close(d_fd);
return 0;
}
这篇关于Unix高级编程:文件的基本操作、mmap将文件映射虚拟地址、文件描述符的复制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!