12장. I/O

Gillilab - TechLog·2024년 11월 17일

Rust

목록 보기
13/21

12장. I/O

Rust에서는 표준 라이브러리를 통해 파일 입출력(I/O) 작업을 쉽게 수행할 수 있습니다

파일 읽기

Rust에서 파일을 읽기 위해서는 std::fs::Filestd::io::Read 트레이트를 사용합니다.

파일 읽기 예제

use std::fs::File;
use std::io::{self, Read};

fn read_file_to_string(filename: &str) -> io::Result<String> {
    let mut file = File::open(filename)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn main() {
    let filename = "example.txt";

    match read_file_to_string(filename) {
        Ok(contents) => println!("File contents:\n{}", contents),
        Err(e) => println!("Error reading file: {}", e),
    }
}

위 예제에서 read_file_to_string 함수는 파일 이름을 받아서 파일 내용을 문자열로 반환합니다. File::open 함수와 file.read_to_string 메서드는 Result 타입을 반환하며, ? 연산자를 사용하여 에러를 전파합니다.

파일 쓰기

Rust에서 파일에 쓰기 위해서는 std::fs::Filestd::io::Write 트레이트를 사용합니다.

파일 쓰기 예제

use std::fs::File;
use std::io::{self, Write};

fn write_string_to_file(filename: &str, contents: &str) -> io::Result<()> {
    let mut file = File::create(filename)?;
    file.write_all(contents.as_bytes())?;
    Ok(())
}

fn main() {
    let filename = "output.txt";
    let contents = "Hello, Rust!";

    match write_string_to_file(filename, contents) {
        Ok(_) => println!("Successfully wrote to the file."),
        Err(e) => println!("Error writing to file: {}", e),
    }
}

위 예제에서 write_string_to_file 함수는 파일 이름과 내용을 받아서 파일에 씁니다. File::create 함수와 file.write_all 메서드는 Result 타입을 반환하며, ? 연산자를 사용하여 에러를 전파합니다.

파일 읽기 및 쓰기 통합

이제 파일을 읽고 쓰는 기능을 통합하여 하나의 프로그램으로 만들어 보겠습니다.

파일 읽기 및 쓰기 통합 예제

use std::fs::File;
use std::io::{self, Read, Write};

fn read_file_to_string(filename: &str) -> io::Result<String> {
    let mut file = File::open(filename)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn write_string_to_file(filename: &str, contents: &str) -> io::Result<()> {
    let mut file = File::create(filename)?;
    file.write_all(contents.as_bytes())?;
    Ok(())
}

fn main() {
    let input_filename = "example.txt";
    let output_filename = "output.txt";

    match read_file_to_string(input_filename) {
        Ok(contents) => {
            println!("File contents:\n{}", contents);
            match write_string_to_file(output_filename, &contents) {
                Ok(_) => println!("Successfully wrote to the file."),
                Err(e) => println!("Error writing to file: {}", e),
            }
        }
        Err(e) => println!("Error reading file: {}", e),
    }
}

위 예제에서 main 함수는 example.txt 파일을 읽고, 그 내용을 output.txt 파일에 씁니다. 파일을 읽고 쓰는 과정에서 발생할 수 있는 에러를 처리하여 사용자에게 알립니다.

I/O 요약

  • 커맨드라인 인수 받기

    • std::env::args() 함수를 사용한 인수 처리
    • 검색어와 파일 경로 인수 파싱하기
    • 예제:
      let args: Vec<String> = env::args().collect();
      let query = &args[1];
      let file_path = &args[2];
  • 파일 읽기

    • std::fs 모듈을 이용한 파일 읽기
    • 버퍼를 통한 대용량 파일 처리
    • 예제:
      let contents = fs::read_to_string(file_path)
          .expect("파일을 읽는데 실패했습니다");
  • 모듈성과 에러 처리

    • 구조체와 트레이트를 활용한 모듈화

    • Result와 Option을 이용한 우아한 에러 처리

    • 예제:

      pub struct Config {
          query: String,
          file_path: String,
      }
      
      impl Config {
          pub fn build(args: &[String]) -> Result<Config, &'static str> {
              if args.len() < 3 {
                  return Err("필요한 인수가 부족합니다");
              }
              Ok(Config {
                  query: args[1].clone(),
                  file_path: args[2].clone(),
              })
          }
      }
  • TDD(테스트 주도 개발)

    • 단위 테스트 작성하기
    • 통합 테스트 구현하기
    • 예제:
      mod tests {
      use super::\*;
              #[test]
              fn one_result() {
                  let query = "duct";
                  let contents = "\
      Rust:
      safe, fast, productive.
      Pick three.";
      assert_eq!(vec!["safe, fast, productive."],
      search(query, contents));
      }
      }

0개의 댓글