# 파일 읽기와 쓰기

파일 입출력은 Dart에서 파일 시스템과 상호작용하는 중요한 기능이다. 이를 통해 파일을 읽고 쓰는 작업을 효율적으로 처리할 수 있다. Dart는 `dart:io` 라이브러리를 제공하여 파일 시스템에 대한 다양한 작업을 할 수 있다.

#### 파일 읽기

파일을 읽는 방법에는 여러 가지가 있으며, Dart에서는 동기 및 비동기 방식 모두를 지원한다. 동기 방식은 코드 실행 흐름이 파일이 완전히 읽힐 때까지 대기하는 방식이고, 비동기 방식은 파일 읽기 작업이 끝날 때까지 다른 작업을 수행할 수 있는 방식이다.

**동기 파일 읽기**

동기 파일 읽기에서는 `File` 클래스의 `readAsStringSync()` 메서드를 사용하여 파일의 내용을 문자열로 읽을 수 있다.

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  var contents = file.readAsStringSync();
  print(contents);
}
```

이 코드에서 `example.txt` 파일의 모든 내용을 읽고 문자열로 반환한다. 이 방법은 파일을 작은 크기로 다룰 때 유용하지만, 파일 크기가 큰 경우 성능에 영향을 줄 수 있다.

**비동기 파일 읽기**

비동기 파일 읽기는 `await`와 `async` 키워드를 사용하여 파일을 읽는 동안 프로그램의 다른 부분이 실행될 수 있도록 한다. 이는 큰 파일을 처리할 때나 파일 시스템의 상태에 따라 느린 작업을 처리할 때 유용하다.

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('example.txt');
  var contents = await file.readAsString();
  print(contents);
}
```

이 예제에서 `readAsString()` 메서드는 `Future`를 반환하며, 파일 읽기가 완료될 때까지 기다린 후 문자열을 반환한다.

#### 파일 쓰기

파일 쓰기도 Dart에서 매우 간단하게 수행할 수 있다. Dart는 동기 및 비동기 방식을 모두 지원하며, 파일에 새로운 내용을 추가하거나 기존 내용을 덮어쓸 수 있는 기능을 제공한다.

**동기 파일 쓰기**

동기 방식으로 파일에 내용을 쓰기 위해서는 `writeAsStringSync()` 메서드를 사용할 수 있다. 이 메서드는 파일에 문자열을 기록하고, 기록이 완료될 때까지 코드 실행을 중단시킨다.

```dart
import 'dart:io';

void main() {
  var file = File('output.txt');
  file.writeAsStringSync('Dart is amazing!');
}
```

이 코드는 `output.txt` 파일에 "Dart is amazing!"이라는 문자열을 기록하며, 파일이 없으면 새로 생성하고, 기존 파일이 있으면 그 내용을 덮어씁니다.

**비동기 파일 쓰기**

비동기 방식에서는 `writeAsString()` 메서드를 사용하여 파일에 비동기적으로 내용을 쓸 수 있다. 이 방식은 큰 파일을 처리하거나 파일에 기록하는 작업이 시간이 오래 걸릴 때 유용하다.

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('output.txt');
  await file.writeAsString('Dart is amazing!');
}
```

이 방식은 파일에 내용을 기록하는 동안 다른 작업이 실행될 수 있도록 한다. `await`를 사용하여 기록이 완료될 때까지 대기한 후, 다음 작업을 실행한다.

#### 파일에 내용 추가하기

기본적으로 파일에 내용을 기록할 때는 기존 내용을 덮어쓰게 된다. 하지만 파일에 내용을 추가하고 싶을 때는 `mode` 옵션을 사용하여 파일을 열 수 있다. Dart의 `FileMode.append` 옵션을 통해 파일에 내용을 추가할 수 있다.

```dart
import 'dart:io';

void main() {
  var file = File('output.txt');
  file.writeAsStringSync('Appended text!', mode: FileMode.append);
}
```

이 코드는 기존 `output.txt` 파일에 "Appended text!"라는 문자열을 추가한다.

#### 파일 존재 여부 확인

파일에 접근하기 전에 파일이 존재하는지 여부를 확인하는 것이 좋다. Dart에서는 `existsSync()` 메서드를 사용하여 파일이 동기적으로 존재하는지 확인할 수 있으며, 비동기적으로 확인하려면 `exists()` 메서드를 사용할 수 있다.

**동기 파일 존재 확인**

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  if (file.existsSync()) {
    print('File exists.');
  } else {
    print('File does not exist.');
  }
}
```

