UNIX Day05

1 写入文件
2 读取文件
3 二进制读写
4 文本读写
5 顺序与随机读写
6 内存映射文件
7 文件元数据
1 写入文件
1.1 问题
文件被打开后,就可以向其中写入字节流,注意在不使用文件时需要将文件关闭。

1.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:写入文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
char text[] = “将这些内容写入到文件中”;
size_t towrite = strlen(text);
ssize_t written = write (fd, text, towrite);
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

创建并打开一个data.txt文件。

上述代码中,以下代码:

char text[] = "将这些内容写入到文件中";
size_t towrite = strlen(text);
ssize_t written = write (fd, text, towrite);
if (written == -1) 
{ 
    perror ("write"); 
    exit (EXIT_FAILURE); 
}

使用write函数将字符数组text中的内容写入到data.txt文件中。该函数的参数说明如下:

第一个参数为文件描述符。

第二个参数为要写入数据的内存缓冲区的首地址。

第三个参数为期望写入的字节数。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

1.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
char text[] = “将这些内容写入到文件中”;
size_t towrite = strlen(text);
ssize_t written = write (fd, text, towrite);
if (written == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
2 读取文件
2.1 问题
文件被打开后,就可以从其中读出字节流,注意在不使用文件时需要将文件关闭。

2.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:读取文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
char text1[1024] = {};
size_t toread = 1024;
ssize_t readed = read (fd, text1, toread);
if (readed == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf("%s\n", text1);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDONLY, 0444);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

打开一个data.txt文件。

上述代码中,以下代码:

char text1[1024] = {};
size_t toread = 1024;
ssize_t readed = read (fd, text1, toread);
if (readed == -1)
{
perror(“read”);
exit (EXIT_FALLURE);
}
Printf(“%s\n”,text1);
使用read函数从文件中读取字节流。该函数的参数说明如下:

第一个参数为文件描述符。

第二个参数为要读入数据存放的内存缓冲区的首地址。

第三个参数为期望读入的字节数。

函数的返回值为实际读入的字节数。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

2.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
char text1[1024] = {};
size_t toread = 1024;
ssize_t readed = read (fd, text1, toread);
if (readed == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf("%s\n", text1);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
3 二进制读写
3.1 问题
基于系统调用的文件读写本来就是面向二进制字节流的,因此对二进制读写而言,无需做任何额外的工作。

3.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:写入文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
if (write (fd, &emp, sizeof (emp)) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

创建并打开一个名为data.txt的文件。

上述代码中,以下代码:

typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
定义一个结构体变量emp,并对其进行初始化。

上述代码中,以下代码:

if (write (fd, &emp, sizeof (emp)) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
使用write函数将结构体变量emp写入文件data.txt。需要注意的是,第二个参数为要写入的数据的首字节地址,所以这里对emp取地址。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

步骤二:读取文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
if (read (fd, &emp, sizeof (emp)) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf("%s,%d,%f\n", emp.name, emp.age, emp.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDONLY, 0444);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

打开一个名为data.txt的文件。

上述代码中,以下代码:

typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
定义一个结构体变量emp,并对其每个字节进行初始化为0。

上述代码中,以下代码:

if (read (fd, &emp, sizeof (emp)) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
从文件data.txt中读取二进制数据。需要注意的是,第二个参数为要读入数据在内存存放的首字节地址,所以这里对emp取地址。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

3.3 完整代码
本案例的完整代码如下所示:

写入文件代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
if (write (fd, &emp, sizeof (emp)) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
读取文件代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
if (read (fd, &emp, sizeof (emp)) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
printf("%s,%d,%f\n", emp.name, emp.age, emp.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
4 文本读写
4.1 问题
因为基于系统调用的文件读写是面向二进制字节流的,因此对写入内容的格式化和对读取内容的解格式化,都必须通过自己编写的代码处理。

4.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:写入文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

创建并打开一个名为data.txt的文件。

上述代码中,以下代码:

typedefstruct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
定义一个结构体变量emp,并对其进行初始化。

上述代码中,以下代码:

char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
因此对写入的内容进行格式化处理。

上述代码中,以下代码:

if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
使用write函数将格式化处理后的内容写入文件data.txt。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

步骤二:读取文件

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
char buf[1024] = {};
if (read (fd, buf, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
sscanf(buf, “%s%d%f”, emp.name, &emp.age, &emp.salary);
printf("%s,%d,%f\n", emp.name, emp.age, emp.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDONLY, 0444);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

打开一个名为data.txt的文件。

上述代码中,以下代码:

typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
定义一个结构体变量emp,并对其每个字节进行初始化为0。

上述代码中,以下代码:

char buf[1024] = {};
if (read (fd, buf, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
从文件data.txt中读取文本数据。

上述代码中,以下代码:

sscanf(buf, "%s%d%f", emp.name, &emp.age, &emp.salary);

对读取内容的解格式化,放入变量emp中。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

4.3 完整代码
本案例的完整代码如下所示:

写入文件代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
读取文件代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDONLY, 0444);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {};
char buf[1024] = {};
if (read (fd, buf, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
sscanf(buf, “%s%d%f”, emp.name, &emp.age, &emp.salary);
printf("%s,%d,%f\n", emp.name, emp.age, emp.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
5 顺序与随机读写
5.1 问题
每个打开的文件都有一个与其相关的“文件读写位置”保存在文件表项中,用以记录从文件头开始计算的字节偏移,“文件读写位置”通常是一个非负的整数,用off_t类型表示,在32位系统上被定义为long int,而在64位系统上则被定义为long long int。

打开一个文件时,除非指定了O_APPEND标志,否则文件读写位置一律被设为0,即文件首字节的位置。

5.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:顺序读写

每一次读写操作都从当前的文件读写位置开始,并根据所读写的字节数,同步增加文件读写位置,为下一次读写做好准备。

因为文件读写位置是保存在文件表项而不是v节点中的,因此通过多次打开同一个文件得到多个文件描述符,各自拥有各自的文件读写位置。

步骤二:随机读写

代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
lseek(fd, 0, SEEK_SET);
EMP emp1 = {};
char buf1[1024] = {};
if (read (fd, buf1, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
sscanf(buf1, “%s%d%f”, emp1.name, &emp1.age, &emp1.salary);
printf("%s,%d,%f\n", emp1.name, emp1.age, emp1.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

int fd = open ("data.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
    perror ("open");
    exit (EXIT_FAILURE);
}

创建并打开一个名为data.txt的文件。

上述代码中,以下代码:

typedef strutc Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
定义一个结构体变量emp,并对其进行初始化。

上述代码中,以下代码:

char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
因此对写入的内容进行格式化处理。

上述代码中,以下代码:

if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
使用write函数将格式化处理后的内容写入文件data.txt。

上述代码中,以下代码:

lseek(fd, 0, SEEK_SET);

使用lseek函数人为调整“文件读写位置”。该函数的参数说明如下:

第一个参数为文件描述符。

第二个参数为文件读写位置相对于第一个参数的偏移量。

第三个参数为根据offset参数计算文件读写位置的起点,可取以下值

SEEK_SET - 从文件头(文件的第一个字节)开始

SEEK_CUR - 从当前位置(上次读写的最后一个字节的下一个位置)开始

SEEK_END - 从文件尾(文件最后一个字节的下一个位置)开始

该函数的返回值为调整后的“文件读写位置”。

上述代码中,以下代码:

EMP emp1 = {};
char buf1[1024] = {};
if (read (fd, buf1, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
从文件data.txt中读取文本数据。

上述代码中,以下代码:

sscanf(buf1, "%s%d%f", emp1.name, &emp1.age, &emp1.salary);

对读取内容的解格式化,放入变量emp中。

上述代码中,以下代码:

if (close (fd) == -1)
{
    perror ("close");
    exit (EXIT_FAILURE);
}

在文件data.txt不再使用时将其关闭。

5.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
typedef struct Employee
{
char name[256];
int age;
float salary;
} EMP;
EMP emp = {“赵云”, 25, 8000};
char buf[1024] = {};
sprintf(buf, “%s %d %0.2f”, emp.name, emp.age, emp.salary);
if (write (fd, buf, strlen(buf) * sizeof (buf[0])) == -1)
{
perror (“write”);
exit (EXIT_FAILURE);
}
lseek(fd, 0, SEEK_SET);

EMP emp1 = {};
char buf1[1024] = {};
if (read (fd, buf1, 1024) == -1)
{
perror (“read”);
exit (EXIT_FAILURE);
}
sscanf(buf1, “%s%d%f”, emp1.name, &emp1.age, &emp1.salary);
printf("%s,%d,%f\n", emp1.name, emp1.age, emp1.salary);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
6 内存映射文件
6.1 问题
内存映射文件不仅提供了一种以访问内存的方式读写文件的方法,而且还在多个进程之间打通了一条基于文件共享的数据通道

6.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:内存映射文件

代码如下所示:

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
ftruncate (fd, 8192);
char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
perror (“mmap”);
exit (EXIT_FAILURE);
}
strcpy (p, “Hello, File !”);
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
perror (“munmap”);
exit (EXIT_FAILURE);
}
strcpy (p += 4096, “Hello, File !”);
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
perror (“munmap”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

ftruncate (fd, 8192);

使用函数ftruncate修改指定文件的大小。该函数有两个参数,说明如下:

第一个参数为文件描述符,即修改哪个文件。

第二个参数为文件大小。

该函数既可以把文件截短,也可以把文件加长,对于后者,新增加的部分全部用数字0填充

上述代码中,以下代码:

char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
    perror ("mmap");
    exit (EXIT_FAILURE);
}

使用函数mmap建立虚拟内存到物理内存或文件的映射。该函数有六个参数,说明如下:

第一个参数为映射区内存起始地址,NULL系统自动选定后返回

第二个参数为映射区字节长度,自动按页(4K)圆整

第三个参数为映射区访问权限,可取以下值

PROT_READ - 映射区可读

PROT_WRITE - 映射区可写

PROT_EXEC - 映射区可执行PROT_NONE - 映射区不可访问

第四个参数为映射标志,可取以下值。

MAP_ANONYMOUS - 匿名映射,将虚拟内存映射到物理内存而非文件,忽略fd和offset参数。

MAP_PRIVATE - 对映射区的写操作只反映到缓冲区中,并不会真正写入文件。

MAP_SHARED - 对映射区的写操作直接反映到文件中。

MAP_DENYWRITE - 拒绝其它对文件的写操作。

MAP_FIXED - 若在start上无法创建映射,则失败(无此标志系统会自动调整)。

MAP_LOCKED - 锁定映射区,保证其不被换出。

第五个参数为文件描述符

第六个参数为文件偏移量,自动按页(4K)对齐

上述代码中,以下代码:

strcpy (p, "Hello, File !");

看似写内存,实则写文件。

上述代码中,以下代码:

printf ("%s\n", p);

假读内存之名,行读文件之实。

上述代码中,以下代码:

if (munmap (p, 4096) == -1)
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}

使用函数munmap解除虚拟内存到物理内存或文件的映射。该函数有两个参数,说明如下:

第一个参数为:映射区内存起始地址,必须是页的首地址。

第二个参数为映射区字节长度,自动按页(4K)圆整。

函数munmap允许对映射区的一部分解映射,但必须按页为单位。

6.3 完整代码
本案例的完整代码如下所示:

#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
ftruncate (fd, 8192);
char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
perror (“mmap”);
exit (EXIT_FAILURE);
}
strcpy (p, “Hello, File !”);
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
perror (“munmap”);
exit (EXIT_FAILURE);
}
strcpy (p += 4096, “Hello, File !”);
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
perror (“munmap”);
exit (EXIT_FAILURE);
}
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
7 文件元数据
7.1 问题
文件的元数据是指文件的属性信息。本案例讲解如何获取文件元数据,元数据的数据结构,及文件类型和权限说明。

7.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:获取文件元数据

代码如下所示:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd = open (“data.txt”, O_RDWR, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
struct stat statdata;
fstat(fd, &statdata);
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

fstat(fd, &statdata);

使用函数fstat提取文件fd的元数据。该函数有两个参数,说明如下:

第一个参数为文件描述符,即哪个文件。

第二个参数为文件元数据结构地址。

步骤二:文件元数据结构

stat结构体说明如下:

struct stat
{
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
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;
};
上述代码中,以下代码:

dev_t st_dev;
保存设备的ID号。

上述代码中,以下代码:

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;
保存特殊设备的ID号。

上述代码中,以下代码:

off_t st_size;
保存文件的总字节数。

上述代码中,以下代码:

blksize_t st_blksize;
保存I/O块的字节数。

上述代码中,以下代码:

blkcnt_t st_blocks;
保存占用块数,每块512字节。

上述代码中,以下代码:

time_t st_atime;
保存文件的最后访问时间。

上述代码中,以下代码:

time_t st_mtime;
保存文件的最后修改时间。

上述代码中,以下代码:

time_t st_ctime;
保存文件的最后状态修改时间。

步骤三:文件类型和权限

stat结构的st_mode成员表示文件的类型和权限,该成员在stat结构中被声明为mode_t类型,其原始类型在32位系统中被定义为unsigned int,即32位无符号整数,但到目前为止,只有其中的低18位有意义。其中:

B17B16B15B14B13B12:文件类型

B11B10B9:设置用户ID、设置组ID和粘滞

B8B7B6:拥有者用户的读、写和执行权限

B5B4B3:拥有者组的读、写和执行权限

B2B1B0:其它用户的读、写和执行权限

代码如下所示:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
constchar* mtos (mode_t m)
{
staticchar s[11];
if(S_ISDIR (m))
strcpy (s, “d”);
elseif (S_ISSOCK (m))
strcpy (s, “s”);
elseif (S_ISCHR (m))
strcpy (s, “c”);
elseif (S_ISBLK (m))
strcpy (s, “b”);
elseif (S_ISLNK (m))
strcpy (s, “l”);
elseif (S_ISFIFO (m))
strcpy (s, “p”);
else
strcpy (s, “-”);
strcat (s, m & S_IRUSR ? “r” : “-”);
strcat (s, m & S_IWUSR ? “w” : “-”);
strcat (s, m & S_IXUSR ? “x” : “-”);
strcat (s, m & S_IRGRP ? “r” : “-”);
strcat (s, m & S_IWGRP ? “w” : “-”);
strcat (s, m & S_IXGRP ? “x” : “-”);
strcat (s, m & S_IROTH ? “r” : “-”);
strcat (s, m & S_IWOTH ? “w” : “-”);
strcat (s, m & S_IXOTH ? “x” : “-”);
if (m & S_ISUID)
s[3] = (s[3] == ‘x’ ? ‘s’ : ‘S’);
if (m & S_ISGID)
s[6] = (s[6] == ‘x’ ? ‘s’ : ‘S’);
if (m & S_ISVTX)
s[9] = (s[9] == ‘x’ ? ‘t’ : ‘T’);
return s;
}
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
struct stat statdata;
fstat(fd, &statdata);
printf("%s\n", mtos(statdata.st_mode));
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}
上述代码中,以下代码:

if(S_ISDIR (m))
strcpy (s, “d”);
判断该文件是否是目录。

上述代码中,以下代码:

elseif (S_ISSOCK (m))
strcpy (s, “s”);
判断该文件是否是本地套接字。

上述代码中,以下代码:

elseif (S_ISCHR (m))
strcpy (s, “c”);
判断该文件是否是字符设备。

上述代码中,以下代码:

elseif (S_ISBLK (m))
strcpy (s, “b”);
判断该文件是否是块设备。

上述代码中,以下代码:

elseif (S_ISLNK (m))
strcpy (s, “l”);
判断该文件是否是符号链接。

上述代码中,以下代码:

elseif (S_ISFIFO (m))
strcpy (s, “p”);
判断该文件是否是有名管道。

上述代码中,以下代码:

else
strcpy (s, “-”);
该文件是普通文件。

上述代码中,以下代码:

strcat (s, m & S_IRUSR ? "r" : "-");

该文件允许用户读。

上述代码中,以下代码:

strcat (s, m & S_IWUSR ? "w" : "-");

该文件允许用户写。

上述代码中,以下代码:

strcat (s, m & S_IXUSR ? "x" : "-");

该文件允许用户执行。

上述代码中,以下代码:

strcat (s, m & S_IRGRP ? "r" : "-");

该文件允许组读。

上述代码中,以下代码:

strcat (s, m & S_IWGRP ? "w" : "-");

该文件允许组写。

上述代码中,以下代码:

strcat (s, m & S_IXGRP ? "x" : "-");

该文件允许组执行。

上述代码中,以下代码:

strcat (s, m & S_IROTH ? "r" : "-");

该文件允许其它读。

上述代码中,以下代码:

strcat (s, m & S_IWOTH ? "w" : "-");

该文件允许其它写。

上述代码中,以下代码:

strcat (s, m & S_IXOTH ? "x" : "-");

该文件允许其它执行。

上述代码中,以下代码:

if (m & S_ISUID)
s[3] = (s[3] == ‘x’ ? ‘s’ : ‘S’);
判断是否设置用户ID位。

上述代码中,以下代码:

if (m & S_ISGID)
s[6] = (s[6] == ‘x’ ? ‘s’ : ‘S’);
判断是否设置组ID位。

上述代码中,以下代码:

if (m & S_ISVTX)
s[9] = (s[9] == ‘x’ ? ‘t’ : ‘T’);
判断是否设置粘滞位。

7.3 完整代码
本案例中的完整代码如下所示:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
constchar* mtos (mode_t m)
{
staticchar s[11];
if(S_ISDIR (m))
strcpy (s, “d”);
elseif (S_ISSOCK (m))
strcpy (s, “s”);
elseif (S_ISCHR (m))
strcpy (s, “c”);
elseif (S_ISBLK (m))
strcpy (s, “b”);
elseif (S_ISLNK (m))
strcpy (s, “l”);
elseif (S_ISFIFO (m))
strcpy (s, “p”);
else
strcpy (s, “-”);
strcat (s, m & S_IRUSR ? “r” : “-”);
strcat (s, m & S_IWUSR ? “w” : “-”);
strcat (s, m & S_IXUSR ? “x” : “-”);
strcat (s, m & S_IRGRP ? “r” : “-”);
strcat (s, m & S_IWGRP ? “w” : “-”);
strcat (s, m & S_IXGRP ? “x” : “-”);
strcat (s, m & S_IROTH ? “r” : “-”);
strcat (s, m & S_IWOTH ? “w” : “-”);
strcat (s, m & S_IXOTH ? “x” : “-”);
if (m & S_ISUID)
s[3] = (s[3] == ‘x’ ? ‘s’ : ‘S’);
if (m & S_ISGID)
s[6] = (s[6] == ‘x’ ? ‘s’ : ‘S’);
if (m & S_ISVTX)
s[9] = (s[9] == ‘x’ ? ‘t’ : ‘T’);
return s;
}
int main()
{
int fd = open (“data.txt”, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd == -1)
{
perror (“open”);
exit (EXIT_FAILURE);
}
struct stat statdata;
fstat(fd, &statdata);
printf("%s\n", mtos(statdata.st_mode));
if (close (fd) == -1)
{
perror (“close”);
exit (EXIT_FAILURE);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值