소개
본 랩에서는 C++ 에서 다양한 파일 작업을 수행하는 방법을 배웁니다. 이 랩에서는 파일 열기 (읽기 및 쓰기), 텍스트 데이터 파일에 쓰기, 텍스트 파일에서 데이터 읽기, 파일 열림 상태 확인, 파일 읽기/쓰기 오류 처리, 바이너리 파일 작업, 파일 포인터 위치 지정, 리소스 해제를 위한 파일 닫기 등을 다룹니다. C++ 표준 라이브러리의 기본 파일 스트림 클래스인 ofstream 및 ifstream을 사용하여 파일과 상호 작용하는 실질적인 경험을 쌓게 될 것입니다. 이 랩이 끝날 때쯤에는 C++ 프로그래밍에서 파일 처리에 대한 확고한 이해를 갖게 될 것입니다.
ofstream 및 ifstream 을 사용하여 파일 열기
이 단계에서는 파일을 쓰기 위한 ofstream과 파일을 읽기 위한 ifstream이라는 두 가지 기본 파일 스트림 클래스를 사용하여 C++ 에서 파일을 여는 방법을 배웁니다. 이 클래스들은 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;
}
주요 개념을 분석해 보겠습니다:
#include <fstream>: 파일 스트림 라이브러리를 포함합니다.std::ofstream: 파일을 쓰기 위한 출력 파일 스트림 (Output File Stream) 입니다.std::ifstream: 파일을 읽기 위한 입력 파일 스트림 (Input File Stream) 입니다.is_open(): 파일이 성공적으로 열렸는지 확인합니다.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();
// seek 작업 시연
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: 100
파일 포인터에 대한 주요 사항:
seekg(): 읽기 포인터 (get pointer) 이동seekp(): 쓰기 포인터 (put pointer) 이동- 첫 번째 인수는 바이트 위치입니다.
- 파일 내에서 임의 접근 (random access) 에 유용합니다.
- 특정 위치로 이동할 수 있습니다.
파일 포인터를 텍스트 편집기의 커서라고 생각할 수 있습니다. 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 원칙을 활용합니다.
- 범위 기반 리소스 관리를 사용합니다.
- 리소스 누수를 방지합니다.
- 파일 작업 중 예외를 처리합니다.
파일 리소스를 도서관에서 책을 빌리는 것에 비유할 수 있습니다. 도서관 (시스템 리소스) 을 정리하려면 사용이 끝나면 항상 책 (파일) 을 반납해야 합니다.
요약
본 랩 (lab) 에서는 표준 라이브러리의 ofstream 및 ifstream 클래스를 사용하여 C++ 에서 파일을 여는 방법을 배웠습니다. 파일 열림 상태 확인, 파일에 텍스트 데이터 쓰기, 텍스트 파일에서 데이터 읽기 과정을 탐구했습니다. 추가적으로, 파일 읽기/쓰기 오류 처리, fstream을 사용한 바이너리 파일 작업, seekg/seekp를 사용한 파일 포인터 위치 지정, 그리고 파일 닫기 및 리소스 해제 방법을 이해했습니다. 이러한 기본적인 파일 작업은 C++ 애플리케이션에서 데이터 저장 및 검색을 관리하는 데 필수적입니다.



