#(37):文本文件讀寫
上一章我們介紹了有關二進制文件的讀寫。二進制文件比較小巧,卻不是人可讀的格式。而文本文件是一種人可讀的文件。為了操作這種文件,我們需要使用`QTextStream`類。`QTextStream`和`QDataStream`的使用類似,只不過它是操作純文本文件的。另外,像 XML、HTML 這種,雖然也是文本文件,可以由`QTextStream`生成,但 Qt 提供了更方便的 XML 操作類,這里就不包括這部分內容了。
`QTextStream`會自動將 Unicode 編碼同操作系統的編碼進行轉換,這一操作對開發人員是透明的。它也會將換行符進行轉換,同樣不需要自己處理。`QTextStream`使用 16 位的`QChar`作為基礎的數據存儲單位,同樣,它也支持 C++ 標準類型,如 int 等。實際上,這是將這種標準類型與字符串進行了相互轉換。
`QTextStream`同`QDataStream`的使用基本一致,例如下面的代碼將把“The answer is 42”寫入到 file.txt 文件中:
~~~
QFile data("file.txt");
if (data.open(QFile::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&data);
out << "The answer is " << 42;
}
~~~
這里,我們在`open()`函數中增加了`QIODevice::Truncate`打開方式。我們可以從下表中看到這些打開方式的區別:
| 枚舉值 | 描述 |
| -- | -- |
| QIODevice::NotOpen | 未打開 |
| QIODevice::ReadOnly | 以只讀方式打開 |
| QIODevice::WriteOnly | 以只寫方式打開 |
| QIODevice::ReadWrite | 以讀寫方式打開 |
| QIODevice::Append | 以追加的方式打開,新增加的內容將被追加到文件末尾 |
| QIODevice::Truncate | 以重寫的方式打開,在寫入新的數據時會將原有數據全部清除,游標設置在文件開頭。 |
| QIODevice::Text | 在讀取時,將行結束符轉換成 \n;在寫入時,將行結束符轉換成本地格式,例如 Win32 平臺上是 \r\n |
| QIODevice::Unbuffered | 忽略緩存 |
我們在這里使用了`QFile::WriteOnly | QIODevice::Truncate`,也就是以只寫并且覆蓋已有內容的形式操作文件。注意,`QIODevice::Truncate`會直接將文件內容清空。
雖然`QTextStream`的寫入內容與`QDataStream`一致,但是讀取時卻會有些困難:
~~~
QFile data("file.txt");
if (data.open(QFile::ReadOnly)) {
QTextStream in(&data);
QString str;
int ans = 0;
in >> str >> ans;
}
~~~
在使用`QDataStream`的時候,這樣的代碼很方便,但是使用了`QTextStream`時卻有所不同:讀出的時候,str 里面將是 The answer is 42,ans 是 0。這是因為以文本形式寫入數據,是沒有數據之間的分隔的。還記得我們前面曾經說過,使用`QDataStream`寫入的時候,實際上會在要寫入的內容前面,額外添加一個這段內容的長度值。而文本文件則沒有類似的操作。因此,使用文本文件時,很少會將其分割開來讀取,而是使用諸如`QTextStream::readLine()`讀取一行,使用`QTextStream::readAll()`讀取所有文本這種函數,之后再對獲得的`QString`對象進行處理。
默認情況下,`QTextStream`的編碼格式是 Unicode,如果我們需要使用另外的編碼,可以使用
~~~
stream.setCodec("UTF-8");
~~~
這樣的函數進行設置。
另外,為方便起見,`QTextStream`同`std::cout`一樣提供了很多描述符,被稱為 stream manipulators。因為文本文件是供人去讀的,自然需要良好的格式(相比而言,二進制文件就沒有這些問題,只要數據準確就可以了)。這些描述符是一些函數的簡寫,我們可以從文檔中找到:
| 描述符 | 等價于 |
| -- | -- |
| `bin` | `setIntegerBase(2)` |
| `oct` | `setIntegerBase(8)` |
| `dec` | `setIntegerBase(10)` |
| `hex` | `setIntegerBase(16)` |
| `showbase` | `setNumberFlags(numberFlags() | ShowBase)` |
| `forcesign` | `setNumberFlags(numberFlags() | ForceSign)` |
| `forcepoint` | `setNumberFlags(numberFlags() | ForcePoint)` |
| `noshowbase` | `setNumberFlags(numberFlags() & ~ShowBase)` |
| `noforcesign` | `setNumberFlags(numberFlags() & ~ForceSign)` |
| `noforcepoint` | `setNumberFlags(numberFlags() & ~ForcePoint)` |
| `uppercasebase` | `setNumberFlags(numberFlags() | UppercaseBase)` |
| `uppercasedigits` | `setNumberFlags(numberFlags() | UppercaseDigits)` |
| `lowercasebase` | `setNumberFlags(numberFlags() & ~UppercaseBase)` |
| `lowercasedigits` | `setNumberFlags(numberFlags() & ~UppercaseDigits)` |
| `fixed` | `setRealNumberNotation(FixedNotation)` |
| `scientific` | `setRealNumberNotation(ScientificNotation)` |
| `left` | `setFieldAlignment(AlignLeft)` |
| `right` | `setFieldAlignment(AlignRight)` |
| `center` | `setFieldAlignment(AlignCenter)` |
| `endl` | `operator<<('\n')`和`flush()` |
| `flush` | `flush()` |
| `reset` | `reset()` |
| `ws` | `skipWhiteSpace()` |
| `bom` | `setGenerateByteOrderMark(true)` |
這些描述符只是一些函數的簡寫。例如,我們想要輸出 12345678 的二進制形式,那么可以直接使用
~~~
out << bin << 12345678;
~~~
就可以了。這等價于
~~~
out.setIntegerBase(2);
out << 12345678;
~~~
更復雜的,如果我們想要舒服 1234567890 的帶有前綴、全部字母大寫的十六進制格式(0xBC614E),那么只要使用
~~~
out << showbase << uppercasedigits << hex << 12345678;
~~~
即可。
不僅是`QIODevice`,`QTextStream`也可以直接把內容輸出到`QString`。例如
~~~
QString str;
QTextStream(&str) << oct << 31 << " " << dec << 25 << endl;
~~~
這提供了一種簡單的處理字符串內容的方法。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)