• Flutter:文件与网络操作摘要


    一、本地文件操作

    1.File文件操作:

    说明:
    临时目录:getTemporaryDirectory()
    文档目录:getApplicationDocumentsDirectory()
    外部存储目录(iOS不支持):getExternalStorageDirectory()

    (1)添加PathProvider依赖,在pubspec.yaml中:

    1. dependencies:
    2.   path_provider: ^2.0.11

    (2)文件读写

    1. void editFile() async {
    2.   String dir = (await getApplicationDocumentsDirectory()).path;  // 获取文档目录
    3.   File file = await File('$dir/counter.txt');  //获得文件对象
    4.   String content = await file.readAsString();   // 读取文件内容
    5.   content = content + "新内容";
    6.   file.writeAsString(content);  //修改文件内容
    7. }

    2.Shared Preferences数据存储/获取:

    说明:

    存储位置:.../包名/shared_prefs/xxx.xml

    (1)添加shared_preferences插件依赖,在pubspec.yaml中:

    1. dependencies:
    2. shared_preferences: ^2.0.15 #preferences存储库

    (2)shared_preferences数据增删查工具类:

    1. class SharedPreferenceUtil {//shared_preferences数据增删查工具类
    2. late SharedPreferences _sharedPrefs; //Shared Preference操作类
    3. void init() async {
    4. _sharedPrefs = await SharedPreferences.getInstance();
    5. }
    6. void setInt(String key, int value) {
    7. _sharedPrefs.setInt(key, value);
    8. }
    9. int? getInt(String key) {
    10. return _sharedPrefs.getInt(key);
    11. }
    12. void setBool(String key, bool value) {
    13. _sharedPrefs.setBool(key, value);
    14. }
    15. bool? getBool(String key) {
    16. return _sharedPrefs.getBool(key);
    17. }
    18. void setDouble(String key, double value) {
    19. _sharedPrefs.setDouble(key, value);
    20. }
    21. double? getDouble(String key) {
    22. return _sharedPrefs.getDouble(key);
    23. }
    24. void setString(String key, String value) {
    25. _sharedPrefs.setString(key, value);
    26. }
    27. String? getString(String key) {
    28. return _sharedPrefs.getString(key);
    29. }
    30. void setStringList(String key, List<String> value) {
    31. _sharedPrefs.setStringList(key, value);
    32. }
    33. List<String>? getStringList(String key) {
    34. return _sharedPrefs.getStringList(key);
    35. }
    36. void remove(String key) {
    37. _sharedPrefs.remove(key);
    38. }
    39. }

    (3)使用工具类存储/读取数据:

    1. ...
    2. SharedPreferenceUtil sharedPrefs = SharedPreferenceUtil(); //创建工具类
    3. ...
    4. sharedPrefs.init(); //初始化
    5. ...
    6. sharedPrefs.setString("key", "value"); //存储数据
    7. String? value = sharedPrefs.getString("key"); //读取数据
    8. ...

    二、HTTP网络请求:

    1.使用dio库实现:

    (1)添加dio库依赖,在pubspec.yaml中:

    1. dependencies:
    2.   dio: ^4.0.6  #dio HTTP网络库

    (2)使用dio实现网络请求:

    1. class DioNetUtil {
    2.   Dio dio = Dio();
    3.   Map<String, CancelToken?> requestMap = {};  //取消标志,用于取消请求
    4.   //添加代理主机,通过代理主机转发请求
    5.   void _addProxy(HttpClient httpClient){
    6.     httpClient.findProxy = (uri) {
    7.       return "PROXY IP:端口";  //代理主机
    8.       //return "DIRECT";   //不需要代理主机时返回"DIRECT"
    9.     };
    10.   }
    11.   //添加证书校验
    12.   void _verifyCer(HttpClient httpClient, String cerContent) {
    13.     httpClient.badCertificateCallback = (X509Certificate cert, String host, int port) {
    14.       if(cert.pem != cerContent) return false;  //证书校验失败
    15.       return true; //证书校验通过,放行
    16.     };
    17.   }
    18.   //外部调用,添加证书校验
    19.   void initCerVerify(String cerContent){
    20.     (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (client) {
    21.       //添加代理主机,通过代理主机转发请求
    22.       //_addProxy(client);
    23.       //添加证书校验
    24.       _verifyCer(client, cerContent);
    25.     };
    26.   }
    27.   //get请求
    28.   Future<void> doGet(String url) async {
    29.     requestMap[url] = CancelToken(); //取消标志,用于取消请求
    30.     Response response = await dio.get(url, cancelToken: requestMap[url]);
    31.     String json = response.data.toString();
    32.     //...解析json
    33.   }
    34.   //post请求-请求参数为json
    35.   Future<void> doPostByJson(String url, {Map<String, dynamic>? params}) async {
    36.     requestMap[url] = CancelToken(); //取消标志,用于取消请求
    37.     //1.发起post请求
    38.     Response response;
    39.     if (params != null) {//有请求参数时
    40.       response = await dio.post(url, data: params, cancelToken: requestMap[url]);
    41.     } else { //无请求参数时
    42.       response = await dio.post(url, cancelToken: requestMap[url]);
    43.     }
    44.     //2.获取返回数据并解析
    45.     String json = response.data.toString();
    46.     //...解析json
    47.   }
    48.   //post请求-请求参数为Form表单,contentType为multipart/form-data
    49.   Future<void> doPostByForm(String url, {Map<String, dynamic>? params}) async {
    50.     requestMap[url] = CancelToken(); //取消标志,用于取消请求
    51.     //1.发起post请求
    52.     Response response;
    53.     if (params != null) {//有请求参数时,封装请求参数到FormData
    54.       FormData formData = FormData.fromMap(params);
    55.       response = await dio.post(url, data: formData, cancelToken: requestMap[url]);
    56.     } else {
    57.       response = await dio.post(url, cancelToken: requestMap[url]);
    58.     }
    59.     //2.获取返回数据并解析
    60.     String json = response.data.toString();
    61.     //...解析json
    62.   }
    63.   //文件上传
    64.   Future<void> uploadFile(String url, String filePath, {Map<String, dynamic>? params}) async {
    65.     requestMap[url] = CancelToken(); //取消标志,用于取消请求
    66.     //1.封装文件与请求参数到FormData
    67.     Map<String, dynamic> params1 = {
    68.       "file": File(filePath)
    69.       //"files": [...]  //此字段支持多个文件上传
    70.     };
    71.     if (params != null) {
    72.       params.forEach((key, value) { //遍历Map集合
    73.         params1[key] = value; //添加参数到Map集合中
    74.       });
    75.     }
    76.     FormData formData = FormData.fromMap(params1);
    77.     //2.发起post请求,上传文件
    78.     Response response = await dio.post(url, data: formData, cancelToken: requestMap[url], onSendProgress: (int progress, int total) {
    79.       print("文件总长度: $total, 当前上传进度: $progress");
    80.       if(progress == total) {
    81.         print("文件上传完成");
    82.         //...处理上传完后的逻辑
    83.       }
    84.     });
    85.     //3.获取返回数据并解析
    86.     String json = response.data.toString();
    87.     //...解析json
    88.   }
    89.   //文件下载
    90.   Future<void> downloadFile(String url, String saveFilePath) async {
    91.     requestMap[url] = CancelToken(); //取消标志,用于取消请求
    92.     try {
    93.       //发起post请求,下载文件
    94.       Response response = await dio.download(url, saveFilePath, cancelToken: requestMap[url], onReceiveProgress: (int count, int total) {
    95.         print("文件总长度: $total, 当前下载进度: $count");
    96.         if(count == total) {
    97.           print("文件下载完成");
    98.           //...处理下载完后的逻辑
    99.         }
    100.       });
    101.     } on DioError catch (e) {
    102.       if (e.type == DioErrorType.connectTimeout) {
    103.         print("连接超时");
    104.       } else if (e.type == DioErrorType.sendTimeout) {
    105.         print("请求超时");
    106.       } else if (e.type == DioErrorType.receiveTimeout) {
    107.         print("接收超时");
    108.       } else if (e.type == DioErrorType.response) {
    109.         print("响应异常");
    110.       } else {
    111.         print("下载失败");
    112.       }
    113.     }
    114.   }
    115.   //取消请求
    116.   Future<void> cancel(String url) async {
    117.     if (requestMap[url] != null && !requestMap[url]!.isCancelled) {
    118.       requestMap[url]!.cancel();
    119.       requestMap[url] = null;
    120.     }
    121.   }
    122. }

    2.使用HttpClient实现:

    1. class HttpClientUtil {
    2.   late HttpClient httpClient;
    3.   //初始化HttpClient
    4.   HttpClient _createHttpClient(Uri uri) {
    5.     if (httpClient != null) return httpClient;
    6.     httpClient = HttpClient(context: _getSecurityContext()); //创建HttpClient时添加证书
    7.     httpClient.idleTimeout = Duration(milliseconds: 10000); //对应请求头keep-alive
    8.     httpClient.connectionTimeout = Duration(milliseconds: 10000); //连接超时时间
    9.     httpClient.maxConnectionsPerHost = 5; //同一个url,允许同时连接的最大数
    10.     httpClient.autoUncompress = true; //对应请求头Content-Encoding,true时使用gzip压缩
    11.     //添加Basic认证或Digest认证
    12.     //_addAuth(uri);
    13.     //添加代理主机,通过代理主机转发请求
    14.     //_addProxy(uri);
    15.     return httpClient;
    16.   }
    17.   //添加Basic认证或Digest认证
    18.   void _addAuth(Uri uri){
    19.     httpClient.addCredentials(uri, "用户角色分组(后台添加)", HttpClientBasicCredentials("用户名", "密码"));   //添加Basic认证(Base64编码),对应请求头Authorization,值为:Basic xxx
    20.     httpClient.addCredentials(uri, "用户角色分组(后台添加)", HttpClientDigestCredentials("用户名", "密码"));   //添加Digest认证(哈希运算),对应请求头Authorization,值为:Basic xxx
    21.   }
    22.   //添加代理主机,通过代理主机转发请求
    23.   void _addProxy(){
    24.     httpClient.findProxy = (uri) {
    25.      return "PROXY IP:端口";  //代理主机
    26.    //return "DIRECT";   //不需要代理主机时返回"DIRECT"
    27.     };
    28.     //代理主机添加Basic认证或Digest认证
    29.     httpClient.addProxyCredentials("代理主机IP", 80, "用户角色分组", HttpClientBasicCredentials("用户名", "密码"));
    30.     httpClient.addProxyCredentials("代理主机IP", 80, "用户角色分组", HttpClientDigestCredentials("用户名", "密码"));
    31.   }
    32.   //添加证书校验
    33.   SecurityContext _getSecurityContext() {
    34.     //1.1.添加证书,请求时会自动校验
    35.     SecurityContext sc = SecurityContext();
    36.     //sc.setTrustedCertificates("证书本地路径"); //支持PEM格式(无需密码)、PKCS12格式(需要证书密码)
    37.     //1.2.上面添加的证书验证失败时,触发以下监听
    38.     httpClient.badCertificateCallback = (X509Certificate cert, String host, int port) {
    39.       return true; //不校验证书,全部放行
    40.     };
    41.     return sc;
    42.   }
    43.   //添加头字段
    44.   void _addHeader(HttpClientRequest request) {
    45.     request.headers.add("Connection", "keep-alive");
    46.     request.headers.add("Content-Type", "application/json");
    47.   }
    48.   //执行网络请求
    49.   Future<String?> doRequest(String url) async {
    50.     Uri uri = Uri.parse(url);
    51.     //1.创建一个HttpClient
    52.     HttpClient httpClient = _createHttpClient(uri);
    53.     try {
    54.       //2.0.打开Http连接
    55.       HttpClientRequest request = await httpClient.getUrl(uri);
    56.       //2.1.POST方式打开Http连接
    57.       //HttpClientRequest request = await httpClient.postUrl(uri);
    58.       //2.2.GET方式打开Http连接
    59.       //HttpClientRequest request = await httpClient.get("www.baidu.com", 80, "/path?key=value");
    60.       //3.添加请求头
    61.       _addHeader(request);
    62.       //4.等待连接服务器(会将请求信息发送给服务器)
    63.       HttpClientResponse response = await request.close();
    64.       //5.读取返回的json
    65.       String json = await response.transform(utf8.decoder).join();
    66.       print("json: " + json);
    67.       return json;
    68.     } catch (e) {
    69.       print("e: ${e.toString()}");
    70.       return null;
    71.     } finally {
    72.       //6.关闭client
    73.       httpClient.close();
    74.     }
    75.   }
    76. }

    三、TCP/IP长连接:

    1.使用WebSocket实现长连接:

    (1)添加WebSocket依赖,在pubspec.yaml中:

    1. dependencies:
    2.   web_socket_channel: ^2.0.0 #WebSocket库

    (2)使用WebSocket实现长连接:

    1. class WebSocketUtil {
    2.   late IOWebSocketChannel channel;
    3.   //1.创建websocket连接,并监听消息
    4.   Future<void> connect(String ws, Map<String, dynamic>? headers) async {
    5.     channel = IOWebSocketChannel.connect(ws, headers: headers);  //创建websocket连接
    6.     channel.stream.listen((msg) {  //监听消息
    7.       String json = msg;
    8.       //...解析json
    9.     });
    10.   }
    11.   //2.发送消息
    12.   Future<void> sendMsg(String msg) async {
    13.     channel.sink.add(msg); //发送消息
    14.   }
    15.   //3.关闭连接
    16.   Future<void> close() async {
    17.     channel.sink.close(); //关闭连接
    18.   }
    19. }

    2.使用Socket实现长连接:

    1. class SocketUtil {
    2.   late var socket;
    3.   //1.创建socket连接
    4.   Future<void> connect(String host, int port) async {
    5.     socket = Socket.connect(host, port); //创建socket连接
    6.   }
    7.   //2.读取消息
    8.   Future<String> readMsg() {
    9.     Future<String> msg = utf8.decoder.bind(socket).join(); //读取消息内容
    10.     return msg;
    11.   }
    12.   //3.发送消息
    13.   Future<void> sendMsg(String msg) async {
    14.     socket.writeln(msg);
    15.     socket.flush(); //发送消息
    16.   }
    17.   //4.关闭连接
    18.   Future<void> close() async {
    19.     socket.close(); //关闭连接
    20.   }
    21. }


     

  • 相关阅读:
    【Godot4自学手册】第二十节增加游戏的打击感,镜头震颤、冻结帧和死亡特效
    七牛云 vue 图片上传简单解说,js 上传文件图片
    js 图形操作一(兼容pc、移动端实现 draggable属性 拖放效果)
    自动化工具 接口自动化测试引擎
    pod install速度慢的终极解决方案
    Android~Compose脚手架和Toast
    网易Airtest全新推出:小型便携式集群解决方案!
    《软件质量保证与测试》第 6 章——系统测试 重点部分总结
    简单易用的地图可视化
    【Hadoop】- MapReduce & YARN 初体验[9]
  • 原文地址:https://blog.csdn.net/a526001650a/article/details/127690733