Flutter:使用Dart检查设备可用存储空间

5

如何检查设备存储,是否可以在Flutter中实现而不需要本地操作?我想知道设备是否有足够的存储空间来下载图片。如何实现这一点?

3个回答

15

有一个名为disk_space的包,可以让您准确地获取您要查找的信息。您可以像这样使用它:

import 'package:disk_space/disk_space.dart';

void getDiskSpaceInfo() async{
  print(await DiskSpace.getFreeDiskSpace);
  print(await DiskSpace.getTotalDiskSpace);
}

编辑:此软件包已于2021年3月9日更新为Dart 2.12的版本0.1.0+2。但仍未链接到GitHub。


1
我已在iOS和Android上进行了测试,它在两者上都可以正常工作。如果某个答案解决了您的问题,请将其标记为正确答案。 - J. S.
1
@RodrigoHenriques 文档没有说明,但我相信它是字节。 - J. S.
@JoãoSoares,我想问一下,你知道DiskSpace.getTotalDiskSpace只访问内部存储还是包括SD卡存储吗?我尝试将其实现到我的项目中,但与手机上的空间相比,我得到了不同的结果。 - wahyu
1
抱歉,我不知道实际的实现方法。我找不到那个软件包的GitHub页面,而且它自2019年11月以来也没有更新过。 - J. S.
@JoãoSoares 非常感谢您的信息。 - wahyu
显示剩余2条评论

4

其中一种可能性是使用之前提到的DiskSpace,稍作修改即可。

该库包含两个文件:

disk_space.dart

import 'dart:async';

import 'package:flutter/services.dart';

class DiskSpace {
  static const MethodChannel _channel =
      const MethodChannel('disk_space');

  static Future<String?> get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }

  static Future<double?> get getFreeDiskSpace async {
    final double? freeDiskSpace = await _channel.invokeMethod('getFreeDiskSpace');
    return freeDiskSpace;
  }

  static Future<double?> get getTotalDiskSpace async {
    final double? totalDiskSpace = await _channel.invokeMethod('getTotalDiskSpace');
    return totalDiskSpace;
  }
}

and

DiskSpacePlugin.kt:

package de.appgewaltig.disk_space

import android.os.Environment
import android.os.StatFs
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar

class DiskSpacePlugin: MethodCallHandler {
  companion object {
    @JvmStatic
    fun registerWith(registrar: Registrar) {
      val channel = MethodChannel(registrar.messenger(), "disk_space")
      channel.setMethodCallHandler(DiskSpacePlugin())
    }
  }

  private fun getFreeDiskSpace(): Double {
    val stat = StatFs(Environment.getExternalStorageDirectory().path)

    var bytesAvailable: Long

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
      bytesAvailable = stat.blockSizeLong * stat.availableBlocksLong
    else
      bytesAvailable = stat.blockSize.toLong() * stat.availableBlocks.toLong()
    return (bytesAvailable / (1024f * 1024f)).toDouble()
  }

  private fun getTotalDiskSpace(): Double {
    val stat = StatFs(Environment.getExternalStorageDirectory().path)

    var bytesAvailable: Long

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
      bytesAvailable = stat.blockSizeLong * stat.blockCountLong
    else
      bytesAvailable = stat.blockSize.toLong() * stat.blockCount.toLong()
    return (bytesAvailable / (1024f * 1024f)).toDouble()
  }


  override fun onMethodCall(call: MethodCall, result: Result) {
    when(call.method) {
      "getFreeDiskSpace" -> result.success(getFreeDiskSpace())
      "getTotalDiskSpace" -> result.success(getTotalDiskSpace())
      else -> result.notImplemented()
    }
  }
}

我的修改:

我添加了另一种通道方法(以及一个用于获取内部存储的KT文件方法):

class DiskSpacePlugin: MethodCallHandler {
  ...

