Dart 語言標準流與檔案操作

程式設計之路從0到1發表於2019-09-16

標準輸入輸出流

  • stdin
  • stdout
  • stderr
// 匯入io包
import 'dart:io';

void main() {
  // 向標準輸出流寫字串
  stdout.write('root\$:');
  // 從標準輸入流讀取一行字串
  var input = stdin.readLineSync();
  // 帶換行符的寫資料
  stdout.writeln("input data:$input");
  // 向標準錯誤流寫資料
  stderr.writeln("has not error");
}
複製程式碼

stdin除了可以使用readLineSync讀一行字串,還可以使用readByteSync讀取一個位元組。

檔案操作

寫檔案

一種簡便的操作方式,無需手動關閉檔案,檔案寫入完成後會自動關閉

import 'dart:io';

void main() async{
  // 建立檔案
  File file = new File('test.txt');
  String content = 'The easiest way to write text to a file is to create a File';

  try {
    // 向檔案寫入字串
    await file.writeAsString(content);
    print('Data written.');
  } catch (e) {
    print(e);
  }
}
複製程式碼

writeAsString原型

  Future<File> writeAsString(String contents,
      {FileMode mode: FileMode.write,
      Encoding encoding: utf8,
      bool flush: false})
複製程式碼
  • mode 檔案模式,這裡預設為寫模式
  • encoding 字元編碼,預設為utf-8
  • flush 是否立刻重新整理快取,預設為false

檔案模式FileMode的常量

常量值 說明
read 只讀模式
write 可讀可寫模式,如果檔案存在則會覆蓋
append 追加模式,可讀可寫,檔案存在則往末尾追加
writeOnly 只寫模式
writeOnlyAppend 只寫模式下的追加模式,不可讀

除了writeAsString方法外,還可以使用writeAsBytes寫入一個位元組列表。需要注意的是,這兩個方法都是非同步執行的,返回值都是Future,如果有必要,也可以使用同步方法執行寫入操作

  • writeAsStringSync
  • writeAsBytesSync

如需要更靈活的控制,可以使用如下方式操作檔案,但是需要手動關閉檔案

import 'dart:io';

void main() async{
  // 建立檔案
  File file = new File('test.txt');
  // 檔案模式設定為追加
  IOSink isk = file.openWrite(mode: FileMode.append);

  // 多次寫入
  isk.write('A woman is like a tea bag');
  isk.writeln('you never know how strong it is until it\'s in hot water.');
  isk.writeln('-Eleanor Roosevelt');
  await isk.close();
  print('Done!');
}
複製程式碼

讀檔案

簡便的方式

  • readAsBytes
  • readAsBytesSync
  • readAsString
  • readAsStringSync
  • readAsLines
  • readAsLinesSync
void main() async{
  File file = new File('test.txt');
  try{
    String content = await file.readAsString();
    print(content);
  }catch(e){
    print(e);
  }
}
複製程式碼

另一種更低階別的方式

import 'dart:io';
import 'dart:convert';

void main() async{
  try {
    // LineSplitter Dart語言封裝的換行符,此處將文字按行分割
    Stream lines = new File('test.txt').openRead()
    	.transform(utf8.decoder).transform(const LineSplitter());

    await for (var line in lines) {
      print(line);
    }
  } catch (_) {}
}
複製程式碼

檔案的其他操作

import 'dart:io';

void main() async{
  File file = new File('test.txt');

  // 判斷檔案是否存在
  if(await file.exists()){
    print("檔案存在");
  }else{
    print("檔案不存在");
  }

  // 複製檔案
  await file.copy("test-1.txt");

  // 修改檔名。當傳入不同路徑時,可用來移動檔案
  await file.rename("test-2.txt");
  
  // 獲取檔案 size
  print(await file.length());
}
複製程式碼

相應的,這些方法還有一個帶Sync字尾的同步版本方法,例如copySyncrenameSync等。

要獲取檔案更多的資訊,還可以使用File等多個類的超類FileSystemEntity來操作

import 'dart:io';

void main() async{
  String path = 'test.txt';

  // 判斷路徑是否是資料夾
  if (!await FileSystemEntity.isDirectory(path)) {
    print('$path is not a directory');
  } 

 Directory dir = Directory(r'D:\workspace\dart_space\Tutorial');
 // 目錄是否存在
 if(await dir.exists()){
   // 從目錄的list方法獲取FileSystemEntity物件
   Stream<FileSystemEntity> fse = await dir.list();
   await for (FileSystemEntity entity in fse) {
     if(entity is File){
       print("entity is file");
     }

     // 列印檔案資訊
     print(await entity.stat());
     // 刪除
     await entity.delete();
   }
 }else{
   // 不存在則建立。recursive為true時,建立路徑上所有不存在的目錄
   await dir.create(recursive: true);
 }
}
複製程式碼

需注意,delete中包含一個可選的引數,原型Future<FileSystemEntity> delete({bool recursive: false})recursive預設為false,當刪除目錄時,目錄必須為空才能刪除;當recursive設定為true時,將刪除目錄下的所有子目錄及檔案。

關注我的公眾號:程式設計之路從0到1

程式設計之路從0到1

相關文章