inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

StreamSubscription listen 내부에서 file copy 이슈

217

ststxx

작성한 질문수 1

0

안녕하세요. 학습내용을 확장하는 중 이슈가 있어서 문의드립니다.

윈도우 OS 타겟으로 개발 중이며,

특정폴더(origin)에 파일이 생성되는 event 발생 시 다른 특정폴더(target)로 파일을 복사하는 로직을 구현했습니다.

이슈는, 용량이 1kb로 작은 파일일 경우 잘 작동하지만, 용량이 몇mb 정도로 큰파일은 아래와 같은 예외가 발생하며 복사가 되지 않습니다.

예외는 다음과 같습니다.

Unhandled Exception: PathAccessException: Cannot copy file to 'C:\0.st\target\10.tdms', path = 'C:\0.st\origin\10.tdms' (OS Error: 다른 프로세스가 파일을 사용 중이기 때문에 프로세스가 액세스 할 수 없습니다.

, errno = 32)

#0      _checkForErrorResponse (dart:io/common.dart:55:9)

#1      File.copy.<anonymous closure> (dart:io/fileimpl.dart:356:7)

<asynchronous suspension>

 제가 파일을 복사하기 위해 구현한 함수는 아래와 같습니다.

중간에 newOriginFile.copy(copyFilePath); 부분에서 예외가 발생합니다.

참고로 copySync 메서드로 변경해 보았으나 같은 현상이 발생합니다.

복사할 대상 파일을 다른 프로세스에서 열지 않은 상태인데도 위와 같은 예외가 발생하여 디버깅이 안되는 상황입니다.

항상 감사합니다!

void _startEvaluationMode() {
    Navigator.pop(context, 'OK');
    // 계측 모드 시작
    setState(() {
      _evaluationMode = true;
    });
    // origin 경로 불러오기
    if (_directoryInfoBox.containsKey(DirectoryType.origin.name)) {
      setState(() {
        _originDirectory =
            Directory(_directoryInfoBox.get(DirectoryType.origin.name)!.path);
      });
      if (!_originDirectory!.existsSync()) {
        // 실제 origin 경로의 폴더가 존재하지 않는 상태
        // origin directory 확인하라는 alert dialog 보여주고 evaluation mode 종료
      }
      // origin 경로 워칭
      Stream<FileSystemEvent> originDirFileEvent = _originDirectory!.watch();
      print('start evaluation mode');

      // _streamListner = originDirFileEvent.listen((event) async {
      //   if (event.type == 1) {
      //     print('create event');
      //   }
      // });

      _streamListner = originDirFileEvent.listen((event) {
        // origin 경로에 새 파일이 생성된 경우 FileSystemCreateEvent type == 1
        if (event.type == 1) {
          print('created file: ${event.path}');
          final newOriginFile = File(event.path);

          // 포맷에 맞는 파일 이름 생성
          var newOriginFilename = p.basenameWithoutExtension(event.path);
          // print('base file name: ${newOriginFilename}');

          String testMethodRoadName =
              TestMethodRoadInfoManager.getNameById(newOriginFilename);
          // 중복되는 이름 확인
          // 파일 이름을 _ 로 분리하여 4번째 인덱스 값으로 구분
          List<String> existingTestMethodRoadNameList =
              _evaluationItem!.evaluationFileInfos!.map((fileInfo) {
            return p
                .basenameWithoutExtension(fileInfo.evaluationFilePath)
                .split('_')
                .first;
          }).toList();
          // print(existingTestMethodRoadNameList);
          //
          List<String> duplicatedList =
              existingTestMethodRoadNameList.where((name) {
            return name == testMethodRoadName;
          }).toList();
          String fileNameWithDuplicateCount = '';
          if (duplicatedList.isNotEmpty) {
            fileNameWithDuplicateCount =
                '${testMethodRoadName}_${duplicatedList.length + 1}';
          } else {
            fileNameWithDuplicateCount = '${testMethodRoadName}_1';
          }
          // print('road name: ${testMethodRoadName}');
          // var copyFilePath = p.join(_itemDirectory!.path,
          //     '${_itemFilePrefix}_${fileNameWithDuplicateCount}.tdms');
          var copyFilePath = p.join(
              _itemDirectory!.path, '${fileNameWithDuplicateCount}.tdms');
          print('copy file path: ${copyFilePath}');

          // 파일을 eval item 경로로 이름 바꾸어 복사
          newOriginFile.copy(copyFilePath);
          print('copy finish');

          // eval item DB의 evaluationFileInfos 리스트 업데이트
          var newEvaluationFileInfo = EvaluationFileInfo(
            originFilePath: event.path,
            evaluationFilePath: copyFilePath,
            activated: true,
          );
          setState(() {
            _evaluationItem!.evaluationFileInfos!.add(newEvaluationFileInfo);
          });
          // print(
          //     'file info length: ${_evaluationItem!.evaluationFileInfos!.length}');
          _evaluationItemBox.put(_evaluationItem!.id, _evaluationItem!);

          // ui 상 file list, count 업데이트
          List<File> files = [];
          for (var entity in _itemDirectory!
              .listSync(recursive: false, followLinks: false)) {
            if (entity is File) {
              files.add(entity);
            }
          }
          setState(() {
            _files = files;
          });
        }
      });
    }
  }

