이번에는 저번에 맛보기로 진행했던 파일 입출력(File I/O)과 스트림(Stream)을 확인보자.
- 파일을 읽고( readAsString() ), 쓰고( writeAsString() ) 수정하는 방법
- 스트림( Stream )을 사용하여 대용량 파일을 효율적으로 처리하는 방법
1. 파일 쓰기 ( writeAsString() , writeAsBytes() )
Dart에서는 dart:io 라이브러리를 사용하여 파일을 생성하고 데이터를 저장할 수 있다.
✔️ 문자열을 파일에 저장 ( writeAsString() )
import 'dart:io';
void main() async {
File file = File('test.txt'); // 파일 객체 생성
await file.writeAsString('Hello, Dart! 파일 입출력 테스트', mode: FileMode.write);
print("✅ 파일 저장 완료: ${file.path}");
}
- writeAsString() → 파일에 문자열을 저장
- mode: FileMode.write → 기존 파일 내용을 덮어씀
2. 파일 읽기 ( readAsString() , readAsLines() )
파일에 저장된 데이터를 읽을 수도 있다.
✔️ 파일 읽기 ( readAsString() )
import 'dart:io';
void main() async {
File file = File('test.txt');
if (await file.exists()) {
String content = await file.readAsString();
print("📄 파일 내용: $content");
} else {
print("⚠️ 파일이 존재하지 않습니다.");
}
}
- readAsString() → 파일의 모든 내용을 읽어 문자열로 반환
- 파일이 존재하지 않을 경우 예외를 방지하기 위해 exists()로 확인
3. 파일에 여러 줄 저장 & 읽기 ( writeAsLines(), readAsLines() )
여러 줄 데이터를 저장하고 읽을 수도 있다.
✔️ 여러 줄 저장 ( join('\n') 사용 )
import 'dart:io';
void main() async {
File file = File('lines.txt');
List<String> lines = [
'첫 번째 줄',
'두 번째 줄',
'세 번째 줄'
];
await file.writeAsString(lines.join('\n')); // 리스트를 문자열로 변환하여 저장
print("✅ 여러 줄 파일 저장 완료");
}
- join('\n') → 리스트를 문자열로 변환하여 파일에 저장
✔️ 여러 줄 읽기 (split('\n') 사용)
import 'dart:io';
void main() async {
File file = File('lines.txt');
if (await file.exists()) {
String content = await file.readAsString();
List<String> lines = content.split('\n'); // 줄 단위로 나누기
print("📄 파일 내용:");
for (var line in lines) {
print(line);
}
} else {
print("⚠️ 파일이 존재하지 않습니다.");
}
}
- split('\n') → 문자열을 줄 단위 리스트로 변환
✔️ 기존 파일에 내용 추가 (append 모드)
import 'dart:io';
void main() async {
File file = File('lines.txt');
List<String> newLines = [
'네 번째 줄',
'다섯 번째 줄'
];
await file.writeAsString('\n' + newLines.join('\n'),
mode: FileMode.append); // 기존 내용 뒤에 추가
print("✅ 파일에 새로운 줄 추가 완료");
}
- FileMode.append → 기존 내용 뒤에 새로운 데이터를 추가
- '\n' + newLines.join('\n') → 기존 줄과 새 줄 사이에 줄바꿈 추가
4. 파일 존재 여부 확인 & 삭제 ( exists(), delete() )
파일이 존재하는지 확인하고 삭제할 수도 있다.
✔️ 파일 존재 여부 확인
import 'dart:io';
void main() async {
File file = File('test.txt');
if (await file.exists()) {
print("✅ 파일이 존재합니다.");
} else {
print("⚠️ 파일이 존재하지 않습니다.");
}
}
✔️ 파일 삭제 (delete())
import 'dart:io';
void main() async {
File file = File('test.txt');
if (await file.exists()) {
await file.delete();
print("🗑 파일 삭제 완료");
} else {
print("⚠️ 삭제할 파일이 없습니다.");
}
}
- delete() → 파일을 삭제
- 파일이 존재하지 않으면 예외를 방지하기 위해 exists() 확인
5. 스트림(Stream) 활용 - 대용량 파일 처리
- 파일을 한 번에 읽으면 메모리 사용량이 많아질 수 있다
- 스트림( Stream )을 사용하면 데이터를 한 줄씩 읽으며 메모리를 효율적으로 관리 가능
✔️ 스트림을 이용한 파일 읽기 ( openRead() )
import 'dart:io';
import 'dart:convert';
void main() async {
File file = File('large_file.txt');
if (await file.exists()) {
Stream<List<int>> inputStream = file.openRead(); // 스트림 열기
inputStream
.transform(utf8.decoder) // 바이트를 문자열로 변환
.transform(LineSplitter()) // 줄 단위로 나누기
.listen((line) {
print("📄 읽은 줄: $line");
}, onDone: () {
print("✅ 파일 읽기 완료");
}, onError: (e) {
print("⚠️ 오류 발생: $e");
});
} else {
print("⚠️ 파일이 존재하지 않습니다.");
}
}
- openRead() → 파일을 스트림으로 열기
- transform(utf8.decoder) → 바이트 데이터를 문자열로 변환
- transform(LineSplitter()) → 한 줄씩 처리
✔️ 스트림(Stream)으로 파일 쓰기 ( openWrite() )
import 'dart:io';
void main() async {
File file = File('stream_output.txt');
// 스트림을 이용한 파일 쓰기 (기존 파일 내용 덮어쓰기)
IOSink sink = file.openWrite(mode: FileMode.write);
List<String> lines = [
'첫 번째 줄 - 스트림 사용',
'두 번째 줄 - 파일 쓰기',
'세 번째 줄 - 효율적인 데이터 저장'
];
for (var line in lines) {
sink.writeln(line); // 한 줄씩 쓰기
}
await sink.flush(); // 버퍼 비우기
await sink.close(); // 스트림 닫기
print("✅ 스트림을 이용한 파일 쓰기 완료");
}
- openWrite(mode: FileMode.write) → 파일을 쓰기 모드로 스트림 열기
- sink.writeln(line) → 한 줄씩 데이터 추가 (writeln()은 자동 줄바꿈)
- await sink.flush(); → 버퍼를 비워 데이터 즉시 저장
- await sink.close(); → 파일을 닫아 메모리 해제
✔️ 테스트 예제 코드 1
위에서 진행했던 내용을 토대로 충분한 실습을 진행한 후, 테스트 예제를 진행해보도록 하자.
1. 사용자 입력을 받아 파일에 저장하는 프로그램
2. 사용자가 입력한 내용을 파일(user_input.txt)에 저장하는 프로그램
3. 여러 줄 입력 가능 (q 입력 시 종료)
4. 기존 내용을 유지하면서 새로운 내용 추가 (FileMode.append)
5. 입력값이 공백("")이면 다시 입력받도록 유효성 검사 포함
import 'dart:io';
void main() async {
File file = File('user_input.txt'); // 파일 객체 생성
IOSink sink = file.openWrite(mode: FileMode.append); // 기존 내용 유지하며 추가
print("📝 텍스트를 입력하세요. (종료하려면 'q' 입력)");
while (true) {
stdout.write("> ");
String? input = stdin.readLineSync()?.trim(); // 입력값 앞뒤 공백 제거
// 공백 입력 방지
if (input == null || input.isEmpty) {
print("⚠️ 입력이 비어 있습니다. 다시 입력하세요.");
continue;
}
// 'q' 입력 시 종료
if (input.toLowerCase() == 'q') {
print("🚪 입력 종료. 파일에 저장 완료!");
break;
}
sink.writeln(input); // 한 줄씩 파일에 추가
}
await sink.flush(); // 버퍼 비우기
await sink.close(); // 스트림 닫기
}
- File('user_input.txt') → 파일 객체 생성
- openWrite(mode: FileMode.append) → 기존 내용 유지하면서 데이터 추가
- stdin.readLineSync() → 사용자 입력 받기
- input.toLowerCase() == 'q' → q 입력 시 종료
- sink.writeln(input); → 입력된 내용을 한 줄씩 파일에 추가
- sink.flush(); & sink.close(); → 버퍼 비우고 파일 닫기
✔️ 테스트 예제 코드 2
1. 파일에서 데이터를 읽어와서 출력하는 프로그램
2. 사용자가 입력한 파일(user_input.txt)을 읽고 출력
3. 파일이 존재하지 않으면 경고 메시지를 출력
4. 한 줄씩 데이터를 읽어서 출력 (split('\n'))
5. 파일이 클 경우, openRead()(스트림)를 사용하여 한 줄씩 읽도록 개선 가능
6. 파일이 존재하지 않을 때 새 파일을 생성하도록 수정 가능
import 'dart:io';
import 'dart:convert';
void main() async {
File file = File('user_input.txt'); // 읽을 파일 지정
// 파일이 존재하지 않으면 자동 생성
if (!await file.exists()) {
await file.writeAsString("기본 데이터입니다.\nDart 파일 입출력 예제\n", mode: FileMode.write);
print("🆕 파일이 없어서 새로 생성되었습니다!");
}
print("📄 파일 내용:");
// 스트림을 활용하여 한 줄씩 파일 읽기
Stream<List<int>> inputStream = file.openRead();
inputStream
.transform(utf8.decoder) // 바이트를 문자열로 변환
.transform(LineSplitter()) // 한 줄씩 나누기
.listen((line) {
if (line.trim().isNotEmpty) { // 빈 줄 제외
print(line);
}
}, onDone: () {
print("✅ 파일 읽기 완료");
}, onError: (e) {
print("⚠️ 오류 발생: $e");
});
}
✔️ 테스트 예제 코드 3
1. 스트림(Stream) 활용 + 파일 자동 생성 + 특정 키워드 필터링 기능.
2. 대용량 파일(large_file.txt)을 스트림으로 한 줄씩 읽기
3. 파일이 없으면 기본 데이터를 포함한 새 파일을 자동 생성
4. 사용자가 원하는 키워드가 포함된 줄만 출력 가능 (filterKeyword)
5. 메모리를 절약하면서 효율적으로 파일 읽기
6. openRead() + utf8.decoder + LineSplitter() 조합으로 효율적인 파일 처리
7. 읽기 완료 시 메시지 출력 & 오류 발생 시 예외 처리
import 'dart:io';
import 'dart:convert';
void main() async {
File file = File('large_file.txt'); // 파일 지정
// 파일이 존재하지 않으면 기본 내용 포함하여 자동 생성
if (!await file.exists()) {
await file.writeAsString(
"첫 번째 줄 - 스트림 사용\n"
"두 번째 줄 - 대용량 데이터 처리\n"
"세 번째 줄 - 메모리 절약\n"
"네 번째 줄 - 효율적인 파일 읽기\n"
"다섯 번째 줄 - 키워드 필터링 지원\n",
mode: FileMode.write,
);
print("🆕 파일이 없어서 새로 생성되었습니다!");
}
print("📄 대용량 파일 읽기 시작...");
String filterKeyword = "키워드"; // 특정 키워드가 포함된 줄만 출력
Stream<List<int>> inputStream = file.openRead(); // 스트림 열기
inputStream
.transform(utf8.decoder) // 바이트 데이터를 문자열로 변환
.transform(LineSplitter()) // 한 줄씩 나누기
.listen((line) {
if (line.trim().isNotEmpty) { // 빈 줄 제외
if (line.contains(filterKeyword)) { // 특정 키워드 포함된 줄만 출력
print("🔍 필터링된 줄: $line");
} else {
print("📄 읽은 줄: $line");
}
}
}, onDone: () {
print("✅ 대용량 파일 읽기 완료!");
}, onError: (e) {
print("⚠️ 오류 발생: $e");
});
}
- 파일이 없으면 기본 데이터를 포함한 새 파일을 자동 생성
- 대용량 파일도 스트림(openRead())으로 한 줄씩 읽어 효율적으로 처리
- trim().isNotEmpty를 사용하여 빈 줄 출력 방지
- 특정 키워드(filterKeyword)가 포함된 줄만 따로 출력
이렇게 파일 입출력 (File I/O) & 스트림 (Stream) 활용에 대해서 알아보았다. 추가 적인 내용이 필요한 경우에는 댓글을 요청드리고, 틀린 부분이 있다면 이것 또한 댓글로 알려주시면 수정하도록 하겠습니다!
'IT > Dart' 카테고리의 다른 글
Dart 번외 : IDE 선택하기 + 설치 (2) | 2025.03.11 |
---|---|
Dart_11일차 : 파일 및 디렉터리 관리 (File & Directory Handling) (0) | 2025.03.10 |
Dart_9일차 : 예외 처리 (Exception Handling) & Future Error Handling (0) | 2025.03.07 |
Dart_8일차 : 클래스 심화 (생성자, Getter/Setter, 연산자 오버로딩) (0) | 2025.03.06 |
Dart_7일차 : 파일 입출력 & JSON 데이터 처리 (0) | 2025.03.05 |