從輸入流中讀入原始C風格的數組並不像對operator>>()
的簡單調用那麼習慣。您還必須通過跟蹤爲緩衝區分配的字節和正在讀入緩衝區的字節來防止緩衝區溢出。
讀入緩衝區可以通過使用輸入流方法getline()
來完成。以下示例顯示提取到x1.name
;同樣會爲x1.path
來完成:
if (std::cin.getline(x1.name, sizeof(x1.name))) {
}
第二個參數是要讀取的字節的最大數量。這是有用的,因爲流不會寫入數組的分配邊界。接下來要做的事情只是將其寫入文件,你所做的:
if (std::cin.getline(x1.name, sizeof(x1.name))) {
inout.write(reinterpret_cast<char*>(&x1.name), std::cin.gcount());
}
std::cin.gcount()
是從輸入流中讀取的字符數。這是sizeof(x1.name)
的更可靠的替代方案,它返回的字符數寫入,而不是分配的字符數。
現在,雙向文件流有點棘手。他們以正確的方式進行協調。正如其他答案中所解釋的,雙向文件流(或std::fstream
s)共享輸入和輸出的聯合緩衝區。標記輸入和輸出序列中位置的位置指示器都受可能發生的任何輸入和輸出操作的影響。因此,在執行輸入之前,必須將文件流位置「移回」。這可以通過致電seekg()
或seekp()
來完成。因爲無論是就足夠了,正如我所說,位置指示器相互結合:
if (std::cin.getline(x1.pass, sizeof(x1.pass))) {
inout.write(reinterpret_cast<char*>(&x1.pass), std::cin.gcount());
inout.seekg(0, std::ios_base::beg);
}
注意如何被提取後進行到x1.pass
。我們無法在x1.name
之後執行此操作,因爲我們將在第二次調用時覆蓋流write()
。你可以看到,提取到原始C風格的數組並不美觀,你必須管理更多的東西,而不是你應該做的。幸運的是,C++用標準字符串類std::string
來拯救。使用此更高效的I/O:
使標準C++字符串(std::string
)與name
和pass
都取代原始C數組。這允許您在作爲第二個參數傳遞給您的read()
和write()
電話:
#include <string>
struct x {
std::string name;
std::string pass;
};
// ...
if (std::cin >> x1.name) {
inout.write(x1.name.data(), x1.name.size());
}
if (std::cin >> x1.pass) {
inout.write(x1.name.data(), x1.name.size());
inout.seekg(0, std::ios_base::beg);
}
std::string
使我們能夠利用它的動態性質及其對維護緩衝區的容量大小。我們不再需要使用getline()
,而是現在只需撥打operator>>()
和if()
支票。
這是不可能的,但現在我們正在使用std::string
我們還可以結合兩種提取實現如下:
if (std::cout << "Enter your name: " && std::cin >> x1.name &&
std::cout << "Enter your pass: " && std::cin >> x1.pass) {
inout.write(x1.name.data(), x1.name.size());
inout.write(x1.pass.data(), x1.pass.size());
inout.seekg(0, std::ios_base::beg);
}
最後,上次提取,簡直是這樣的:
while (inout >> x2.name)
{
std::cout << x2.name;
}
你得到的錯誤是什麼? – 0x499602D2
沒有錯誤,我沒有在屏幕上看到任何東西! – elika
'test.dat'是一個預先存在的文件嗎? – 0x499602D2