이 코드는 파일이 존재하는 경우 "File exists."를 출력하고, 존재하지 않으면 "File does not exist."를 출력한다.

**비동기 파일 존재 확인**

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('example.txt');
  if (await file.exists()) {
    print('File exists.');
  } else {
    print('File does not exist.');
  }
}
```

비동기 방식으로 파일이 존재하는지 확인하는 방법은 `await` 키워드를 사용하여 파일 존재 여부를 대기한다.

#### 파일 삭제

파일을 삭제할 때는 `deleteSync()` 메서드를 사용하여 동기적으로 파일을 삭제할 수 있고, `delete()` 메서드를 사용하여 비동기적으로 파일을 삭제할 수 있다.

**동기 파일 삭제**

```dart
import 'dart:io';

void main() {
  var file = File('output.txt');
  if (file.existsSync()) {
    file.deleteSync();
    print('File deleted.');
  }
}
```

이 코드는 `output.txt` 파일이 존재하는 경우 파일을 삭제한다.

**비동기 파일 삭제**

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('output.txt');
  if (await file.exists()) {
    await file.delete();
    print('File deleted.');
  }
}
```

비동기 파일 삭제에서는 `await` 키워드를 사용하여 파일 삭제 작업이 완료될 때까지 대기한다.

#### 파일 경로 정보 가져오기

파일의 경로 정보를 가져올 때는 `absolute` 속성을 사용할 수 있다. 이 속성은 파일의 절대 경로를 반환하며, 이를 통해 파일이 실제로 저장된 위치를 알 수 있다.

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  print('Absolute path: ${file.absolute.path}');
}
```

이 코드는 `example.txt` 파일의 절대 경로를 출력한다.

#### 파일 복사

파일을 다른 위치에 복사하는 방법은 `copySync()` 메서드를 사용하여 동기적으로 복사할 수 있으며, `copy()` 메서드를 사용하여 비동기적으로 복사할 수 있다.

**동기 파일 복사**

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  var newFile = file.copySync('copy_of_example.txt');
  print('File copied to: ${newFile.path}');
}
```

이 코드는 `example.txt` 파일을 `copy_of_example.txt`라는 이름으로 복사한다. 복사가 완료된 후 새 파일의 경로를 출력한다.

**비동기 파일 복사**

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('example.txt');
  var newFile = await file.copy('copy_of_example.txt');
  print('File copied to: ${newFile.path}');
}
```

비동기 방식으로 파일을 복사하면, 파일이 완전히 복사될 때까지 기다린 후 새 파일 경로를 출력한다.

#### 파일 크기 확인

파일의 크기를 확인할 때는 `lengthSync()` 메서드를 사용하여 동기적으로 파일 크기를 확인할 수 있으며, `length()` 메서드를 사용하여 비동기적으로 확인할 수 있다.

**동기 파일 크기 확인**

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  print('File size: ${file.lengthSync()} bytes');
}
```

이 코드는 `example.txt` 파일의 크기를 바이트 단위로 출력한다.

**비동기 파일 크기 확인**

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('example.txt');
  print('File size: ${await file.length()} bytes');
}
```

비동기 방식에서는 파일 크기가 계산될 때까지 대기한 후 그 결과를 출력한다.

#### 파일 라인별 읽기

파일의 내용을 한 줄씩 읽고 처리할 때는 `readAsLinesSync()`와 `readAsLines()` 메서드를 사용할 수 있다. 이를 통해 파일의 각 줄을 리스트로 반환한다.

**동기 파일 라인별 읽기**

```dart
import 'dart:io';

void main() {
  var file = File('example.txt');
  var lines = file.readAsLinesSync();
  for (var line in lines) {
    print(line);
  }
}
```

이 코드는 `example.txt` 파일의 내용을 한 줄씩 읽고 출력한다.

**비동기 파일 라인별 읽기**

```dart
import 'dart:io';

Future<void> main() async {
  var file = File('example.txt');
  var lines = await file.readAsLines();
  for (var line in lines) {
    print(line);
  }
}
```

비동기 방식에서는 파일을 한 줄씩 읽고, 비동기적으로 처리가 완료될 때까지 기다린다.