flutter

답변 1

1

코드팩토리

안녕하세요!

의심하시는 것 처럼 파일 크기의 문제가 아닐 가능성이 높습니다. (부가적인 이유일수는 있습니다.)

에러 메세지를 잘 읽어보시면 "다른 프로세스가 파일을 사용 중이기 때문에 프로세스가 액세스 할 수 없습니다."라고 나와있습니다.

말 그대로 이미 열려있는 또는 사용중인 파일을 다시 접근하려고하니 문제가 생기는겁니다.

파일이 큰 경우에만 에러가 난다면 파일의 크기가 작은 경우 동시 접근 문제가 생기기 전에 파일 관련 작업이 끝나기 때문일 수 있습니다.

어찌됐든 모든 IO 관련 작업은 파일 크기와 관련 없이 이미 접근중인 파일은 다시 접근하지 못하도록 코드를 작성하시는게 중요합니다.

감사합니다!

0

ststxx

파일이 다른곳에서 접근하는 로직은 없었으나, 일단 말씀하신바와 같이 파일이 열려있다는 에러였기때문에, 타겟 파일이 available한 상태가 될때까지 잠시 기다리는 로직을 추가하여 기능 구현은 했습니다. 왜 어디서 리소스를 잡고 있는지 모르겠으나...일단 해결이 되어 다행입니다.

198강 (){onTap(e);}의 이해 돕기

0

29

1

video_call 플러그인 설치후 에러 발생

0

46

1

SDK 안드로이드 설치 질문!

0

60

1

코드팩토리 디스코드 링크 다시 부탁드려요~

0

92

1

Webview를 이용해서 URL 상의 페이지 출력 불가

0

70

1

홈스크린 함수를 함축해서 main.dart에 옮기는 문제

0

55

1

플레이스토어

0

59

1

아고라 엔진 init 함수의 반환타입이 Future<void> 이것의 의미는 무엇인가요?

0

55

1

가이드라인 질문

0

57

0

emulator 에러 환경설정 뭐가 문제 일까요??

0

77

1

emulator 실행 오류

0

93

3

Column을 가로방향 최대 사이즈를 차지하도록 하는 방법에 관련

0

71

1

pubspec.yaml에서 font를 추가하면서 weight 값을 지정하는 것이 의미가 있는 것인지 문의

0

43

1

setState()를 호출하지 않으면 build가 실행 안되는 건가요?

0

53

1

video_call 플러그인 설치시 에러문제

0

64

1

children 안의 if 문에서 { } 못쓰는 이유?

0

48

1

이렇게 오류가 떠요

0

64

1

AppBar 사용했는데

0

61

2

[문제해결] '오늘도 출첵!' 의 171번 강의에서 중요한 문제를 발견했습니다

0

56

1

StatefulWidget 실습 에러가 발생합니다.[해결완료]

0

63

1

Video Player 프로젝트에 대한 추가 질문

0

53

0

Row위젯이나 column위젯의 위치는 누가 정하나요??

0

42

1

geolocator 오류때문에 개발진행이 불가능입니다

0

63

1

API 관련 이슈

0

86

2