Skip to content

Instantly share code, notes, and snippets.

@tobischw
Last active March 8, 2023 15:32
Show Gist options
  • Save tobischw/98dcd2563eec9a2a87bda8299055358a to your computer and use it in GitHub Desktop.
Save tobischw/98dcd2563eec9a2a87bda8299055358a to your computer and use it in GitHub Desktop.
Recursively copy directory in Dart (requires "path")
/*
* I'm sure there's a better way to do this, but this solution works for me.
* Recursively copies a directory + subdirectories into a target directory.
* You may want to replace calls to sync() with Futures. There's also no error handling. Have fun.
*/
import 'dart:io';
import 'package:path/path.dart' as path;
void copyDirectory(Directory source, Directory destination) =>
source.listSync(recursive: false)
.forEach((var entity) {
if (entity is Directory) {
var newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path)));
newDirectory.createSync();
copyDirectory(entity.absolute, newDirectory);
} else if (entity is File) {
entity.copySync(path.join(destination.path, path.basename(entity.path)));
}
});
// HOW TO USE IT:
copyDirectory(Directory('cool_pics/tests'), Directory('new_pics/copy/new'));
@gaddlord
Copy link

gaddlord commented Dec 25, 2022

Slightly extended version written as extension with ability to skip files and directories (similar to Power Shell Copy-Item cmdlet):

import 'dart:io';

import 'package:path/path.dart' as path;

extension DirectoryHelper on Directory {
  /// Recursively copies a directory + subdirectories into a target directory.
  /// Similar to Copy-Item in PowerShell.
  void copyTo(
    final Directory destination, {
    final List<String> ignoreDirList = const [],
    final List<String> ignoreFileList = const [],
  }) =>
      listSync().forEach((final entity) {
        if (entity is Directory) {
          if (ignoreDirList.contains(path.basename(entity.path))) {
            return;
          }
          final newDirectory = Directory(
            path.join(destination.absolute.path, path.basename(entity.path)),
          )..createSync();
          entity.absolute.copyTo(newDirectory);
        } else if (entity is File) {
          if (ignoreFileList.contains(path.basename(entity.path))) {
            return;
          }
          entity.copySync(
            path.join(destination.path, path.basename(entity.path)),
          );
        }
      });
}

Ignore lists can be further extended with Glob expressions using https://pub.dev/packages/glob

@brian-at-pieces
Copy link

@gaddlord thanks for this! One small fix though - in order to properly ignore dirs and files you need to pass in the ignore lists on each recursive call as well:
entity.absolute.copyTo(newDirectory, ignoreDirList: ignoreDirList, ignoreFileList: ignoreFileList);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment