# 簡述
**磁盤文件和設備文件**
* 磁盤文件
指一組相關數據的有序集合,通常存儲在外部介質上(如磁盤)上,使用時才調入內存
* 設備文件
在操作系統中把每一個與主機相連的輸入,輸出設備看作一個文件,把他們的輸入,輸出等同于對磁盤文件的讀和寫
**磁盤文件的分類**
計算機的存儲在物理上是二進制的,所以物理上所有的磁盤文件本質上都是一樣的:以字節為單位進行順序存儲
從用戶或者操作系統使用者的角度(邏輯上)把文件分為:
* 文本文件: 基于字符編碼的文件
* 二進制文件: 基于值編碼的文件
**文本文件和二進制文件**
**文本文件**
* 基于字符編碼,常見編碼有ASCII,UNICODE等
* 一般可以使用文本編輯器直接打開
* 數5678的以ASCII存儲形式(ASCII碼)為:
`00110101 00110110 00110111 00111000`
**二進制文件**
* 基于值編碼,自己根據具體應用,指定某個值是什么意思
* **把內存中的數據按其在內存中的存儲形式原樣輸出到磁盤上**
* 數5678的存儲形式(二進制碼)為: `00010110 00101110`
我們對文件的概念已經非常熟悉了,比如常見的 Word 文檔、txt 文件、源文件等。文件是數據源的一種,最主要的作用是保存數據。
在操作系統中,為了統一對各種硬件的操作,簡化接口,不同的硬件設備也都被看成一個文件。對這些文件的操作,等同于對磁盤上普通文件的操作。例如:
* 通常把顯示器稱為標準輸出文件,printf 就是向這個文件輸出數據;
* 通常把鍵盤稱為標準輸入文件,scanf 就是從這個文件讀取數據。

