C++ 讀檔,讀取txt文字檔各種範例

本篇 ShengYu 介紹 C++ 讀檔,讀取txt文字檔各種範例,C++ 讀檔是寫程式中很基礎且實用的技巧,尤其是讀取文字檔再作後續的處理算是很常會用到的功能,
以下 C++ 讀取文字檔的介紹內容將分為這幾部份,

  • C++ std::ifstream 讀取文字檔到 C-Style 陣列裡
  • C++ 一次讀取全部文字檔到 string 裡
  • C++ 一次一行逐行讀取到 C-Style 陣列裡
  • C++ 一次一行逐行讀取到 vector<string>

C++ std::ifstream 讀取文字檔到 C-Style 陣列裡

先來示範最簡單的讀取文字檔,建立完 ifstream 後使用 ifstream::open() 來開檔,之後使用 ifstream::read() 一次讀取全部文字檔,參數帶入 buffer 陣列以及要讀取的數量,要讀取的數量不能超過 buffer 的陣列大小,當然你也可以自行控制要讀取的數量,這邊只是示範讀取全部內容,

假如我們的文字檔長這樣

input.txt
1
2
Hello world
This is a input text example

讀進來後放到 buffer 後,這邊很簡單的用 cout 把它印出來,程式碼長這樣,

cpp-txt-read.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-txt-read.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs;
char buffer[256] = {0};

ifs.open("input.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

ifs.read(buffer, sizeof(buffer));
cout << buffer;
ifs.close();
return 0;
}

那麼會獲得這樣的執行結果,

1
2
Hello world
This is a input text example

上述例子是用 ifstream::open() 開檔,開檔時你也可以改使用 fstream::open(),然後再指定模式是 std::ios::in 就可以了,

1
2
3
std::fstream ifs;
ifs.open("output.txt", std::ios::in);
// ...

另外 txt 文字檔是放在資料下的話,不同作業系統下寫法稍有不同,
在 Windows 系統中 input.txt 放在 mydir 資料下的話,就這樣寫

1
ifs.open("mydir\\input.txt");

在 Linux 或 macOS 系統中 input.txt 放在 mydir 資料下的話,就這樣寫

1
ifs.open("mydir/input.txt");

C++ 一次讀取全部文字檔到 string 裡

這邊示範 C++ 將文字檔內容一次讀進 string 容器裡,開檔跟上個範例不同的是這次我們在 ifstream 建構時一併開檔,

第一種方法為先將 ifs.rdbuf() 串流到 stringstream ss 裡,再用 ss.str() 轉換成 std::string

cpp-txt-read2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// g++ cpp-txt-read2.cpp -o a.out
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main() {
std::ifstream ifs("input.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1;
}

std::stringstream ss;
ss << ifs.rdbuf();
std::string str(ss.str());
cout << str;
ifs.close();
return 0;
}

第二種方法是使用 istreambuf_iterator 的方式,再建立 std::string
要注意的是 std::string str() 第一個引數裡有多一對 () 小括號,否則結果會截然不同,

cpp-txt-read3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// g++ cpp-txt-read3.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs("input.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1;
}

std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
cout << str;
ifs.close();
return 0;
}

C++ 一次一行逐行讀取到 C-Style 陣列裡

這次使用 ifstream::getline() 取得一行的檔案資料放入 C-Style 陣列,搭配 while 迴圈逐行讀入 C-Style 陣列直到檔尾,每一次的 getline 都會覆蓋之前的 buffer 資料而不是添加在後面,

cpp-txt-read4.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// g++ cpp-txt-read4.cpp -o a.out
#include <iostream>
#include <fstream>
using namespace std;

int main() {
std::ifstream ifs;
char buffer[256] = {0};

ifs.open("input.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

while (!ifs.eof()) {
ifs.getline(buffer, sizeof(buffer));
cout << buffer << "\n";
}
ifs.close();
return 0;
}

C++ 一次一行逐行讀取到 vector<string>

那我們來個實際的例子,假如我們讀取一個txt文字檔裡面有學生姓名,txt文字檔內容如下,

input2.txt
1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

程式碼如下,使用 std::getline() 將 std::ifstream 每次讀取一行的結果放到 std::string 裡,接著用 cout 印出來確認看看,有時候也會放入 vector 容器裡讓之後的程式作後續處理,所以這裡宣告成 vector<string>,這樣就可以一直放入多個 string,

cpp-txt-read5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// g++ cpp-txt-read5.cpp -o a.out
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main() {
std::vector<std::string> names;
std::ifstream ifs("input2.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

std::string s;
while (std::getline(ifs, s)) {
cout << s << "\n";
names.push_back(s);
}
ifs.close();
return 0;
}

根據上個範例,假如我們這次是讀入某一個科目的學生分數資料進行處理的話,這個txt文字檔裡面有學生姓名與學生分數,txt文字檔內容如下,

input2.txt
1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

那我們這次要見識一下 >> operator 流的威力,實做方法如下:

cpp-txt-read6.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// g++ cpp-txt-read6.cpp -o a.out
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

int main() {
std::vector<std::string> names;
std::vector<int> scores;
std::ifstream ifs("input3.txt", std::ios::in);
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
return 1; // EXIT_FAILURE
}

std::string name;
int score;
while (ifs >> name >> score) {
cout << name << " " << score << "\n";
names.push_back(name);
scores.push_back(score);
}
ifs.close();
return 0;
}

輸出結果如下,>> operator 還可以幫你轉換成你要的變數型態,就像範例中的 score,不用自己在那邊,一切自動轉換~~夠快速方便懶惰了吧!

1
2
3
4
Alan 75
John 95
Tony 60
Mary 80

那麼你可能會想問上面的範例是空白作分隔,那如果是 tab 作分隔呢?那如果是逗號作分隔呢?
關於這部分下次我再寫一篇給大家講解,

下一篇文章是 C++ 寫檔,寫入txt文字檔各種範例

其它相關文章推薦
C/C++ 新手入門教學懶人包
C/C++ 字串轉數字的4種方法
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例