Dart: การจัดการ File และ Directory เบื้องต้น

ในการเขียน native แอป เพื่ออ่าน File และ Directory จากเครื่องที่แอปทำงานอยู่ สามารถใช้งานผ่าน dart:io การใช้งานจะต้องประกาศ import 'dart:io'; เพื่อให้สามารถเรียกใช้งาน class File Directory Link สำหรับเข้าถึงไฟล์ในดิสก์หรือ network ได้ โดยตัว API จะรองรับทั้งแบบ synchronous และ asynchronous โดยสังเกตได้จากคำสั่งที่ลงท้ายด้วย *Sync จะเป็นการทำงานแบบ synchronous

รู้จัก FileSystemEntity class

class File Directory Link ต่าง implement FileSystemEntity class ซึี่งเป็น abstract class จะมีคำสั่งที่ช่วยในการจัดการ File และ Directory ที่เหมือนกัน และยังมี static method ช่วยในการทำงานอีกด้วย

FileSystemEntity class

Parent directory ของ entity ด้วยคำสั่ง .parent

ไม่ว่าจะเป็น File หรือ Directory จะต้องบรรจุอยู่ใน Directory ที่เป็น parent อีกที หากต้องการใช้งานสามารถใช้คำสั่ง .parent เพื่อคืนค่ากลับมาเป็น Directory Link class ในกรณีที่ตัว entity ที่อ้างอิงอยู่ใน root directory ทำให้ parent คืนค่ากับมาเป็น root directory

import 'dart:io';

