【问题标题】:How to get files from external storage in Flutter?如何在 Flutter 中从外部存储中获取文件?
【发布时间】:2020-01-24 06:58:31
【问题描述】:

我想用flutter项目获取listview中的所有文件,但是如何访问外部文件夹。

我创建了一个名为“MyFile”的文件夹,它创建于“/storage/emulated/0/MyFile”,

但下面的代码指向“/storage/emulated/0/Android/data/com.example.demo/MyFile”。

我不知道为什么下面的代码不起作用

 Directory externalDirectory = await getExternalStorageDirectory();
 print('External Storage:$externalDirectory');
 // External storage: /storage/emulated/0/Android/data/com.example.demo/MyFile

【问题讨论】:

    标签: android ios flutter dart


    【解决方案1】:

    使用 Flutter 官方 path_provider 包时,getExternalStorageDirectory() 将始终返回 /storage/emulated/0/your-package-name/files 的路径。

    要获取/storage/emulated/0/,您可以使用第三方包ext_storage。下面的代码将返回您想要的目录路径

     var externalDirectoryPath = await ExtStorage.getExternalStorageDirectory();
     print(path);  // /storage/emulated/0
    

    现在要创建一个文件夹,您可以使用以下函数:

    //this will create a Folder in the storage/emulated/0
    new Directory(externalDirectoryPath +'/YourfolderName')
      .create()
      .then((Directory directory) 
      {
        print(directory.path);
      });;
    

    '

    【讨论】:

    • 插件 ext_storage 使用了已弃用的 Android 嵌入版本。为避免意外的运行时失败或未来的构建失败,请尝试查看此插件是否支持 Android V2 嵌入。否则,请考虑将其删除,因为 Flutter 的未来版本将删除这些已弃用的 API。
    【解决方案2】:

    编辑张贴图片 2 以证明它有效。

    代码 sn -p 创建目录、文件

        new Directory('/storage/emulated/0/MyFile').create()
        // The created directory is returned as a Future.
            .then((Directory directory) {
          print(directory.path);
        });
    
        new File('/storage/emulated/0/MyFile/test.txt').create(recursive: true)
            .then((File file) {
          // Stuff to do after file has been created...
          print('${file.path}');
        });
    
        var dir = Directory('/storage/emulated/0/MyFile');
        print('${dir.path}');
        print('${dir.list().toList()}');
    

    创建目录和文件的完整代码

    import 'package:flutter/material.dart';
    import 'dart:io';
    import 'package:simple_permissions/simple_permissions.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      // This widget is the home page of your application. It is stateful, meaning
      // that it has a State object (defined below) that contains fields that affect
      // how it looks.
    
      // This class is the configuration for the state. It holds the values (in this
      // case the title) provided by the parent (in this case the App widget) and
      // used by the build method of the State. Fields in a Widget subclass are
      // always marked "final".
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      int _counter = 0;
    
      void _incrementCounter() {
        new Directory('/storage/emulated/0/MyFile').create()
        // The created directory is returned as a Future.
            .then((Directory directory) {
          print(directory.path);
        });
    
        new File('/storage/emulated/0/MyFile/test.txt').create(recursive: true)
            .then((File file) {
          // Stuff to do after file has been created...
          print('${file.path}');
        });
    
        var dir = Directory('/storage/emulated/0/MyFile');
        print('${dir.path}');
        print('${dir.list().toList()}');
    
    
        setState(() {
          // This call to setState tells the Flutter framework that something has
          // changed in this State, which causes it to rerun the build method below
          // so that the display can reflect the updated values. If we changed
          // _counter without calling setState(), then the build method would not be
          // called again, and so nothing would appear to happen.
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        SimplePermissions.requestPermission(Permission.WriteExternalStorage);
    
        // This method is rerun every time setState is called, for instance as done
        // by the _incrementCounter method above.
        //
        // The Flutter framework has been optimized to make rerunning build methods
        // fast, so that you can just rebuild anything that needs updating rather
        // than having to individually change instances of widgets.
        return Scaffold(
          appBar: AppBar(
            // Here we take the value from the MyHomePage object that was created by
            // the App.build method, and use it to set our appbar title.
            title: Text(widget.title),
          ),
          body: Center(
            // Center is a layout widget. It takes a single child and positions it
            // in the middle of the parent.
            child: Column(
              // Column is also a layout widget. It takes a list of children and
              // arranges them vertically. By default, it sizes itself to fit its
              // children horizontally, and tries to be as tall as its parent.
              //
              // Invoke "debug painting" (press "p" in the console, choose the
              // "Toggle Debug Paint" action from the Flutter Inspector in Android
              // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
              // to see the wireframe for each widget.
              //
              // Column has various properties to control how it sizes itself and
              // how it positions its children. Here we use mainAxisAlignment to
              // center the children vertically; the main axis here is the vertical
              // axis because Columns are vertical (the cross axis would be
              // horizontal).
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have pushed the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.display1,
                ),
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), // This trailing comma makes auto-formatting nicer for build methods.
        );
      }
    }
    

    请使用软件包flutter_file_manager https://pub.dev/packages/flutter_file_manager
    我用真机测试过,效果很好

    完整代码

    // framework
    import 'dart:async';
    import 'dart:io';
    import 'package:flutter/material.dart';
    
    // packages
    import 'package:flutter_file_manager/flutter_file_manager.dart';
    import 'package:path_provider/path_provider.dart';
    import 'package:path/path.dart' as p;
    import 'package:simple_permissions/simple_permissions.dart';
    
    void main() => runApp(new MyApp());
    
    @immutable
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        //SimplePermissions.requestPermission(Permission.ReadExternalStorage);
        SimplePermissions.requestPermission(Permission.WriteExternalStorage);
        return new MaterialApp(
          home: Scaffold(
              appBar: AppBar(
                title: Text("Flutter File Manager Demo"),
              ),
              body: FutureBuilder(
                future: _files(), // a previously-obtained Future<String> or null
                builder: (BuildContext context, AsyncSnapshot snapshot) {
                  switch (snapshot.connectionState) {
                    case ConnectionState.none:
                      return Text('Press button to start.');
                    case ConnectionState.active:
                    case ConnectionState.waiting:
                      return Text('Awaiting result...');
                    case ConnectionState.done:
                      if (snapshot.hasError)
                        return Text('Error: ${snapshot.error}');
                      return snapshot.data != null
                          ? ListView.builder(
                              itemCount: snapshot.data.length,
                              itemBuilder: (context, index) => Card(
                                      child: ListTile(
                                    title: Column(children: [
                                      Text('Size: ' +
                                          snapshot.data[index]
                                              .statSync()
                                              .size
                                              .toString()),
                                      Text('Path: ' +
                                          snapshot.data[index].path.toString()),
                                      Text('Date: ' +
                                          snapshot.data[index]
                                              .statSync()
                                              .modified
                                              .toUtc()
                                              .toString())
                                    ]),
    
                                    subtitle: Text(
                                        "Extension: ${p.extension(snapshot.data[index].absolute.path).replaceFirst('.', '')}"), // getting extension
                                  )))
                          : Center(
                              child: Text("Nothing!"),
                            );
                  }
                  return null; // unreachable
                },
              )),
        );
      }
    
    
      _files() async {
        var root = await getExternalStorageDirectory();
        var files = await FileManager(root: root).walk().toList();
    
        for(var i = 0;i<files.length;i++) {
          print("${files[i].path} ");
        }
          return files;
      }
    
    }
    

    在模拟器中工作演示

    【讨论】:

    • 请提供path_provider和simple_permissions的包版本名称
    • 这是官方演示。 simple_permissions: ^0.1.9 路径: '>=1.5.1 =0.4.0
    • 不工作。它显示路径 /storage/emulated/0/Android/data/com.example.demo/MyFile
    • 在我的三星。我检查过。如果文件由应用程序创建,它始终显示为 /storage/emulated/0/Android/data/com.abc.appname/files
    • 在我的三星,ms office下载文件路径是/storage/emulated/0/Android/data/com.microsoft.office.excel/files/Download/foregroundexcelsamsung/16.0.1.11601.20074跨度>
    【解决方案3】:

    我也遇到了同样的问题,虽然 Android SDK 版本 >30 或 31 不允许从其他目录读取,但您肯定在没有任何权限的情况下从您的目录读取。

    添加 '//' + 目录路径 & 你的问题将得到解决 所以这意味着你的路径将是'//'+ getExternalStorageDirectory())!.path

    这是在 SDK > 30 和 SDK =

    final directory = (await getExternalStorageDirectory())!.path;
      ByteData? byteData =
          await (image.toByteData(format: ui.ImageByteFormat.png));
      Uint8List pngBytes = byteData!.buffer.asUint8List();
      File imgFile = new File('$directory/screenshot${rng.nextInt(2000)}.png');
      await imgFile.writeAsBytes(pngBytes);
      setState(() {
        _imageFile = imgFile;
      });
      // Add '//' + directory path & your problem will be resolved
      return '//'+imgFile.path; 
    

    首先我将图像保存在目录中,然后我正在阅读它。

    【讨论】:

    • 如何从下载目录中获取 PDF 并显示。?你能帮我么 ?阿克谢
    猜你喜欢
    • 2018-08-30
    • 2019-11-22
    • 1970-01-01
    • 2021-12-09
    • 2019-04-18
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    相关资源
    最近更新 更多