android flutter:文件操作与网络请求

一、获取Android的文件路径
使用PathProvider插件获取文件路径,需要再pubspec.yaml添加依赖;添加后执行命令 “flutter packages get”,成功后即可使用。

path_provider: ^0.4.1

在这里插入图片描述
PathProvider 插件获取文件路径有3钟:
1、getTemporaryDirectory:此方法获取临时目录,Android上对应getCacheDir()目录,即data/data/packageName/cache。
2、getApplicationDocumentsDirectory:此方法获取应用程序的文档目录,Android上对应/data/data/packageName/app_flutter目录
3、getExternalStorageDircetory:此方法获取外部存储目录,Android上对应getExternalStorageDirectory目录,即外部分出目录根目录。
注意:Android系统操作sd卡文件需要读写权限。在AndroidManifest.xml中添加读写权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

二、文件夹常用操作
1、创建目录:

var rootDir = await getTemporaryDirectory();
Directory('$rootDir${Platform.pathSeparator}dir1').create();

create中有一个可选参数recursive,默认值为false,false表示只能创建最后一级文件夹,如果创建“dir1/dir2”这种嵌套文件夹,recursive为false时将抛出异常,而设置为true可以创建嵌套文件夹。例如,在根目录创建“dir1/dir2”文件夹,如下:

var rootDir = await getTemporaryDirectory();
      var dir2 = await 
      Directory('$rootDir${Platform.pathSeparator}dir1${Platform.pathSeparator}dir2${Platform.pathSeparator}').create(recursive: true);

2、重命名目录

var dir3 = await dir2.rename('${dir2.parent.absolute.path}/dir3');

3、删除目录

await dir3.delete();
      await dir2.delete(recursive: true);

recurise设置为true,删除当前文件夹及文件夹下所有内容。

4、遍历目录下文件

Stream<FileSystemEntity> fileList = rootDir.list(recursive: false) ;
      await for (FileSystemEntity entity in fileList) {
        print(entity.path);
      }

recursive默认为false,表示只遍历当前目录;设置为true,表示遍历当前目录及子目录。
三、文件常用操作
1、创建文件

 var rootDir = await getTemporaryDirectory();
 var filetest = await File('$rootDir/dir1/file.txt').create(recursive: true);

2、写入文件

//字符串写入文件
      filetest.writeAsString("Flutter 实践入门");
      //将byte写入文件
      filetest.writeAsBytes(Utf8Encoder().convert("Flutter 实践入门"));
      //向文件末尾追加内容
      filetest.openWrite(mode: FileMode.append).write("Flutter 实践入门\n");

3、读取文件

//读取一行内容
      List<String> lines = await filetest.readAsLines();

4、删除文件

 filetest.delete();

四、HTTPClient网络请求(不常用)
HTTP网络请求方式包含GET、 POST、 HEAD 、PUT 、DELETE、 TRACE 、CONNECT 、OPTIONSD等。本节介绍dart:io。
发起一个HTTP请求需要如下5个步骤:
1、创建HttpClient。

var httpClient = new HttpClient();

2、构建Uri.

var uri = Uri(scheme: 'http',host: 'www.baidu.com',queryParameters: {
      'params1:':'',
      'params2:':'',
    });

3、打开HTTP连接

HttpClientRequest request = await httpClient.getUrl(uri);

4、设置header
需要通过HttpClientRequest设置header

HttpClientRequest request = await httpClient.getUrl(uri);
    request.headers.add('','');

5、发送请求并接续返回的数据。

ttpClientResponse response = await request.close();
    String responseBody = await response.transform(utf8.decoder).join();

五、dio 网络请求(常用)
使用dio需要添加依赖,在pubspec.yaml中添加,用flutter packages get命令获取:

dio: ^3.0.7

建议将dio设置为单例,这样可以对所有的HTTP请求进行同意配置,比如超时设置、公共header、cookie等。设置统一参数方法:

var options = BaseOptions(
      baseUrl: '_host',
      connectTimeout: 5000,
      receiveTimeout: 3000,
    );
    Dio _dio = Dio(options);

1、发起请求
(1)发起get请求

Response response = await _dio.get("/test ? id = 12&name = flutter");
print(response.data.toString());

(2)发起post请求

 Response response = await _dio.post("/test",data: {"id":12,"name":"flutter"});
 print(response.data.toString());

(3)发起多个并发请求

List<Response> response = await Future.wait([_dio.post("/info"),_dio.get("/token")]);

2、下载文件

await _dio.download(urlPath, savePath,onReceiveProgress: (count,total) {
      //下载进度回调
    });

3、发送FormData

FormData formData = FormData.fromMap({
      "name":"flutter",
      "age":25,
    });
    Response response = await _dio.post("/info",data: formData);

4、通过FormData上传多个文件

 FormData formData = FormData.fromMap({
      "name":"flutter",
      "age":25,
      "file":await MultipartFile.fromFile("./text.txt",filename: "upload.txt"),
      "files":[
        await MultipartFile.fromFile("./text1.txt",filename: "upload1.txt"),
        await MultipartFile.fromFile("./text2.txt",filename: "upload2.txt"),
    ],
    });
    Response response = await _dio.post("/info",data: formData);

5、监听发送(上传)数据进度

 Response response = await _dio.post("/info",data: formData,onSendProgress: (int send,int total){
      print("$send,$total");
    });

