C++ でファイル操作を行う

C++C++Beginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、C++ で様々なファイル操作を行う方法を学びます。この実験では、読み取りと書き込み用にファイルを開く方法、ファイルにテキストデータを書き込む方法、テキストファイルからデータを読み取る方法、ファイルの開き状態を確認する方法、ファイルの読み取り/書き込みエラーを処理する方法、バイナリファイルの操作方法、ファイルポインタの位置決め方法、およびファイルを閉じてリソースを解放する方法が扱われます。C++ 標準ライブラリの基本的なファイルストリームクラス ofstreamifstream を使ってファイルとやり取りする実際の経験を得ます。この実験が終了するとき、C++ プログラミングにおけるファイル操作について十分な理解を得ることができます。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("C++")) -.-> cpp/AdvancedConceptsGroup(["Advanced Concepts"]) cpp(("C++")) -.-> cpp/IOandFileHandlingGroup(["I/O and File Handling"]) cpp(("C++")) -.-> cpp/StandardLibraryGroup(["Standard Library"]) cpp(("C++")) -.-> cpp/BasicsGroup(["Basics"]) cpp(("C++")) -.-> cpp/ControlFlowGroup(["Control Flow"]) cpp/BasicsGroup -.-> cpp/strings("Strings") cpp/ControlFlowGroup -.-> cpp/if_else("If...Else") cpp/AdvancedConceptsGroup -.-> cpp/pointers("Pointers") cpp/AdvancedConceptsGroup -.-> cpp/structures("Structures") cpp/AdvancedConceptsGroup -.-> cpp/exceptions("Exceptions") cpp/IOandFileHandlingGroup -.-> cpp/output("Output") cpp/IOandFileHandlingGroup -.-> cpp/files("Files") cpp/StandardLibraryGroup -.-> cpp/string_manipulation("String Manipulation") subgraph Lab Skills cpp/strings -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/if_else -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/pointers -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/structures -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/exceptions -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/output -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/files -.-> lab-446086{{"C++ でファイル操作を行う"}} cpp/string_manipulation -.-> lab-446086{{"C++ でファイル操作を行う"}} end

ofstream と ifstream を使ってファイルを開く

このステップでは、C++ でファイルを開く方法を学びます。2 つの基本的なファイルストリームクラスを使って行います。書き込み用の ofstream と読み取り用の ifstream です。これらのクラスは C++ 標準ライブラリの一部で、重要なファイル操作機能を提供します。

まず、WebIDE のターミナルでプロジェクトディレクトリに移動します。

cd ~/project

file_operations.cpp という新しい C++ ファイルを作成します。

touch file_operations.cpp

file_operations.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>  // ファイルストリームヘッダをインクルード

int main() {
    // ofstream を使って書き込み用にファイルを開く
    std::ofstream outputFile("example.txt");

    // ファイルが正常に開いたかどうかを確認する
    if (outputFile.is_open()) {
        std::cout << "File opened for writing successfully!" << std::endl;
        outputFile.close();  // ファイルを閉じる
    } else {
        std::cout << "Unable to open file for writing." << std::endl;
    }

    // ifstream を使って読み取り用にファイルを開く
    std::ifstream inputFile("example.txt");

    // ファイルが正常に開いたかどうかを確認する
    if (inputFile.is_open()) {
        std::cout << "File opened for reading successfully!" << std::endl;
        inputFile.close();  // ファイルを閉じる
    } else {
        std::cout << "Unable to open file for reading." << std::endl;
    }

    return 0;
}

重要な概念を解説しましょう。

  1. #include <fstream>:ファイルストリームライブラリをインクルードします。
  2. std::ofstream:ファイルに書き込むための出力ファイルストリーム
  3. std::ifstream:ファイルから読み取るための入力ファイルストリーム
  4. is_open():ファイルが正常に開いたかどうかを確認します。
  5. close():操作後にファイルを閉じます。

