Rust 에서 파일 시스템 작업

Beginner

This tutorial is from open-source community. Access the source code

소개

이 실습에서는 Rust 의 std::fs 모듈을 소개합니다. 이 모듈은 파일 시스템 작업을 위한 함수를 제공합니다. 이 실습에서는 디렉토리 생성, 파일 생성, 파일 내용 읽기, 심볼릭 링크 생성, 디렉토리 내용 목록화, 파일 삭제, 디렉토리 삭제 등 다양한 파일 시스템 작업의 예제를 제공합니다. 코드 스니펫은 std::fs 모듈 함수를 사용하여 이러한 작업을 수행하는 방법을 보여주며, 각 작업에 대한 예상 출력도 제공됩니다. 또한, 에러 처리를 위해 ? 표기법을 사용하는 cat 함수의 대안 구현에 대해 언급합니다.

참고: 실습에서 파일 이름을 지정하지 않으면 원하는 파일 이름을 사용할 수 있습니다. 예를 들어 main.rs를 사용하고 rustc main.rs && ./main으로 컴파일 및 실행할 수 있습니다.

파일 시스템 작업

std::fs 모듈은 파일 시스템과 관련된 여러 함수를 포함합니다.

use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::os::unix;
use std::path::Path;

// `% cat path`의 간단한 구현
fn cat(path: &Path) -> io::Result<String> {
    let mut f = File::open(path)?;
    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

// `% echo s > path`의 간단한 구현
fn echo(s: &str, path: &Path) -> io::Result<()> {
    let mut f = File::create(path)?;

    f.write_all(s.as_bytes())
}

// `% touch path`의 간단한 구현 (기존 파일은 무시)
fn touch(path: &Path) -> io::Result<()> {
    match OpenOptions::new().create(true).write(true).open(path) {
        Ok(_) => Ok(()),
        Err(e) => Err(e),
    }
}

fn main() {
    println!("`mkdir a`");
    // 디렉토리를 생성합니다. `io::Result<()>` 를 반환합니다.
    match fs::create_dir("a") {
        Err(why) => println!("! {:?}", why.kind()),
        Ok(_) => {},
    }

    println!("`echo hello > a/b.txt`");
    // 이전 매치는 `unwrap_or_else` 메서드를 사용하여 간소화할 수 있습니다.
    echo("hello", &Path::new("a/b.txt")).unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });

    println!("`mkdir -p a/c/d`");
    // 재귀적으로 디렉토리를 생성합니다. `io::Result<()>` 를 반환합니다.
    fs::create_dir_all("a/c/d").unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });

    println!("`touch a/c/e.txt`");
    touch(&Path::new("a/c/e.txt")).unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });

    println!("`ln -s ../b.txt a/c/b.txt`");
    // 심볼릭 링크를 생성합니다. `io::Result<()>` 를 반환합니다.
    if cfg!(target_family = "unix") {
        unix::fs::symlink("../b.txt", "a/c/b.txt").unwrap_or_else(|why| {
            println!("! {:?}", why.kind());
        });
    }

    println!("`cat a/c/b.txt`");
    match cat(&Path::new("a/c/b.txt")) {
        Err(why) => println!("! {:?}", why.kind()),
        Ok(s) => println!("> {}", s),
    }

    println!("`ls a`");
    // 디렉토리 내용을 읽습니다. `io::Result<Vec<Path>>` 를 반환합니다.
    match fs::read_dir("a") {
        Err(why) => println!("! {:?}", why.kind()),
        Ok(paths) => for path in paths {
            println!("> {:?}", path.unwrap().path());
        },
    }

    println!("`rm a/c/e.txt`");
    // 파일을 삭제합니다. `io::Result<()>` 를 반환합니다.
    fs::remove_file("a/c/e.txt").unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });

    println!("`rmdir a/c/d`");
    // 비어있는 디렉토리를 삭제합니다. `io::Result<()>` 를 반환합니다.
    fs::remove_dir("a/c/d").unwrap_or_else(|why| {
        println!("! {:?}", why.kind());
    });
}

예상 성공 출력:

$ rustc fs.rs && ./fs
$(mkdir a)
$(echo hello > a/b.txt)
$(mkdir -p a/c/d)
$(touch a/c/e.txt)
$(ln -s ../b.txt a/c/b.txt)
$(cat a/c/b.txt)
> hello
$(ls a)
> "a/b.txt"
> "a/c"
$(rm a/c/e.txt)
$(rmdir a/c/d)

a 디렉토리의 최종 상태:

$ tree a
a
|-- b.txt
`-- c
    `-- b.txt -> ../b.txt

1 directory, 2 files

cat 함수를 정의하는 또 다른 방법은 ? 표기법을 사용하는 것입니다.

fn cat(path: &Path) -> io::Result<String> {
    let mut f = File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

요약

축하합니다! 파일 시스템 작업 실습을 완료했습니다. LabEx 에서 더 많은 실습을 통해 기술을 향상시킬 수 있습니다.