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;
}