プログラムをコンパイルします。

g++ file_operations.cpp -o file_operations

実行可能ファイルを実行します。

./file_operations

出力例:

File opened for writing successfully!
File opened for reading successfully!

ファイルストリームに関する重要なポイント:

  • 操作を行う前に必ずファイルが正常に開いたかどうかを確認してください。
  • 使用が終わったら必ずファイルを閉じてください。
  • ofstream はファイルに書き込むために使用します。
  • ifstream はファイルから読み取るために使用します。
  • 両クラスは <fstream> ヘッダの一部です。

ファイルストリームを、ファイルのドアを開けたり閉めたりするように考えることができます。ofstream は部屋に書き込むことができ、ifstream は中身を読むことができます。

ファイルにテキストデータを書き込む

このステップでは、C++ の ofstream クラスを使ってファイルにテキストデータを書き込む方法を学びます。前のステップを基に、文字列を書き込む方法、数値を書き込む方法、複数行を書き込む方法を探ります。

write_files.cpp という新しい C++ ファイルを作成します。

touch ~/project/write_files.cpp

write_files.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>

int main() {
    // 書き込み用にファイルを開く
    std::ofstream outputFile("student_data.txt");

    // ファイルが正常に開いたかどうかを確認する
    if (outputFile.is_open()) {
        // 単一の文字列を書き込む
        outputFile << "John Doe" << std::endl;

        // 複数のデータを書き込む
        std::string name = "Alice Smith";
        int age = 22;
        double gpa = 3.75;
        outputFile << name << ", " << age << " years old, GPA: " << gpa << std::endl;

        // 複数行を書き込む
        outputFile << "Computer Science Student" << std::endl;
        outputFile << "University of Programming" << std::endl;

        // ファイルを閉じる
        outputFile.close();
        std::cout << "Data written to file successfully!" << std::endl;
    } else {
        std::cout << "Unable to open file for writing." << std::endl;
    }

    return 0;
}

プログラムをコンパイルします。

g++ write_files.cpp -o write_files

実行可能ファイルを実行します。

./write_files

出力例:

Data written to file successfully!

ファイルの内容を確認します。

cat student_data.txt

ファイルの内容例:

John Doe
Alice Smith, 22 years old, GPA: 3.75
Computer Science Student
University of Programming

ファイルに書き込む際の重要なポイント:

  • << 演算子を使ってファイルにデータを書き込む
  • std::endl は新しい行を追加する
  • 文字列、数値、変数を書き込める
  • 書き込み前に必ずファイルが開いているかどうかを確認する
  • 書き込み操作後にファイルを閉じる

ファイルに書き込むことをノートに書くことのように考えることができます。ofstream があなたのペンで、ファイルが情報を記録するページです。

テキストファイルからデータを読み取る

このステップでは、C++ の ifstream クラスを使ってテキストファイルからデータを読み取る方法を学びます。前のステップを基に、行、単語、ファイル全体を読み取るさまざまな方法を探ります。

read_files.cpp という新しい C++ ファイルを作成します。

touch ~/project/read_files.cpp

read_files.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>

int main() {
    // 前のステップで作成したファイルを開く
    std::ifstream inputFile("student_data.txt");

    // ファイルが正常に開いたかどうかを確認する
    if (inputFile.is_open()) {
        // 全行を読み取る
        std::string line;
        std::cout << "Reading entire lines:" << std::endl;
        while (std::getline(inputFile, line)) {
            std::cout << line << std::endl;
        }

        // ファイルポインタを先頭に戻す
        inputFile.clear();
        inputFile.seekg(0, std::ios::beg);

        // 個々の単語を読み取る
        std::cout << "\nReading individual words:" << std::endl;
        std::string word;
        while (inputFile >> word) {
            std::cout << word << " ";
        }
        std::cout << std::endl;

        // ファイルを閉じる
        inputFile.close();
    } else {
        std::cout << "Unable to open file for reading." << std::endl;
    }

    return 0;
}