六、json数据转Model
老孟《flutter入门实践》148页,需要的时候再学习。

七、项目实践:记事本
完整程序可以运行


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

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: NodeDemo(),
    );
  }
}

class NodeDemo extends StatefulWidget{

  @override
  State<StatefulWidget> createState() {
    return _NodeDemo();
    throw UnimplementedError();
  }
}
class NoteInfo {
  const NoteInfo(this.name, this.path,this.updateTime);
  final String name;
  final String path;
  final DateTime updateTime;
}

String getFileNameFromPath(String path){
  int index = path.lastIndexOf('/');
  if (index <= 0) {
    return path;
  }
  return path.substring(index + 1);
}

class _NodeDemo extends State<NodeDemo> {
  @override
  void initState() {
    _loadNote();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _noteList.length == 0 ? _buildEmpty() : _buildList(),
      floatingActionButton: RaisedButton(
        padding: EdgeInsets.all(10),
        child: Icon(
          Icons.mode_edit,
          color: Theme.of(context).primaryColor,
          size: 35,
        ),
        shape: CircleBorder(),
        onPressed: () async {
          var result = await Navigator.of(context).push(MaterialPageRoute(builder: (context) {
           return NoteEdit("");
          }));
          _loadNote();
        },
      ),

    );
    throw UnimplementedError();
  }

  //构建日记列表
  _buildList() {
    return ListView.separated(
        itemBuilder: (context,index) {
          return InkWell(
            onTap: () async {
              var result = await Navigator.of(context).push(MaterialPageRoute(builder: (context) {
                return NoteEdit(_noteList[index].path);
              }));
              _loadNote();
            },
            child: Container(
              child: ListTile(
                title: Text('${_noteList[index].name}'),
                subtitle: Text('${_noteList[index].updateTime}'),
              ),
            ),
          );
        },
        separatorBuilder: (context,index) {
          return Divider(
            height: 1,
          );
        },
        itemCount: _noteList.length);
  }

  List<NoteInfo> _noteList = [];
  //遍历已经存在的日记
  _loadNote() async {
    //遍历日记目录下所有文件
    getTemporaryDirectory().then((dir) async {
      List<FileSystemEntity> dirs = dir.listSync(recursive: false);
      List<FileSystemEntity> files = [];
      for (var dir in dirs) {
        if ((await dir.stat()).type == FileSystemEntityType.file) {
          files.add(dir);
        }
      }
      //排序
      files.sort((f1, f2) {
        try {
          var dt1 = File(f1.path).lastModifiedSync();
          var dt2 = File(f2.path).lastModifiedSync();
          return dt2.millisecondsSinceEpoch - dt1.millisecondsSinceEpoch;
        } catch (e) {
          print(e);
          return 0;
        }
      });
      _noteList.clear();
      //将文件转换为日记信息
      files.forEach((f) {
        var file = File(f.path);
        if (file.path.endsWith('txt')) {
          _noteList.add(NoteInfo(getFileNameFromPath(file.path), file.path,
              file.lastModifiedSync()));
        }
      });
      setState(() {

      });
    });
  }

  //构建没有写日志的界面
  _buildEmpty(){
    return Center(
      child: Text('空空如也,快去写日志吧!',style: TextStyle(color: Colors.black.withOpacity(0.6),),),
    );
  }

}


class NoteEdit extends StatefulWidget {
  String path;
  NoteEdit(String path) {
    this.path = path;
  }

  @override
  State<StatefulWidget> createState() {
    return _NoteEdit();
    throw UnimplementedError();
  }

}

class _NoteEdit extends State<NoteEdit> {

  TextEditingController _titleController;
  TextEditingController _contentController;
  @override
  void initState() {
    _titleController = TextEditingController();
    _contentController = TextEditingController();
    _loadData();
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          IconButton(
              icon: const Icon(Icons.done),
              tooltip: 'Show Snackbar',
              onPressed: () {
                _save();
              },
          ),
        ],
      ),
      body: SafeArea(
          child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 10),
            child: Column(
              children: <Widget>[
                TextField(
                  controller: _titleController,
                  decoration: InputDecoration(hintText: '输入日记名称'),
                ),
                Expanded(
                  child: TextField(
                    controller: _contentController,
                    decoration: InputDecoration(
                      hintText: '开始你的故事'
                    ),
                    maxLines: 2000,
                  ),
                ),
              ],
            ),
          ),
      ),
    );
    throw UnimplementedError();
  }

  _loadData() async{
    if (widget.path != null) {
      var fileName = getFileNameFromPath(widget.path);
      print("lilili len = ${fileName.length}" );
      if (fileName.length != 0) {
        fileName = fileName.substring(0,fileName.length - 4);
        _titleController.text = fileName;
        var content = Utf8Decoder().convert(await File(widget.path).readAsBytes());
        _contentController.text = content;
      }

      setState(() {

      });
    }
  }

  //保存
  _save() async {
    try{
      var title = _titleController.text;
      var content = _contentController.text;
      var rootDir = await getTemporaryDirectory();
      print("rootdir = ${rootDir}");
      var file = File('${rootDir.path}/$title.txt');
      var exits = file.existsSync();
      if (!exits) {
        //不存在
        file.createSync(recursive: true);
      }
      file.writeAsStringSync(content);
      Navigator.of(context).pop(title);
    }catch(e) {
      print(e);
    }
  }
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值