標籤:
上一章我們介紹了有關二進位檔案的讀寫。二進位檔案比較小巧,卻不是人可讀的格式。而文字檔是一種人可讀的檔案。為了操作這種檔案,我們需要使用QTextStream類。QTextStream和QDataStream的使用類似,只不過它是操作純文字檔案的。另外,像 XML、HTML 這種,雖然也是文字檔,可以由QTextStream產生,但 Qt 提供了更方便的 XML 操作類,這裡就不包括這部分內容了。
QTextStream會自動將 Unicode 編碼同作業系統的編碼進行轉換,這一操作對開發人員是透明的。它也會將分行符號進行轉換,同樣不需要自己處理。QTextStream使用 16 位的QChar作為基礎的資料存放區單位,同樣,它也支援 C++ 標準類型,如 int 等。實際上,這是將這種標準類型與字串進行了相互轉換。
QTextStream同QDataStream的使用基本一致,例如下面的代碼將把“The answer is 42”寫入到 file.txt 檔案中:
| 12345 |
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一致,但是讀取時卻會有些困難:
| 1234567 |
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,如果我們需要使用另外的編碼,可以使用
| 1 |
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 的二進位形式,那麼可以直接使用
| 1 |
out << bin << 12345678; |
就可以了。這等價於
| 12 |
out.setIntegerBase(2);out << 12345678; |
更複雜的,如果我們想要舒服 1234567890 的帶有首碼、全部字母大寫的十六進位格式(0xBC614E),那麼只要使用
| 1 |
out << showbase << uppercasedigits << hex << 12345678; |
即可。
不僅是QIODevice,QTextStream也可以直接把內容輸出到QString。例如
| 12 |
QString str; QTextStream(&str) << oct << 31 << " " << dec << 25 << endl; |
這提供了一種簡單的處理字串內容的方法。
Qt 學習之路 :文字檔讀寫