操作文件的正確流程為:`打開文件 --> 讀寫文件 --> 關閉文件`。文件在進行讀寫操作之前要先打開,使用完畢要關閉。
所謂打開文件,就是獲取文件的有關信息,例如文件名、文件狀態、當前讀寫位置等,這些信息會被保存到一個 FILE 類型的結構體變量中。關閉文件就是斷開與文件之間的聯系,釋放結構體變量,同時禁止再對該文件進行操作。
在C語言中,文件有多種讀寫方式,可以一個字符一個字符地讀取,也可以讀取一整行,還可以讀取若干個字節。文件的讀寫位置也非常靈活,可以從文件開頭讀取,也可以從中間位置讀取。
# 文件流
所有的文件(保存在磁盤)都要載入內存才能處理,所有的數據必須寫入文件(磁盤)才不會丟失。數據在文件和內存之間傳遞的過程叫做文件流,類似水從一個地方流動到另一個地方。數據從文件復制到內存的過程叫做輸入流,從內存保存到文件的過程叫做輸出流。
文件是數據源的一種,除了文件,還有數據庫、網絡、鍵盤等;數據傳遞到內存也就是保存到C語言的變量(例如整數、字符串、數組、緩沖區等)。我們把數據在數據源和程序(內存)之間傳遞的過程叫做數據流(Data Stream)。相應的,數據從數據源到程序(內存)的過程叫做輸入流(Input Stream),從程序(內存)到數據源的過程叫做輸出流(Output Stream)。
輸入輸出(Input output,IO)是指程序(內存)與外部設備(鍵盤、顯示器、磁盤、其他計算機等)進行交互的操作。幾乎所有的程序都有輸入與輸出操作,如從鍵盤上讀取數據,從本地或網絡上的文件讀取數據或寫入數據等。通過輸入和輸出操作可以從外界接收信息,或者是把信息傳遞給外界。
我們可以說,打開文件就是打開了一個流。
# 文本文件和二進制文件區別
根據我們以往的經驗,文本文件通常用來保存肉眼可見的字符,比如`.txt`文件、`.c`文件、`.dat`文件等,用文本編輯器打開這些文件,我們能夠順利看懂文件的內容。
二進制文件通常用來保存視頻、圖片、程序等不可閱讀的內容,用文本編輯器打開這些文件,會看到一堆亂碼,根本看不懂。
但是從物理上講,二進制文件和字符文件并沒有什么區別,它們都是以二進制的形式保存在磁盤上的數據。
我們之所以能看懂文本文件的內容,是因為文本文件中采用的是 ASCII、UTF-8、GBK 等字符編碼,文本編輯器可以識別出這些編碼格式,并將編碼值轉換成字符展示出來。
而二進制文件使用的是 mp4、gif、exe 等特殊編碼格式,文本編輯器并不認識這些編碼格式,只能按照字符編碼格式胡亂解析,所以就成了一堆亂七八糟的字符,有的甚至都沒見過。
如果我們新建一個 mp4 文件,給它寫入一串字符,然后再用文本編輯器打開,你一樣可以讀得懂,有興趣的讀者可以自己試試。
總起來說,不同類型的文件有不同的編碼格式,必須使用對應的程序(軟件)才能正確解析,否則就是一堆亂碼,或者無法使用。
# fopen() 中的文本方式和二進制方式
在C語言中,二進制方式很簡單,讀取文件時,會原封不動的讀出文件的全部內容,寫入數據時,也是把緩沖區中的內容原封不動的寫到文件中。
文本方式和二進制方式并沒有本質上的區別,只是對于換行符的處理不同。
C語言程序將`\n`作為換行符,類 UNIX/Linux 系統在處理文本文件時也將`\n`作為換行符,所以程序中的數據會原封不動地寫入文本文件中,反之亦然。
但是 Windows 系統卻不同,它將`\r\n`作為文本文件的換行符。
在 Windows 系統中,如果以文本方式打開文件,當讀取文件時,程序會將文件中所有的`\r\n`轉換成一個字符`\n`。也就是說,如果文本文件中有連續的兩個字符是`\r\n`,則程序會丟棄前面的`\r`,只讀入`\n`。
當寫入文件時,程序會將`\n`轉換成`\r\n`寫入。也就是說,如果要寫入的內容中有字符`\n`,則在寫入該字符前,程序會自動先寫入一個`\r`。
因此,如果用文本方式打開二進制文件進行讀寫,讀寫的內容就可能和文件的內容有出入。
總起來說,對于 Windows 平臺,為了保險起見,我們最好用`"r"`來打開文本文件,用`"b"`來打開二進制文件。對于 Linux 平臺,使用`"r"`還是`"b"`都無所謂,既然默認是`"r"`,那我們什么都不寫就行了。
- c語言
- 基礎知識
- 變量和常量
- 宏定義和預處理
- 隨機數
- register變量
- errno全局變量
- 靜態變量
- 類型
- 數組
- 類型轉換
- vs中c4996錯誤
- 數據類型和長度
- 二進制數,八進制數和十六進制數
- 位域
- typedef定義類型
- 函數和編譯
- 函數調用慣例
- 函數進棧和出棧
- 函數
- 編譯
- sizeof
- main函數接收參數
- 宏函數
- 目標文件和可執行文件有什么
- 強符號和弱符號
- 什么是鏈接
- 符號
- 強引用和弱引用
- 字符串處理函數
- sscanf
- 查找子字符串
- 字符串指針
- qt
- MFC
- 指針
- 簡介
- 指針詳解
- 案例
- 指針數組
- 偏移量
- 間接賦值
- 易錯點
- 二級指針
- 結構體指針
- 字節對齊
- 函數指針
- 指針例子
- main接收用戶輸入
- 內存布局
- 內存分區
- 空間開辟和釋放
- 堆空間操作字符串
- 內存處理函數
- 內存分頁
- 內存模型
- 棧
- 棧溢出攻擊
- 內存泄露
- 大小端存儲法
- 寄存器
- 結構體
- 共用體
- 枚舉
- 文件操作
- 文件到底是什么
- 文件打開和關閉
- 文件的順序讀寫
- 文件的隨機讀寫
- 文件復制
- FILE和緩沖區
- 文件大小
- 插入,刪除,更改文件內容
- typeid
- 內部鏈接和外部鏈接
- 動態庫
- 調試器
- 調試的概念
- vs調試
- 多文件編程
- extern關鍵字
- 頭文件規范
- 標準庫以及標準頭文件
- 頭文件只包含一次
- static
- 多線程
- 簡介
- 創建線程threads.h
- 創建線程pthread
- gdb
- 簡介
- mac使用gdb
- setjump和longjump
- 零拷貝
- gc
- 調試器原理
- c++
- c++簡介
- c++對c的擴展
- ::作用域運算符
- 名字控制
- cpp對c的增強
- const
- 變量定義數組
- 盡量以const替換#define
- 引用
- 內聯函數
- 函數默認參數
- 函數占位參數
- 函數重載
- extern "C"
- 類和對象
- 類封裝
- 構造和析構
- 深淺拷貝
- explicit關鍵字
- 動態對象創建
- 靜態成員
- 對象模型
- this
- 友元
- 單例
- 繼承
- 多態
- 運算符重載
- 賦值重載
- 指針運算符(*,->)重載
- 前置和后置++
- 左移<<運算符重載
- 函數調用符重載
- 總結
- bool重載
- 模板
- 簡介
- 普通函數和模板函數調用
- 模板的局限性
- 類模板
- 復數的模板類
- 類模板作為參數
- 類模板繼承
- 類模板類內和類外實現
- 類模板和友元函數
- 類模板實現數組
- 類型轉換
- 異常
- 異常基本語法
- 異常的接口聲明
- 異常的棧解旋
- 異常的多態
- 標準異常庫
- 自定義異常
- io
- 流的概念和類庫結構
- 標準io流
- 標準輸入流
- 標準輸出流
- 文件讀寫
- STL
- 簡介
- string容器
- vector容器
- deque容器
- stack容器
- queue容器
- list容器
- set/multiset容器
- map/multimap容器
- pair對組
- 深淺拷貝問題
- 使用時機
- 常用算法
- 函數對象
- 謂詞
- 內建函數對象
- 函數對象適配器
- 空間適配器
- 常用遍歷算法
- 查找算法
- 排序算法
- 拷貝和替換算法
- 算術生成算法
- 集合算法
- gcc
- GDB
- makefile
- visualstudio
- VisualAssistX
- 各種插件
- utf8編碼
- 制作安裝項目
- 編譯模式
- 內存對齊
- 快捷鍵
- 自動補全
- 查看c++類內存布局
- FFmpeg
- ffmpeg架構
- 命令的基本格式
- 分解與復用
- 處理原始數據
- 錄屏和音
- 濾鏡
- 水印
- 音視頻的拼接與裁剪
- 視頻圖片轉換
- 直播
- ffplay
- 常見問題
- 多媒體文件處理
- ffmpeg代碼結構
- 日志系統
- 處理流數據
- linux
- 系統調用
- 常用IO函數
- 文件操作函數
- 文件描述符復制
- 目錄相關操作
- 時間相關函數
- 進程
- valgrind
- 進程通信
- 信號
- 信號產生函數
- 信號集
- 信號捕捉
- SIGCHLD信號
- 不可重入函數和可重入函數
- 進程組
- 會話
- 守護進程
- 線程
- 線程屬性
- 互斥鎖
- 讀寫鎖
- 條件變量
- 信號量
- 網絡
- 分層模型
- 協議格式
- TCP協議
- socket
- socket概念
- 網絡字節序
- ip地址轉換函數
- sockaddr數據結構
- 網絡套接字函數
- socket模型創建流程圖
- socket函數
- bind函數
- listen函數
- accept函數
- connect函數
- C/S模型-TCP
- 出錯處理封裝函數
- 多進程并發服務器
- 多線程并發服務器
- 多路I/O復用服務器
- select
- poll
- epoll
- epoll事件
- epoll例子
- epoll反應堆思想
- udp
- socket IPC(本地套接字domain)
- 其他常用函數
- libevent
- libevent簡介