プログラムをコンパイルします。

g++ read_files.cpp -o read_files

実行可能ファイルを実行します。

./read_files

出力例:

Reading entire lines:
John Doe
Alice Smith, 22 years old, GPA: 3.75
Computer Science Student
University of Programming

Reading individual words:
John Doe Alice Smith, 22 years old, GPA: 3.75 Computer Science Student University of Programming

ファイルを読み取る際の重要なポイント:

  • std::getline() を使って全行を読み取る
  • >> 演算子を使って個々の単語を読み取る
  • clear()seekg() でファイルポインタをリセットする
  • 読み取り前に必ずファイルが開いているかどうかを確認する
  • 読み取り操作後にファイルを閉じる

ファイルを読み取ることを本から情報を抽出することのように考えることができます。ifstream があなたのブックマークで、テキストを読み進めるのを助けます。

ファイルの開き状態を確認する

このステップでは、C++ でファイル操作の状態を確認する方法を学びます。ファイルが正常に開かれ、読み取りまたは書き込みが可能であるかどうかを検証するためのさまざまな方法を学びます。

file_status.cpp という新しい C++ ファイルを作成します。

touch ~/project/file_status.cpp

file_status.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>

int main() {
    // 既存のファイルを読み取り用に開こうとする
    std::ifstream inputFile("student_data.txt");

    // 方法 1:is_open() を使ってファイルの状態を確認する
    if (inputFile.is_open()) {
        std::cout << "File opened successfully for reading." << std::endl;

        // 読み取り操作を実行する
        std::string line;
        while (std::getline(inputFile, line)) {
            std::cout << "Read line: " << line << std::endl;
        }

        inputFile.close();
    } else {
        std::cout << "Failed to open file for reading." << std::endl;
    }

    // 方法 2:good() を使ってファイルの状態を確認する
    std::ofstream outputFile("test_status.txt");

    if (outputFile.good()) {
        std::cout << "File opened successfully for writing." << std::endl;
        outputFile << "Testing file status" << std::endl;

        // 追加の状態確認
        if (outputFile) {
            std::cout << "File is in a good state for writing." << std::endl;
        }

        outputFile.close();
    } else {
        std::cout << "Failed to open file for writing." << std::endl;
    }

    // 方法 3:複数の状態確認方法
    std::ifstream checkFile("non_existent_file.txt");

    std::cout << "File status checks:" << std::endl;
    std::cout << "is_open(): " << (checkFile.is_open()? "True" : "False") << std::endl;
    std::cout << "good(): " << (checkFile.good()? "True" : "False") << std::endl;
    std::cout << "fail(): " << (checkFile.fail()? "True" : "False") << std::endl;

    return 0;
}

プログラムをコンパイルします。

g++ file_status.cpp -o file_status

実行可能ファイルを実行します。

./file_status

出力例:

File opened successfully for reading.
Read line: John Doe
Read line: Alice Smith, 22 years old, GPA: 3.75
Read line: Computer Science Student
Read line: University of Programming
File opened successfully for writing.
File is in a good state for writing.
File status checks:
is_open(): False
good(): False
fail(): True

ファイルの状態確認に関する重要なポイント:

  • is_open():ファイルが正常に開かれたかどうかを確認する
  • good():エラーが発生していないかどうかを確認する
  • fail():エラーが発生したかどうかを確認する
  • 操作を行う前に必ずファイルの状態を確認する
  • さまざまな方法があり、ファイルの状態を検証するためのさまざまな方法を提供します

ファイルの状態確認を、旅の前の安全点検のように考えることができます。これらの方法は、ファイル操作が安全で成功することを確認するのに役立ちます。

ファイルの読み取り/書き込みエラーを処理する

このステップでは、C++ のファイル読み取りと書き込み操作中に発生する可能性のあるエラーをどのように処理するかを学びます。エラーハンドリングを理解することは、堅牢なファイル操作プログラムを作成するために重要です。