  private fun getFreeDiskSpace(String path): Double {
    val stat = StatFs(path) // dynamic path from the Flutter

    var bytesAvailable: Long

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
      bytesAvailable = stat.blockSizeLong * stat.availableBlocksLong
    else
      bytesAvailable = stat.blockSize.toLong() * stat.availableBlocks.toLong()
    return (bytesAvailable / (1024f * 1024f)).toDouble()
  }

  private fun getFreeInternalDiskSpace(): Double {
    val stat = StatFs(Environment.getDataDirectory().path) // changed to get internal directory
    ...
  }

  private fun getFreeExternalDiskSpace(): Double {...} // Changed name to reflect external directory

  private fun getTotalDiskSpace(): Double {...}


  override fun onMethodCall(call: MethodCall, result: Result) {
    when(call.method) {
      "getFreeDiskSpace" -> {
        var path = call.argument("path") as String
        result.success(getFreeDiskSpace(path)) // added this
      }
      "getFreeInternalDiskSpace" -> result.success(getFreeInternalDiskSpace())
      "getFreeExternalDiskSpace" -> result.success(getFreeExternalDiskSpace())
      "getTotalDiskSpace" -> result.success(getTotalDiskSpace())
      else -> result.notImplemented()
    }
  }
}

FlutterActivity 中注册插件:

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);

    DiskSpacePlugin.registerWith(registrarFor("<your_package>.DiskSpacePlugin"));
  }
}

新增了一个Storage助手:

import 'dart:io';

import 'package:path_provider/path_provider.dart';

class Storage {
  static Future<Directory> internal() async {
    return getApplicationDocumentsDirectory();
  }
  
  static Future<Directory> external() async {
    return getExternalStorageDirectory();
  }

  static Future<Directory> sdCard() async {
    return (await getExternalStorageDirectories()).firstWhere(
      (directory) => !directory.path.contains("emulated"),
      orElse: () => null,
    );
  }
}

现在你可以从Dart代码中调用它们:

static const MethodChannel _channel = const MethodChannel('disk_space');

void getFreeMemory() async {
  final String internal = (await Storage.internal()).path;
  final String external = (await Storage.external()).path;
  final String sdCard = (await Storage.sdCard()).path;

  final double freeDiskSpace = await _channel.invokeMethod('getFreeDiskSpace', {"path": internal});
  final double freeExternalDiskSpace = await _channel.invokeMethod('getFreeDiskSpace', {"path": external});
  if (sdCard != null) {
    final double freeSdCardSpace = await _channel.invokeMethod('getFreeDiskSpace', {"path": sdCard});
  }
}

PS:如果有人有DiskSpace库开发者的联系方式,可以询问他是否能够将提到的某些内容添加到库中?谢谢。


这看起来很棒,@NonGrate!请问这段代码是否也适用于获取MacOS、Windows和Linux的磁盘空间? - hardanger
我还没有测试过。如果有人能够测试一下,我会非常感激。 - NonGrate
1
嗨@0xba1,你需要将那个.kt文件添加到android目录中(就像你将文件添加到android项目-android/app/src/main/java/.../...一样)。 - NonGrate

0

测试是扩展存储空间

  private fun getFreeDiskSpace(): Double {
    val stat = StatFs(Environment.getExternalStorageDirectory().path)

    var bytesAvailable: Long

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
      bytesAvailable = stat.blockSizeLong * stat.availableBlocksLong
    else
      bytesAvailable = stat.blockSize.toLong() * stat.availableBlocks.toLong()
    return (bytesAvailable / (1024f * 1024f)).toDouble()
  }

  private fun getTotalDiskSpace(): Double {
    val stat = StatFs(Environment.getExternalStorageDirectory().path)

    var bytesAvailable: Long

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2)
      bytesAvailable = stat.blockSizeLong * stat.blockCountLong
    else
      bytesAvailable = stat.blockSize.toLong() * stat.blockCount.toLong()
    return (bytesAvailable / (1024f * 1024f)).toDouble()
  }


1
原帖是关于Flutter而不是Android的。 - Brandon Pillay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接