# 文件,第 1 部分:使用文件
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Files%2C-Part-1%3A-Working-with-files>
## 两种类型的文件
在 linux 上,有两个带文件的抽象。第一个是 linux `fd`级抽象,意味着你可以使用
* `open`
* `read`
* `write`
* `close`
* `lseek`
* `fcntl` ......
等等。 linux 界面非常强大且富有表现力,但有时我们需要可移植性(例如,如果我们正在为 mac 或 windows 编写)。这就是 C 的抽象发挥作用的地方。在不同的操作系统上,C 使用低级函数来创建可以在任何地方使用的文件的包装器,这意味着 Linux 上的 C 使用上述调用。 C 有以下几点
* `fopen`
* `fread`或`fgetc/fgets`或`fscanf`
* `fwrite`或`fprintf`
* `fclose`
* `fflush`
但是你没有得到 linux 给你系统调用的表达能力,你可以使用`int fileno(FILE* stream)`和`FILE* fdopen(int fd...)`在它们之间来回转换。
需要注意的另一个重要方面是 C 文件是**缓冲**,这意味着默认情况下可能无法写入内容。您可以使用 C 选项更改它。
## 如何判断文件有多大?
对于小于 long 的文件,使用 fseek 和 ftell 是一种简单的方法来完成此任务:
移动到文件末尾并找出当前位置。
```c
fseek(f, 0, SEEK_END);
long pos = ftell(f);
```
这告诉我们文件中的当前位置(以字节为单位) - 即文件的长度!
`fseek`也可用于设置绝对位置。
```c
fseek(f, 0, SEEK_SET); // Move to the start of the file
fseek(f, posn, SEEK_SET); // Move to 'posn' in the file.
```
父进程或子进程中的所有未来读取和写入都将遵循此位置。注意从文件中写入或读取将改变当前位置。
有关更多信息,请参见 fseek 和 ftell 的手册页。
## 但尽量不要这样做
**注意:由于 C 语言**的怪癖,在通常情况下不建议这样做。这个怪癖是多头只需要 **4 字节大**意味着 ftell 可以返回的最大大小略低于 2 千兆字节(我们现在知道我们的文件可能是几百千兆字节甚至太字节数分布式文件系统)。我们该怎么做呢?使用`stat`!我们将在后面的部分介绍 stat,但这里有一些代码可以告诉你文件的大小
```c
struct stat buf;
if(stat(filename, &buf) != -1){
return -1;
}
return (ssize_t)buf.st_size;
```
buf.st_size 的类型为 off_t,足够 _ 疯狂 _ 大文件。
## 如果子进程使用`fclose`或`close`关闭文件流会发生什么?
关闭文件流对每个进程都是唯一的。其他进程可以继续使用自己的文件句柄。请记住,在创建子项时,甚至文件的相对位置都会复制所有内容。
## mmap for files 怎么样?
mmap 的一般用途是将文件映射到内存。这并不意味着文件立即被 malloc'ed 到内存中。以下面的代码为例。
```
int fd = open(...); //File is 2 Pages
char* addr = mmap(..fd..);
addr[0] = 'l';
```
内核可能会说,“好吧,我看到你想把文件映射到内存中,所以我会在你的地址空间中预留一些空间,即文件的长度”。这意味着当您写入 addr [0]时,您实际上正在写入文件的第一个字节。内核实际上也可以做一些优化。它不是将文件加载到内存中,而是一次只能加载页面,因为如果文件是 1024 页;您只能访问 3 或 4 页,这使得加载整个文件浪费时间(这就是页面错误如此强大的原因!它们让操作系统控制您使用文件的程度)。
## 对于每个 mmap
请记住,一旦完成`mmap` ping 您`munmap`告诉操作系统您不再使用已分配的页面,因此操作系统可以将其写回磁盘并在需要时将地址返回给您 malloc 以后。
- UIUC CS241 系统编程中文讲义
- 0. 简介
- #Informal 词汇表
- #Piazza:何时以及如何寻求帮助
- 编程技巧,第 1 部分
- 系统编程短篇小说和歌曲
- 1.学习 C
- C 编程,第 1 部分:简介
- C 编程,第 2 部分:文本输入和输出
- C 编程,第 3 部分:常见问题
- C 编程,第 4 部分:字符串和结构
- C 编程,第 5 部分:调试
- C 编程,复习题
- 2.进程
- 进程,第 1 部分:简介
- 分叉,第 1 部分:简介
- 分叉,第 2 部分:Fork,Exec,等等
- 进程控制,第 1 部分:使用信号等待宏
- 进程复习题
- 3.内存和分配器
- 内存,第 1 部分:堆内存简介
- 内存,第 2 部分:实现内存分配器
- 内存,第 3 部分:粉碎堆栈示例
- 内存复习题
- 4.介绍 Pthreads
- Pthreads,第 1 部分:简介
- Pthreads,第 2 部分:实践中的用法
- Pthreads,第 3 部分:并行问题(奖金)
- Pthread 复习题
- 5.同步
- 同步,第 1 部分:互斥锁
- 同步,第 2 部分:计算信号量
- 同步,第 3 部分:使用互斥锁和信号量
- 同步,第 4 部分:临界区问题
- 同步,第 5 部分:条件变量
- 同步,第 6 部分:实现障碍
- 同步,第 7 部分:读者编写器问题
- 同步,第 8 部分:环形缓冲区示例
- 同步复习题
- 6.死锁
- 死锁,第 1 部分:资源分配图
- 死锁,第 2 部分:死锁条件
- 死锁,第 3 部分:餐饮哲学家
- 死锁复习题
- 7.进程间通信&amp;调度
- 虚拟内存,第 1 部分:虚拟内存简介
- 管道,第 1 部分:管道介绍
- 管道,第 2 部分:管道编程秘密
- 文件,第 1 部分:使用文件
- 调度,第 1 部分:调度过程
- 调度,第 2 部分:调度过程:算法
- IPC 复习题
- 8.网络
- POSIX,第 1 部分:错误处理
- 网络,第 1 部分:简介
- 网络,第 2 部分:使用 getaddrinfo
- 网络,第 3 部分:构建一个简单的 TCP 客户端
- 网络,第 4 部分:构建一个简单的 TCP 服务器
- 网络,第 5 部分:关闭端口,重用端口和其他技巧
- 网络,第 6 部分:创建 UDP 服务器
- 网络,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:远程过程调用简介
- 网络复习题
- 9.文件系统
- 文件系统,第 1 部分:简介
- 文件系统,第 2 部分:文件是 inode(其他一切只是数据...)
- 文件系统,第 3 部分:权限
- 文件系统,第 4 部分:使用目录
- 文件系统,第 5 部分:虚拟文件系统
- 文件系统,第 6 部分:内存映射文件和共享内存
- 文件系统,第 7 部分:可扩展且可靠的文件系统
- 文件系统,第 8 部分:从 Android 设备中删除预装的恶意软件
- 文件系统,第 9 部分:磁盘块示例
- 文件系统复习题
- 10.信号
- 过程控制,第 1 部分:使用信号等待宏
- 信号,第 2 部分:待处理的信号和信号掩码
- 信号,第 3 部分:提高信号
- 信号,第 4 部分:信号
- 信号复习题
- 考试练习题
- 考试主题
- C 编程:复习题
- 多线程编程:复习题
- 同步概念:复习题
- 记忆:复习题
- 管道:复习题
- 文件系统:复习题
- 网络:复习题
- 信号:复习题
- 系统编程笑话