티스토리 뷰

Flutter Cookbook

Flutter로 파일 읽기 및 쓰기: 완벽 가이드

플러터를 배워보자 2024. 12. 9. 11:00

Flutter는 로컬 파일 시스템에 데이터를 읽고 쓰는 작업을 매우 간단하게 처리할 수 있는 강력한 기능을 제공합니다. 이 블로그에서는 Flutter 앱 개발 중 파일 읽기와 쓰기 작업을 효율적으로 처리하는 방법과 주요 포인트를 설명합니다. 예제를 통해 기본 구현부터 주요 사용 사례까지 자세히 알아보겠습니다.

참고. Read and write files

로컬 파일 읽기와 쓰기의 필요성

모바일 앱에서 데이터를 저장하고 관리하는 작업은 매우 중요합니다. Flutter에서 파일 시스템을 활용하면 다음과 같은 이점을 얻을 수 있습니다:

  1. 사용자 데이터 저장: 인터넷 연결이 없을 때도 데이터 접근 가능.
  2. 설정값 유지: 앱의 사용자 선호도와 설정값을 파일로 저장.
  3. 빠른 데이터 읽기: 데이터베이스보다 가벼운 데이터 저장 방법 제공.

Flutter로 파일 읽기 및 쓰기: 기본 구현

Flutter의 dart:io 패키지를 사용하면 손쉽게 파일 작업을 구현할 수 있습니다. 다음은 기본 단계입니다.

1. 파일의 경로 가져오기

파일을 읽거나 쓰기 전에 앱이 파일을 저장할 디렉터리 경로를 알아야 합니다. Flutter에서는 path_provider 패키지를 사용해 간단히 디렉터리 경로를 가져올 수 있습니다.

import 'dart:io';
import 'package:path_provider/path_provider.dart';

Future<String> getFilePath() async {
  final directory = await getApplicationDocumentsDirectory();
  return '${directory.path}/my_file.txt';
}

2. 파일 쓰기

텍스트 데이터를 파일에 쓰는 작업은 아래와 같이 간단히 처리할 수 있습니다.

Future<void> writeToFile(String data) async {
  final file = File(await getFilePath());
  await file.writeAsString(data);
}

3. 파일 읽기

파일에서 데이터를 읽는 코드는 다음과 같습니다.

Future<String> readFromFile() async {
  try {
    final file = File(await getFilePath());
    return await file.readAsString();
  } catch (e) {
    return 'Error: $e';
  }
}

주요 사용 사례

1. 사용자 설정 저장

사용자가 선택한 테마, 언어, 알림 설정 등을 저장하고 앱 재시작 시 불러오는 데 사용.

2. 로컬 데이터 캐싱

네트워크 요청 결과를 파일로 저장해 인터넷 연결이 없을 때도 데이터를 표시.

3. 로그 기록

앱의 주요 작업 로그를 파일로 기록해 디버깅 또는 모니터링 용도로 활용.

예제: 간단한 메모장 앱 만들기

Flutter로 간단한 메모장 앱을 만들어보겠습니다.

UI 코드

사용자가 텍스트를 입력하고 저장한 데이터를 표시하는 간단한 UI를 작성합니다.

import 'package:flutter/material.dart';

class FileExample extends StatefulWidget {
  @override
  _FileExampleState createState() => _FileExampleState();
}

class _FileExampleState extends State<FileExample> {
  String _content = '';
  TextEditingController _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Flutter 파일 읽기/쓰기')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _controller,
              decoration: InputDecoration(labelText: '입력하세요'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: () async {
                await writeToFile(_controller.text);
                final content = await readFromFile();
                setState(() {
                  _content = content;
                });
              },
              child: Text('저장 및 읽기'),
            ),
            SizedBox(height: 20),
            Text('저장된 내용: $_content'),
          ],
        ),
      ),
    );
  }
}

기능 구현

위에서 소개한 writeToFilereadFromFile을 사용하여 파일 입출력 기능을 연결합니다.

주의사항 및 팁

  1. 예외 처리: 파일이 없거나 디렉터리가 존재하지 않을 경우를 대비한 예외 처리를 반드시 구현하세요.
  2. 파일 크기: 너무 큰 파일을 처리하는 경우 성능 문제가 발생할 수 있으므로, 데이터를 효율적으로 관리해야 합니다.
  3. 보안: 민감한 데이터는 암호화를 통해 보호하세요.

결론

Flutter에서 파일 읽기와 쓰기는 강력하면서도 유연한 기능을 제공합니다. 이를 활용하면 사용자 경험을 개선하고 데이터 관리를 더 효율적으로 할 수 있습니다. 위에서 설명한 방법을 따라 파일 입출력을 시작해 보세요!

 

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(
    MaterialApp(
      title: 'Reading and Writing Files',
      home: FlutterDemo(storage: CounterStorage()),
    ),
  );
}

class CounterStorage {
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;
    return File('$path/counter.txt');
  }

  Future<int> readCounter() async {
    try {
      final file = await _localFile;

      // Read the file
      final contents = await file.readAsString();

      return int.parse(contents);
    } catch (e) {
      // If encountering an error, return 0
      return 0;
    }
  }

  Future<File> writeCounter(int counter) async {
    final file = await _localFile;

    // Write the file
    return file.writeAsString('$counter');
  }
}

class FlutterDemo extends StatefulWidget {
  const FlutterDemo({super.key, required this.storage});

  final CounterStorage storage;

  @override
  State<FlutterDemo> createState() => _FlutterDemoState();
}

class _FlutterDemoState extends State<FlutterDemo> {
  int _counter = 0;

  @override
  void initState() {
    super.initState();
    widget.storage.readCounter().then((value) {
      setState(() {
        _counter = value;
      });
    });
  }

  Future<File> _incrementCounter() {
    setState(() {
      _counter++;
    });

    // Write the variable as a string to the file.
    return widget.storage.writeCounter(_counter);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Reading and Writing Files'),
      ),
      body: Center(
        child: Text(
          'Button tapped $_counter time${_counter == 1 ? '' : 's'}.',
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}