file_error_handling.cpp という新しい C++ ファイルを作成します。

touch ~/project/file_error_handling.cpp

file_error_handling.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>
#include <stdexcept>

void writeToFile(const std::string& filename) {
    std::ofstream outputFile(filename);

    // ファイルが開いているかどうかを確認する
    if (!outputFile) {
        // ファイルを開けない場合、例外を投げる
        throw std::runtime_error("Unable to open file for writing: " + filename);
    }

    try {
        // データを書き込もうとする
        outputFile << "Hello, Error Handling!" << std::endl;
        outputFile << "This is a sample text." << std::endl;

        // 書き込みエラーをシミュレートする(本来は推奨されない)
        if (outputFile.bad()) {
            throw std::runtime_error("Write operation failed");
        }
    }
    catch (const std::exception& e) {
        std::cerr << "Error during writing: " << e.what() << std::endl;
    }

    outputFile.close();
}

void readFromFile(const std::string& filename) {
    std::ifstream inputFile(filename);
    std::string line;

    // ファイルが開いているかどうかを確認する
    if (!inputFile) {
        // ファイルを開けない場合、例外を投げる
        throw std::runtime_error("Unable to open file for reading: " + filename);
    }

    try {
        // ファイルの内容を読み取り、表示する
        std::cout << "File contents:" << std::endl;
        while (std::getline(inputFile, line)) {
            std::cout << line << std::endl;
        }

        // 読み取りエラーを確認する
        if (inputFile.bad()) {
            throw std::runtime_error("Read operation encountered an error");
        }
    }
    catch (const std::exception& e) {
        std::cerr << "Error during reading: " << e.what() << std::endl;
    }

    inputFile.close();
}

