C++讀寫檔案

DawnTraveler發表於2024-04-03

1.問題

C++如何快速方便的讀寫檔案?

2.解決

參考:C/C++ 檔案讀寫

2.1 使用freopen

•C中的檔案讀寫-freopen

函式簡介

  freopen 是被包含於 C標準庫標頭檔案 stdio.h 中的一個函式,用於重定向輸入輸出流。

  該函式可以在不改變程式碼原貌的情況下改變輸入輸出環境,但使用時應當保證流是可靠的。

函式宣告

*FILE freopen(const char* _FileName, const char* _Mode, FILE* _Stream );

  • _FileName:需要重定向的檔名或檔案路徑

  • _Mode:代表檔案訪問許可權的字串

  • "r" 表示 只讀訪問

  • "w" 表示 只寫訪問

  • "a" 表示 追加寫入

  • _Stream:需要被重定向的檔案流

    • stdin:表示輸入重定向(從指定檔案中讀取資料到程式中)
    • stdout:表示輸出重定向(將程式中輸出的資料輸入到指定檔案中)
  • 返回值:如果成功,則返回指向該輸出流的檔案指標,否則返回為NULL

測試輸出重定向(寫檔案)

  新建一個專案,並命名為檔案讀寫;

  在該專案中建立一個 C中的檔案讀寫.c 檔案,並新增如下程式碼:

#include<stdio.h>
#define FILENAME "FILEC.txt"//檔名

void write()
{
    freopen(FILENAME, "w", stdout);

    printf("測試向FILEC.txt中寫檔案\\n");
}
int main()
{
    write();

    return 0;
}

  執行該程式碼,你會發現,在專案檔案讀寫的資料夾下多出一個 FILEC.txt 的檔案,開啟該檔案,你會驚奇的發現,該檔案的內容就是你在程式中透過 printf 輸出的語句。

  透過程式碼可以看出,freopen 函式只出現在了 write() 函式中,那麼如果在主函式中輸出 "Hello World",會輸出到哪裡呢?

  讓我們透過程式碼來測試一下。

void write()
{
    freopen(FILENAME, "w", stdout);

    printf("測試向FILEC.txt中寫檔案\\n");
}
int main()
{
    printf("TEST1 : Hello World\\n");
    write();
    printf("TEST2 : Hello World\\n");

    return 0;
}

  執行該程式碼,你會發現,在控制檯只輸出了 "TEST1 : Hello World":

  少的那一句呢?

  莫非是輸出到 FILEC.txt 中了,讓我們一探究竟。

  果然在這裡,透過這個測試,就能發現,在語句 freopen(FILENAME, "w", stdout); 呼叫後,所有的輸出語句都寫到了 FILEC.txt 中。

  C 語言中提供了檔案讀寫的關閉語句 fclose(stdout) ,那可不可以透過該語句實現隨開隨關呢?

  讓我們嘗試在 write() 中使用該語句。

void write()
{
    freopen(FILENAME, "w", stdout);

    printf("測試向FILEC.txt中寫檔案\\n");

    fclose(stdout);
}
int main()
{
    printf("TEST1 : Hello World\\n");
    write();
    printf("TEST2 : Hello World\\n");

    return 0;
}

  讓我們來執行一下修改後的程式。

執行結果

  在 VS2022 上,直接報錯了:

  而在 CodeBlocks 中測試,成功執行了:

  但是, FILEC.txt 檔案中卻丟失了 printf("TEST2 : Hello World\n"); 語句的輸出結果:

  所以,透過測試可知,並不能透過 fclose(stdout); 語句實現隨開隨關 ,正確的寫法應該是:

#include<stdio.h>
#define FILENAME "FILEC.txt"//檔名

void write()
{
    freopen(FILENAME, "w", stdout);

    printf("測試向FILEC.txt中寫檔案\\n");
}
int main()
{
    printf("TEST1 : Hello World\\n");

    write();

    printf("TEST2 : Hello World\\n");

    fclose(stdout);//放置到程式結尾處
    return 0;
}

測試輸入重定向(讀檔案)

  在程式所在目錄下新建一個 Input.txt 檔案,並輸入如下資訊:

  執行如下程式碼:

#include<stdio.h>
#define FILENAME "Input.txt"

int main()
{
    freopen(FILENAME,"r",stdin);//讀檔案
    
    char s\[100\];
    while (scanf("%s", s) != EOF)
        puts(s);
    
    return 0;
}

  執行該程式,你會發現,並不需要輸入任何資料:

  控制檯輸出的內容剛好是 Input.txt 中的內容。

  • scanf("%s", s) != EOF 表示的是讀取到檔案結尾
  • FILENAME 也可以換成 Input.txt 的具體路徑