void main() {
  File iniFile = File(r'C:\Windows\win.ini');
  Directory parent = iniFile.parent;
  print(parent); // output → Directory: 'C:\Windows'

  Directory c = Directory(r'C:\');  // root directory
  print(c.parent); // output → Directory: 'C:\'
}

อีกวิธีโดยการใช้ static method .parentOf() ของ FileSystemEntity โดยจะคืนมาเป็น String ที่เป็นตัว parent ของ path ที่ต้องการ

import 'dart:io';

void main() {
  String parent;
  
  parent = FileSystemEntity.parentOf(r'C:\Windows\win.ini');
  print(parent); // output → C:\Windows

  parent = FileSystemEntity.parentOf(r'C:\Windows\.');
  print(parent); // output → C:\Windows

  parent = FileSystemEntity.parentOf(r'C:\Windows\');
  print(parent); // output → C:\

  parent = FileSystemEntity.parentOf(r'C:\');
  print(parent); // output → C:\

  parent = FileSystemEntity.parentOf(r'\\server1\folder1\.');
  print(parent); // output → \\server1\folder1

  parent = FileSystemEntity.parentOf(r'\\server1\folder1\');
  print(parent); // output → \\server1

  parent = FileSystemEntity.parentOf(r'\\server1\folder1');
  print(parent); // output → \\server1
}

อ่าน Path และ Absolute path ของ entity

เนื่องจากในการอ้างถึงตำแหน่งของ entity สามารถระบุได้ทั้งแบบ absolute หรือ relative ก็ได้ โดยใช้คำสั่ง .path คืนค่ามาเป็นข้อความของ path ที่ใช้สร้าง entity ดังนั้นในกรณีที่อ่านค่า path ของ entity อาจได้แบบ relative มา หากต้องการค่าของ path แบบ absolute ต้องใช้คำสั่ง .absolute โดยจะคืนค่ากลับมาเป็น entity แบบเดียวกัน

import 'dart:io';

void main() {
  File iniFile = File(r'C:\Windows\win.ini');
  Directory parent = iniFile.parent;
  print(iniFile.path); // output → c:\Windows\win.ini
  print(parent.path); // output → c:\Windows

  File someFile = File(r'dart_file.dart');
  File fullPath = someFile.absolute;
  print(someFile.path); // output → dart_file.dart
  print(fullPath.path); // output → C:\src\dart\dart_tester\dart_file.dart

  Directory currentPath = Directory('.');
  Directory currentAbsolute = currentPath.absolute;
  print(currentPath.path); // output → .
  print(currentAbsolute.path); // output → c:\src\dart\dart_tester\

  Directory currentAbsolute2 = Directory('.').absolute;
  print(currentAbsolute2.path); // output → c:\src\dart\dart_tester\
}

หากต้องการตรวจสอบว่า ตัวข้อความที่ใช้สร้าง entity เป็นการอ้างอิงแบบ absolute หรือไม่ สามารถใช้คำสั่ง .isAbsolute ตรวจสอบได้

import 'dart:io';

void main() {
  File iniFile = File(r'C:\Windows\win.ini');
  File someFile = File(r'dart_file.dart');

  print(iniFile.isAbsolute); // output → true
  print(someFile.isAbsolute); // output → false
}

ตรวจสอบว่า entity มีอยู่จริงหรือไม่

เมื่อระบุข้อความที่เป็นตำแหน่ง path ของ File Directory หรือ Link ในกรณีที่ต้องการระบุถึง entity ที่มีอยู่แล้ว ไม่ใช่ต้องการสร้างใหม่ ก่อนการเข้าถึงจำเป็นต้องทำการตรวจสอบก่อนว่า entity มีอยู่จริงหรือไม่ ด้วยคำสั่ง .exists() และ .existsSync() หากไม่ตรวจสอบก่อนว่ามีอยู่หรือไม่ จะเกิด error ขึ้นได้เมื่อทำการอ่านข้อมูลจาก entity ดังกล่าว

import 'dart:io';

void main() {
  File someFile = File(r'C:\Windows\win.ini');
  if (someFile.existsSync()) {
    print(someFile.lastModifiedSync()); // output → 2019-12-07 16:12:42.000
  } else {
    print("${someFile.path} not found.");
  }

  // try to get information from non-existent file
  File newFile = File(r'C:\newfile.txt'); // no file on disk
  print(newFile.lastModified()); // PathNotFoundException: Cannot retrieve modification time
}

ตรวจสอบว่า entity เป็น File Directory หรือ Link

เมื่อใช้คำสั่งจำพวกอ่านข้อมูล entity จาก Directory เช่น คำสั่ง .list() หรือ .listSync() ผลที่ได้จากคำสั่งจะเป็น List ของ FileSystemEntity ดังนั้น หากต้องการจะเลือกเฉพาะ File หรือ Directory อย่างใดอย่างหนึ่ง สามารถใช้คำสั่งต่อไปนี้เพื่อตรวจสอบ path ของ FileSystemEntity ได้

import 'dart:io';

void main() {
  // test exists file with absolute path
  File file1 = File(r'C:\Windows\win.ini');
  print(FileSystemEntity.isFileSync(file1.path)); // output → true

  // test exists file with relative path
  File file2 = File(r'README.md');
  print(FileSystemEntity.isFileSync(file2.path)); // output → true

  // test for non-existent file
  File file3 = File(r'C:\no_file.xxx');
  print(FileSystemEntity.isFileSync(file3.path)); // output → false

  // test path of directory
  print(FileSystemEntity.isFileSync(r'C:\Windows')); // output → false

  // don't use [is] operator to test entity like this
  File windows = File(r'C:\Windows');
  print(windows is File); // output → true
}

อีกตัวอย่าง ในกรณีที่คำสั่ง .list() และ .listSync() ของ Directory class จะคืนค่ามาเป็น List<FileSystemEntity> โดยเมื่อลองพิมพ์ค่าใน List ที่ได้คืนมาจะพบว่ามันเป็น File class และ Directory class ตามประเภท entity จึงสามารถใช้ is เพื่อทดสอบว่าเป็น File หรือ Directory ได้ หรือจะเอา .path ของ entity ใน List มาทดสอบด้วย .isFile() .isFileSync() .isDirectory() .isDirectoryeSync() .isLink() .isLinkSync() ก็ได้เช่นเดียวกัน

import 'dart:io';

void main() {
  // list file and directory in current directory
  List<FileSystemEntity> results = Directory.current.listSync();

  print(results); /* output → 
  [ 
    Directory: 'C:\src\dart\dart_tester\.dart_tool', 
    File: 'C:\src\dart\dart_tester\.gitignore', 
    File: 'C:\src\dart\dart_tester\analysis_options.yaml', 
    Directory: 'C:\src\dart\dart_tester\bin'
  ]
  */

  // It OK to test an entity in List with [is] operator
  for (FileSystemEntity f in results) {
    if (f is File) {
      print("$f is File");
    } else if (f is Directory) {
      print("$f is Directory");
    }
  }
}

อีกวิธีที่ใช้ตรวจสอบประเภทของ entity คือคำสั่ง .type() และ .typeSync() โดยจะคืนค่ามาเป็น FileSystemEntityType ในตัวอย่างด้านล่างจะเป็นการตรวจสอบว่า path ที่ระบุเป็น entity ประเภทใด

import 'dart:io';

void main() {
  String unknowPath = r'./point/to/path/file/link';

  switch (FileSystemEntity.typeSync(unknowPath)) {
    case FileSystemEntityType.directory:
      print('$unknowPath is directory');
      break;
    case FileSystemEntityType.file:
      print('$unknowPath is file');
      break;
    case FileSystemEntityType.link:
      print('$unknowPath is link');
      break;
    case FileSystemEntityType.notFound:
      print('$unknowPath is not found'); // output → ./point/to/path/file/link is not found
      break;
    default:
      print('$unknowPath is something wrong');
  }
}

การเปลี่ยนชื่อ entity หรือย้ายไปอยู่ directory ใหม่ ด้วย .rename() .renameSync()

ทั้ง File และ Directory สามารถเปลี่ยนชื่อได้จากคำสั่ง .rename() และ .renameSync() โดยกำหนดชื่อใหม่ที่ต้องการ โดยหากไม่สามารถเปลี่ยนชื่อได้ จะเกิด exception

ตัวอย่างการเปลี่ยนชื่อแบบ relative หากไม่ระบุ path ใหม่ ระบุแค่ชื่ออย่างเดียว จะเปลี่ยนชื่อโดยยังอยู่ใน Directory เดิม

import 'dart:io';

void main() {
  try {
    File textFile = File('test.txt');
    File renameFile = textFile.renameSync('test1.txt');
    print(renameFile); // output → File: 'test1.txt'
  } catch (e) {
    print('Error: $e');
  }
}

ในกรณีที่ entity ระบุแบบ absolute path แต่ต้องการเปลี่ยนแค่ชื่อ entity ไม่ต้องการเปลี่ยน path สามารถทำได้ดังนี้

import 'dart:io';

void main() {
  try {
    File textFile = File(r'C:\src\dart\dart_tester\test.txt');
    File renameFile = textFile.renameSync('test1.txt');
    print(renameFile); // output → File: 'test1.txt'
    print(renameFile.absolute); // output → File: 'C:\src\dart\dart_tester\test1.txt'
  } catch (e) {
    print('Error: $e');
  }
}

หากต้องการย้าย entity ไปอยู่ตำแหน่ง path ใหม่ สามารถระบุได้ทั้งแบบ absolute หรือ relative ก็ได้เช่นกัน

import 'dart:io';

void main() {
  try {
    File textFile = File(r'C:\src\dart\dart_tester\test.txt');
    File renameFile = textFile.renameSync(r'test\test.txt'); // move to sub directory
    print(renameFile); // output → File: 'test\test.txt'
    print(renameFile.absolute); // output → File: 'C:\src\dart\dart_tester\test\test.txt'
  } catch (e) {
    print('Error: $e');
  }
}

File class

ตัว File class จะมีคำสั่งในการช่วยจัดการ file บนดิสก์หรือเซิร์ฟเวอร์ ตั้งแต่ การสร้างไฟล์ การอ่านไฟล์ คัดลอก ลบ ฯลฯ

การสร้างไฟล์ใหม่ และการบันทึกข้อมูลลงในไฟล์

ในการสร้างไฟล์ใหม่ สามารถทำได้โดยการสร้าง File object ขึ้นมา โดยระบุชื่อไฟล์ที่ต้องการจะสร้าง จากนั้นให้ทำการเปิดไฟล์ เพื่อทำการเขียนข้อมูลลงไป

  • .create() .createSync() สร้างไฟล์ใหม่ตาม path ที่ระบุ โดยขนาดไฟล์จะเป็น 0 แต่ในกรณีที่ไฟล์ที่ระบุมีอยู่แล้ว จะไม่ทำอะไร
  • .writeAsString() .writeAsStringSync() ถ้าไม่มีไฟล์ จะสร้างไฟล์ใหม่ บันทึกข้อความ String ลงในไฟล์โดยตรง
  • .writeAsBytes() .writeAsBytesSync() ถ้าไม่มีไฟล์ จะสร้างไฟล์ใหม่ บันทึกข้อมูลที่เป็น List<int> ลงในไฟล์โดยตรง โดยสมาชิกที่อยู่ใน List จะมีค่าตั้งแต่ 0-255 ถ้ามากกว่านี้จะถูกแปลงให้ไม่เกิน 255
  • .open() .openSync() เปิดไฟล์เพื่อทำการบันทึกข้อมูล ผ่าน RandomAccessFile class
  • .openWrite() เปิดไฟล์เพื่อทำการบันทึกข้อมูล ผ่าน IOSink class

ตัวอย่างการใช้งานคำสั่ง .createSync() โดยหากถูกสร้างไฟแล้ว และเรียกทำคำสั่งซ้ำ คำสั่งจะไม่ทำอะไรกับไฟล์

import 'dart:io';

void main() {
  File testFile = File('test.txt');
  testFile.createSync(); // create new file if not exist
  print(testFile.lengthSync()); // output → 0

  testFile.writeAsStringSync('1234');
  print(testFile.lengthSync()); // output → 4

  testFile.createSync(); // file was created, do nothing
  print(testFile.lengthSync()); // output → 4
}

ตัวอย่างการสร้างไฟล์ โดยระบุข้อมูลที่จะเขียนลงไปด้วย ในกรณีที่มีไฟล์อยู่แล้ว จะเป็นการเขียนทับไฟล์เดิม

import 'dart:io';

void main() {
  File testFile = File('test.txt');

  // create empty file
  testFile.writeAsBytesSync([]);
  print(testFile.lengthSync()); // output → 0

  // create with text data
  testFile.writeAsStringSync('test data');
  print(testFile.lengthSync()); // output → 9
  print(testFile.readAsStringSync()); // output → test data

  // create with binary data
  testFile.writeAsBytesSync([100, 120, 150, 65535]);
  print(testFile.lengthSync()); // output → 4
  print(testFile.readAsBytesSync()); // output → [100, 120, 150, 255]
}

การลบไฟล์ ด้วยคำสั่ง .delete() .deleteSync()

ใช้คำสั่ง .delete() .deleteSync() เพื่อลบไฟล์ที่ระบุ หากไฟล์ไม่มีอยู่หากสั่งลบจะเกิด PathNotFoundException error

ตัวอย่างการสร้างไฟล์ใหม่ จากนั้นลบทิ้ง และลองพยายามลบไฟล์ที่ไม่มีอยู่แล้ว เพื่อให้เกิด error

import 'dart:io';

void main() {
  File testFile = File('test.txt');
  print(testFile.existsSync()); // output → false

  testFile.createSync();
  print(testFile.existsSync()); // output → true

  testFile.deleteSync();
  print(testFile.existsSync()); // output → false

  // try to delete non-existent file
  testFile.deleteSync(); // PathNotFoundException: Cannot delete file, path = 'test.txt'
}

การสำเนา file ด้วย .copy() .copySync()

คำสั่ง .copy() .copySync() จะทำงานเหมือนกับ .rename() และ .renameSync() สิ่งที่แตกต่างกันคือ ไฟล์ต้นฉบับจะยังอยู่

import 'dart:io';

void main() {
  File testFile = File('test.txt');
  testFile.createSync();
  print(testFile.existsSync()); // output → true

  File testFile2 = testFile.copySync('test2.txt');
  print(testFile.existsSync()); // output → true
  print(testFile2.existsSync()); // output → true
}

การอ่านข้อมูลจากไฟล์

  • .readAsBytes() .readAsBytesSync() อ่านข้อมูลแบบ binary คืนกลับมาเป็น List<int> โดยค่าใน List จะอยู่ในช่วง 0-255
  • .readAsString() .readAsStringSync() อ่านข้อมูลแบบข้อความ String โดยสามารถระบุ Encoding ของตัวข้อความว่าเป็นแบบใด ค่าปริยายคือ utf8
  • .readAsLines() .readAsLinesSync() อ่านข้อมูลแบบข้อความ String แต่ทำการแยกข้อมูลเป็นบรรทัดกลับมาในรูปของ List<String>
import 'dart:convert';
import 'dart:io';

void main() {
  File testFile = File('test.txt');

  // write and read simple text data
  testFile.writeAsStringSync('12345678');
  print(testFile.lengthSync()); // output → 8
  print(testFile.readAsStringSync()); // output → 12345678

  // write and read multi-line text
  testFile.writeAsStringSync('Line1\nLine2\nLine3');
  print(testFile.lengthSync()); // output → 17
  print(testFile.readAsLinesSync()); // output → [Line1, Line2, Line3]

  // write and read binary data
  testFile.writeAsBytesSync([1, 2, 3, 4]);
  print(testFile.lengthSync()); // output → 4
  print(testFile.readAsBytesSync()); // output → [1, 2, 3, 4]

  // write and read UTF-8 encode
  testFile.writeAsStringSync("ÀÁÂÃ", encoding: utf8);
  print(testFile.lengthSync()); // output → 8
  print(testFile.readAsStringSync(encoding: utf8)); // output → ÀÁÂÃ

  // write and read ISO Latin-1 encode
  testFile.writeAsStringSync("ÀÁÂÃ", encoding: latin1);
  print(testFile.lengthSync()); // output → 4
  print(testFile.readAsStringSync(encoding: latin1)); // output → ÀÁÂÃ
}

การเข้าถึงคุณสมบัติต่าง ๆ ของ File

การแก้ไขคุณสมบัติต่าง ๆ ของ File

คำสั่งข้างต้น หากการแก้ไขล้มเหลมจะเกิด FileSystemException error

Directory class

Directory class ใช้สำหรับสร้างและจัดการ directory ในดิสก์และเซิร์ฟเวอร์ ตัว API จะมีความคล้ายคลึงกับ File class แต่มีข้อจำกัดที่ไม่เหมือนกัน เช่น ไม่สามารถสั่ง copy ได้โดยตรง จากข้อจำกัดของระบบ File system ในแต่ละ OS ที่แตกต่างกัน

การสร้าง directory ด้วย .create() .createSync()

คำสั่ง .create() .createSync() ใช้สำหรับสร้าง directory ใหม่ โดยสามารถกำหนดค่า recursive ค่าปริยายเป็น false หากกำหนดเป็นค่า true จะทำการสร้าง sub directory ให้อัตโนมัต ในกรณีที่ directory นั้นมีอยู่แล้ว จะไม่ทำอะไร

import 'dart:io';

void main() {
  print(FileSystemEntity.isDirectorySync(r'.\test')); // output → true
  print(FileSystemEntity.isDirectorySync(r'.\test\sub1')); // output → false

  // try to create sub directory sub1\sub2 in .\test
  Directory subDir = Directory(r'.\test\sub1\sub2');
  subDir.createSync(recursive: true);

  print(FileSystemEntity.isDirectorySync(r'.\test\sub1')); // output → true
  print(FileSystemEntity.isDirectorySync(r'.\test\sub1\sub2')); // output → true
}

การสร้าง temporary directory เพื่อใช้งานชั่วคราว

คำสั่ง .createTemp() .createTempSync() จะเป็นการ directory สำหรับใช้งานชั่วคราวขึ้นมา โดยผู้ใช้สามารถระบุ prefix เพื่อนำไปใช้ในการสร้างได้ ตัว API จะทำการสุ่มตัวอักษรต่อท้าย เพื่อให้ไม่ซ้ำกับ directory อื่น ๆ หากไม่ระบุ prefix จะใช้ empty string เป็น prefix

หากต้องการสร้าง directory ชั่วคราวใน system temp directory สามารถค่าคงที่ Directory.systemTemp เพื่อใช้งาน Directory ของ Temp ระบบปฏิบัติการได้

import 'dart:io';

void main() {
  // This is the system temp directory. ( same as %temp% )
  print(Directory.systemTemp.path); // output → C:\Users\chari\AppData\Local\Temp

  // create temp directory inside system temp
  Directory temp = Directory.systemTemp.createTempSync('_test_temp_');
  print(temp); // output → Directory: 'C:\Users\chari\AppData\Local\Temp\_test_temp_78b5195b'

  // create temp directory with out prefix
  temp = Directory.systemTemp.createTempSync();
  print(temp); // output → Directory: 'C:\Users\chari\AppData\Local\Temp\f31e5a31'
}

การลบ directory

คำสั่ง .delete() .deleteSync() ใช้สำหรับลบ directory ที่ต้องการ โดยสามารถกำหนดค่า

  • recursive ค่าปริยายเป็น false โดย directory ที่จะลบต้องเป็น empty directory คือห้ามมีไฟล์หรือ sub directory ใด ๆ
  • หากกำหนดเป็นค่า true จะทำการลบ sub directory และ file ต่าง ๆ ที่อยู่ภายในให้อัตโนมัต

ในกรณีที่ล้มเหลวจะเกิด FileSystemException error กลับมา

ตัวอย่าง จะเป็นการลองพยายามลบ directory ที่ภายในมีไฟล์หรือ sub directory หากไม่กำหนด recursive = true จะเกิด error

import 'dart:io';

void main() {
  Directory test;

  // Example 1 ------------------------------------------------
  // create directory [sub1\sub2] in [.\test]
  test = Directory(r'.\test\sub1\sub2');
  test.createSync(recursive: true);

  // delete directory [sub1] with out recursive
  Directory sub1 = Directory(r'.\test\sub1');
  try {
    sub1.deleteSync(recursive: false);
    print('OK');
  } catch (e) {
    print(e); // output → FileSystemException: Deletion failed, path = '.\test\sub1'
  }

  // delete directory sub1 with recursive
  try {
    sub1.deleteSync(recursive: true);
    print('OK'); // output → OK
  } catch (e) {
    print(e);
  }

  // Example 2 ------------------------------------------------
  // create directory [sub1] in [.\test]
  test = Directory(r'.\test\sub1');
  test.createSync();
  // create text file in [sub1]
  File(r'.\test\sub1\somefile.txt').createSync();

  // delete directory [sub1] with out recursive
  try {
    sub1.deleteSync(recursive: false);
    print('OK');
  } catch (e) {
    print(e); // output → FileSystemException: Deletion failed, path = '.\test\sub1'
  }

  // delete directory sub1 with recursive
  try {
    sub1.deleteSync(recursive: true);
    print('OK'); // output → OK
  } catch (e) {
    print(e);
  }
}

การอ่าน file และ sub directory ทั้งหมดใน directory ด้วย .list() .listSync()

คำสั่ง .list() .listSync() จะไล่อ่านว่าใน directory ที่ระบุบรรจุ file และ directory อะไรบ้าง ผลที่ได้จะเป็น List<FileSystemEntity>

List<FileSystemEntity> listSync({
  bool recursive = false,
  bool followLinks = true,
})
Dsmurat, penubag, Jelican9, CC BY-SA 4.0

การใช้งาน recursive = true หาก directory ที่ระบุว่าจะเข้าไปไล่ดูข้อมูล file ภายในมี file และ sub directory จำนวนมาก ควรใช้คำสั่ง .list() เพื่อให้ประสิทธิภาพการทำงานของแอปเป็นไปอย่างราบรื่น และไม่หยุดตอบสนองกับผู้ใช้

import 'dart:io';

void main() {
  // list file and directory in current directory
  List<FileSystemEntity> results = Directory.current.listSync();

  print(results);

  // [recursive = true] for scan all sub directory and files
  Future<List<FileSystemEntity>> resultBackground = Directory.current.list(recursive: true).toList();
  resultBackground.then((value) => print(value));

  print('wait for list of ${Directory.current}');
}

ผลที่ได้

[Directory: 'C:\src\dart\dart_tester.dart_tool', File: 'C:\src\dart\dart_tester.gitignore', File: 'C:\src\dart\dart_tester\analysis_options.yaml', Directory: 'C:\src\dart\dart_tester\bin', File: 'C:\src\dart\dart_tester\CHANGELOG.md', Directory: 'C:\src\dart\dart_tester\lib', File: 'C:\src\dart\dart_tester\pubspec.lock', File: 'C:\src\dart\dart_tester\pubspec.yaml', File: 'C:\src\dart\dart_tester\README.md', Directory: 'C:\src\dart\dart_tester\test', File: 'C:\src\dart\dart_tester\test.txt']
wait for list of Directory: 'C:\src\dart\dart_tester'
[Directory: 'C:\src\dart\dart_tester.dart_tool', File: 'C:\src\dart\dart_tester.dart_tool\package_config.json', File: 'C:\src\dart\dart_tester.gitignore', File: 'C:\src\dart\dart_tester\analysis_options.yaml', Directory: 'C:\src\dart\dart_tester\bin', File: 'C:\src\dart\dart_tester\bin\dart_duration.dart', File: 'C:\src\dart\dart_tester\bin\dart_enum.dart', File: 'C:\src\dart\dart_tester\bin\dart_file.dart', File: 'C:\src\dart\dart_tester\bin\dart_function.dart', File: 'C:\src\dart\dart_tester\bin\dart_regexp.dart', File: 'C:\src\dart\dart_tester\bin\dart_tester.dart', File: 'C:\src\dart\dart_tester\bin\dart_uri.dart', File: 'C:\src\dart\dart_tester\CHANGELOG.md', Directory: 'C:\src\dart\dart_tester\lib', File: 'C:\src\dart\dart_tester\lib\dart_tester.dart', File: 'C:\src\dart\dart_tester\pubspec.lock', File: 'C:\src\dart\dart_tester\pubspec.yaml', File: 'C:\src\dart\dart_tester\README.md', Directory: 'C:\src\dart\dart_tester\test', File: 'C:\src\dart\dart_tester\test.txt']

Exited.

อ้างอิงตำแหน่ง current directory ที่กำลังทำงานอยู่

คำสั่ง .current จะคืนค่าเป็น Directory ที่กำลังทำงานอยู่ เพื่อใช้อ้างกับการระบุ path ที่เป็นแบบ relative

Dsmurat, penubag, Jelican9, CC BY-SA 4.0

current directory ไม่จำเป็นต้องเป็น directory ที่ไฟล์ executable ของแอปอยู่เสมอไป เพราะในกรณีที่สร้าง shortcut เพื่อเรียกใช้แอป อาจระบุเป็น directory อื่นได้

import 'dart:io';

void main() {
  print(Directory.current); // output → Directory: 'C:\src\dart\dart_tester'
}

Link

Link class เป็นการสร้าง Symbolic Link ถ้าใน Windows คือการใช้คำสั่ง mklink จากที่ลองทดสอบดู พบว่าหากไม่ได้ให้สิทธิ์ Administrator กับแอป จะไม่สามารถสร้างได้ และเกิด FileSystemException error

ตัวอย่างการสร้าง Link เทียบกับคำสั่ง mklink /D E:\sub1\source E:\source

import 'dart:io';

void main() {
  // cmd>mklink /D E:\sub1\source E:\source

  try {
    Link source = Link(r'E:\sub1\source');
    source.createSync(r'E:\source');
    print('Link created.');
  } catch (e) {
    print(e);
  }
}