int main() {
    try {
        // ファイルに書き込む
        writeToFile("error_handling_example.txt");

        // ファイルから読み取る
        readFromFile("error_handling_example.txt");

        // 存在しないファイルから読み取ろうとする
        readFromFile("non_existent_file.txt");
    }
    catch (const std::exception& e) {
        std::cerr << "Main error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

プログラムをコンパイルします。

g++ file_error_handling.cpp -o file_error_handling

実行可能ファイルを実行します。

./file_error_handling

出力例:

File contents:
Hello, Error Handling!
This is a sample text.
Error during reading: Unable to open file for reading: non_existent_file.txt

ファイルエラーハンドリングに関する重要なポイント:

  • 潜在的な例外を処理するために try-catch ブロックを使用する
  • 操作の前後でファイルストリームの状態を確認する
  • 意味のあるエラーメッセージを投げるために std::runtime_error を使用する
  • さまざまな種類のファイル関連のエラーを処理する
  • 情報的なエラーメッセージを提供する

エラーハンドリングを安全ネットのように考えることができます。潜在的な問題をキャッチし、プログラムが予期せずクラッシュするのを防ぎます。

fstream を使ってバイナリファイルを操作する

このステップでは、C++ の fstream クラスを使ってバイナリファイルを操作する方法を学びます。バイナリファイルは、データをそのままのバイナリ形式で保存します。これは、テキストファイルとは異なり、構造化データを効率的に保存するのに役立ちます。

binary_files.cpp という新しい C++ ファイルを作成します。

touch ~/project/binary_files.cpp

binary_files.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>

// バイナリファイルの書き込みを示すための単純な構造体
struct Student {
    int id;
    char name[50];
    double gpa;
};

void writeBinaryFile() {
    std::fstream binaryFile("students.bin", std::ios::out | std::ios::binary);

    if (!binaryFile) {
        std::cerr << "Error opening file for writing!" << std::endl;
        return;
    }

    // いくつかの学生レコードを作成する
    Student students[3] = {
        {1, "John Doe", 3.5},
        {2, "Alice Smith", 3.8},
        {3, "Bob Johnson", 3.2}
    };

    // 構造体全体をバイナリファイルに書き込む
    binaryFile.write(reinterpret_cast<char*>(students), sizeof(students));

    binaryFile.close();
    std::cout << "Binary file written successfully!" << std::endl;
}

void readBinaryFile() {
    std::fstream binaryFile("students.bin", std::ios::in | std::ios::binary);

    if (!binaryFile) {
        std::cerr << "Error opening file for reading!" << std::endl;
        return;
    }

    Student students[3];

    // 構造体全体をバイナリファイルから読み取る
    binaryFile.read(reinterpret_cast<char*>(students), sizeof(students));

    std::cout << "Student Records:" << std::endl;
    for (int i = 0; i < 3; ++i) {
        std::cout << "ID: " << students[i].id
                  << ", Name: " << students[i].name
                  << ", GPA: " << students[i].gpa << std::endl;
    }

    binaryFile.close();
}

int main() {
    // バイナリファイルを書き込む
    writeBinaryFile();

    // バイナリファイルを読み取る
    readBinaryFile();

    return 0;
}

プログラムをコンパイルします。

g++ binary_files.cpp -o binary_files

実行可能ファイルを実行します。

./binary_files

出力例:

Binary file written successfully!
Student Records:
ID: 1, Name: John Doe, GPA: 3.5
ID: 2, Name: Alice Smith, GPA: 3.8
ID: 3, Name: Bob Johnson, GPA: 3.2

バイナリファイルに関する重要なポイント:

  • バイナリモードで std::ios::binary フラグを使用する
  • バイナリデータ用の write()read() メソッド
  • 型間の変換に reinterpret_cast を使用する
  • 構造化データを効率的に保存するのに役立つ
  • データの正確なバイナリ表現を維持する

バイナリファイルを、正確なブループリントのように考えることができます。メモリ内のデータのままをそのまま保存し、テキスト変換は行いません。

seekg/seekp を使ってファイルポインタを位置付ける

このステップでは、C++ で読み取り用に seekg() と書き込み用に seekp() を使ってファイルポインタを操作する方法を学びます。これらのメソッドを使うと、ファイル内の特定の位置を移動して変更することができます。

file_pointer.cpp という新しい C++ ファイルを作成します。

touch ~/project/file_pointer.cpp

file_pointer.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>

void createSampleFile() {
    std::ofstream file("numbers.txt");
    for (int i = 1; i <= 10; ++i) {
        file << i << " ";
    }
    file.close();
}

void demonstrateSeekOperations() {
    // 読み書きモードでファイルを開く
    std::fstream file("numbers.txt", std::ios::in | std::ios::out);

    if (!file) {
        std::cerr << "Error opening file!" << std::endl;
        return;
    }

    // 異なる位置から読み取り
    std::cout << "Reading operations:" << std::endl;

    // 5 バイト目(文字位置)に移動する
    file.seekg(5);
    int value;
    file >> value;
    std::cout << "Value at 5th byte: " << value << std::endl;

    // ファイルの先頭に移動する
    file.seekg(0);
    file >> value;
    std::cout << "First value: " << value << std::endl;

    // 特定の位置に書き込み
    std::cout << "\nWriting operations:" << std::endl;

    // 特定の位置に移動して書き込む
    file.seekp(0);
    file << "100 ";

    // ファイルポインタをリセットして読み取り、変更を確認する
    file.seekg(0);
    file >> value;
    std::cout << "Modified first value: " << value << std::endl;

    file.close();
}

int main() {
    // 数字が入ったサンプルファイルを作成する
    createSampleFile();

    // シーク操作を示す
    demonstrateSeekOperations();

    return 0;
}

プログラムをコンパイルします。

g++ file_pointer.cpp -o file_pointer

実行可能ファイルを実行します。

./file_pointer

出力例:

Reading operations:
Value at 5th byte: 4
First value: 1

Writing operations:
Modified first value: 10

ファイルポインタに関する重要なポイント:

  • seekg():読み取りポインタ(取得ポインタ)を移動させる
  • seekp():書き込みポインタ(書き込みポインタ)を移動させる
  • 最初の引数はバイト位置
  • ファイルのランダムアクセスに便利
  • 特定の場所に移動できる

ファイルポインタを、テキストエディタのカーソルのように考えることができます。seekg()seekp() を使って、このカーソルを正確に必要な場所に移動させることができます。

ファイルを閉じてリソースを解放する

このステップでは、C++ においてファイルを適切に閉じ、リソースを管理することの重要性について学びます。これにより、メモリリークを防ぎ、効率的なファイル操作を確保します。ファイルを閉じるさまざまな方法と、RAII(Resource Acquisition Is Initialization)の原則を使った方法を探ります。

file_resources.cpp という新しい C++ ファイルを作成します。

touch ~/project/file_resources.cpp

file_resources.cpp ファイルに次のコードを追加します。

#include <iostream>
#include <fstream>
#include <string>
#include <memory>

// 手動でファイルを閉じる
void manualFileHandling() {
    std::ofstream outputFile("manual_file.txt");

    if (outputFile.is_open()) {
        outputFile << "Manually managed file resource" << std::endl;

        // 明示的にファイルを閉じる
        outputFile.close();

        std::cout << "File closed manually." << std::endl;
    }
}

// unique_ptr を使った RAII ベースのファイル操作
void raii_fileHandling() {
    try {
        // ファイルリソースを管理するための unique_ptr
        std::unique_ptr<std::ofstream> file(new std::ofstream("raii_file.txt"));

        if (file && file->is_open()) {
            *file << "RAII-managed file resource" << std::endl;
            std::cout << "RAII file handling successful." << std::endl;
        }
        // unique_ptr がスコープ外になるときにファイルは自動的に閉じられる
    }
    catch (const std::exception& e) {
        std::cerr << "Error in RAII file handling: " << e.what() << std::endl;
    }
}

// スコープベースのファイル操作
void scopeBasedFileHandling() {
    {
        // ファイルがスコープ外になるときに自動的に閉じられる
        std::ofstream scopedFile("scoped_file.txt");

        if (scopedFile.is_open()) {
            scopedFile << "Scope-based file resource management" << std::endl;
            std::cout << "Scoped file handling successful." << std::endl;
        }
    } // ここでファイルは自動的に閉じられる
}

int main() {
    // さまざまなファイルリソース管理技術を示す
    manualFileHandling();
    raii_fileHandling();
    scopeBasedFileHandling();

    return 0;
}

プログラムをコンパイルします。

g++ file_resources.cpp -o file_resources

実行可能ファイルを実行します。

./file_resources

出力例:

File closed manually.
RAII file handling successful.
Scoped file handling successful.

ファイルを閉じてリソースを管理するに関する重要なポイント:

  • 使用後は必ずファイルを閉じる
  • 手動で閉じるには close() メソッドを使用する
  • RAII の原則を活用する
  • スコープベースのリソース管理を使用する
  • リソースリークを防止する
  • ファイル操作中の例外を処理する

ファイルリソースを、図書館から本を借りるように考えることができます。終えたら必ず本を返す(ファイルを閉じる)ことで、図書館(システムリソース)を整然と保つことができます。

まとめ

この実験では、標準ライブラリの ofstreamifstream クラスを使って C++ でファイルを開く方法を学びました。ファイルのオープン状態を確認し、ファイルにテキストデータを書き込み、テキストファイルからデータを読み取るプロセスを探りました。また、ファイルの読み取り/書き込みエラーの処理、fstream を使ったバイナリファイルの操作、seekg/seekp を使ったファイルポインタの位置付け、およびファイルを適切に閉じてリソースを解放する方法を理解しました。これらの基本的なファイル操作は、C++ アプリケーションにおけるデータの保存と取得の管理に欠かせないものです。