E:\\Documents\\Visual Studio for C++\\檔案讀寫\\檔案讀寫\\Input.txt

  • 其中,路徑中的 "\\" 可以換成 '/',但不能是 '\'

  同理,我們也可以用 fclose(stdin); 來關閉該輸入流,但同輸出流一樣,應該放到程式結尾出:

#include<stdio.h>
#define FILENAME "Input.txt"

int main()
{
    freopen(FILENAME,"r",stdin);//讀檔案
    
    char s\[100\];
    while (scanf("%s", s) != EOF)
        puts(s);
    
    fclose(stdin);//放到程式結尾處
    return 0;
}

•C++中的檔案讀寫-fstream

函式簡介

  C++中對檔案操作需要包含標頭檔案 (file stream,檔案流)。

  • ofstream:寫操作(output file stream)
  • ifstream: 讀操作(input file stream)
  • fstream : 讀寫操作(file stream)

寫檔案

步驟

  • 建立流物件:ofstream ofs;
  • 開啟檔案:ofs.open("檔名/檔案路徑",開啟方式);
  • 寫資料:ofs << "寫入的資料"; (將 cout 改為 ofs)
  • 關閉檔案:ofs.close();

檔案開啟方式

  • ios::out :為寫檔案而開啟檔案
  • ios::app :追加方式寫檔案

  在程式碼所在的資料夾下新建一個 FILEC++.txt 檔案,新增如下資料:

  並執行如下程式碼:

#include<iostream>
#include<fstream>//包含標頭檔案
using namespace std;
#define FILENAME "FILEC++.txt"
void write()
{
    ofstream ofs;//建立流物件
    ofs.open(FILENAME, ios::out);//開啟檔案
    ofs << "測試向FILEC++.txt中寫檔案" << endl;//寫資料
    ofs.close();//關閉檔案
}
int main()
{
    write();

    return 0;
}

  開啟 FILEC++.txt 檢視檔案內容變化。

  你會發現,透過 ios::out 方式開啟檔案,之前的內容被覆蓋了。

  更改檔案開啟方式:

void write()
{
    ofstream ofs;//建立流物件
    ofs.open(FILENAME, ios::app);//開啟檔案
    ofs << "測試向FILEC++.txt中寫檔案-2.0" << endl;//寫資料
    ofs.close();//關閉檔案
}  

  檢視 FILEC++.txt 中的內容:

  可以測試出, ios::app 是在原檔案的基礎上向後追加內容。

  由於是透過建立 ofs 來進行寫檔案操作,那麼原本的輸出語句就不會報錯。

#include<iostream>
#include<fstream>//包含標頭檔案
using namespace std;
#define FILENAME "FILEC++.txt"

void write()
{
    ofstream ofs;//建立流物件
    ofs.open(FILENAME, ios::out);//開啟檔案
    ofs << "測試向FILEC++.txt中寫檔案" << endl;//寫資料
    ofs.close();//關閉檔案
}
int main()
{
    cout << "TEST1 : Hello World" << endl;
    write();
    cout << "TEST2 : Hello World" << endl;
    return 0;
}

  執行結果:

   FILEC++.txt :

  可見,透過 ofstream 來進行寫檔案操作,並不會影響 cout 的輸出。

讀檔案

步驟

  • 建立流物件: ifstream ifs;
  • 開啟檔案: ifs.open("檔案路徑",開啟方式);
  • 判斷檔案是否開啟成功: ifs.is_open() (成功開啟返回 true,否則返回 false)
  • 讀資料: ifs >> 變數1 >> 變數2 >> ...; (類比 cin)
  • 關閉檔案: ifs.close();

示例

  在當前程式碼所在資料夾下新建一個 Input.txt 的檔案,並放入如下資料:

  分別代表:編號、姓名、年齡,並用 id , name , age 接受這三個資料。

#include<iostream>
#include<fstream>//包含標頭檔案
using namespace std;
#define FILENAME "Input.txt"

void read()
{
    ifstream ifs;//建立流物件
    ifs.open(FILENAME, ios::in);//開啟檔案

    int id;
    string name;
    int age;

    if (!ifs.is\_open())//判斷檔案是否開啟成功
    {
        cout << "檔案開啟失敗" << endl;
        return;
    }

    ifs \>> id >> name >> age;//讀資料,且 編號、姓名、年齡 要和檔案中的資料保持一致
    cout << "編號\\t姓名\\t年齡" << endl;
    cout << id << "\\t" << name << "\\t" << age << endl;

    ifs.close();//關閉檔案

    return;
}
int main()
{
    read();

    return 0;
}

  執行結果:

相關文章