Braden Coates
Braden Coates

Reputation: 33

Can't write to file in flutter

Here is the code for making and writing to the file, I am able to write to temp files but anything else doesn't seem to work for some reason.

Directory? dir;
await Permission.storage.request();
if (!await Permission.storage.isGranted) return;
String? dirPath = await FilePicker.platform.getDirectoryPath();
if (dirPath == null) return;
dir = await Directory(dirPath).create(recursive: true);
for (var pdf in selected) {
  var bytes = base64Decode(pdf.pdfData.replaceAll('\n', ''));
  File savedFile = await File(dir.path +
      '/Receipt-' +
      DateTime.now().millisecondsSinceEpoch.toString() +
      '.pdf')
    .create(recursive: true);
  savedFile.writeAsBytes(bytes.buffer.asUint8List());
}

Here is the full error

E/flutter (21592): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: FileSystemException: Cannot create file, path = '/storage/emulated/0/Receipts/Receipt-1634356377430.pdf' (OS Error: Operation not permitted, errno = 1)
E/flutter (21592): #0      _File.create.<anonymous closure> (dart:io/file_impl.dart:255:9)
E/flutter (21592): #1      _rootRunUnary (dart:async/zone.dart:1436:47)
E/flutter (21592): #2      _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (21592): <asynchronous suspension>
E/flutter (21592): #3      PocketLoaded.downloadPDFs (package:receipts/cubit/pocket_state.dart:54:24)
E/flutter (21592): <asynchronous suspension>

I also have this in my manifest inside the manifest tag

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

If I'm doing this wrong how should I be writing to a file that the user can access outside of the app?

Upvotes: 2

Views: 4398

Answers (2)

Grimmret
Grimmret

Reputation: 221

Another solution I found is that when using the DateTime class as part of the file name, do not include the semicolon(:) in the resulting file path. You can replace the semicolon with a hyphen (-). For example:

'/storage/emulated/0/New Project/v_2023-09-24 16-17-52.109373'

To achieve this you can use the replace all function like so:

final filePath =
      '$tempDir/test_file_${DateTime.now()}.csv'
          .replaceAll(':', '-');

Upvotes: 2

Shaan Mephobic
Shaan Mephobic

Reputation: 1216

Things have changed after android 10. You need to add this permission in your AndroidManifest.xml.

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

To get the permission use

if (await Permission.manageExternalStorage.request().isGranted) {...}

NOTE: This permission is considered pretty risky so play store will reject your app unless it's your app's core functionality.

This is what google says

Core functionality is defined as the main purpose of the app. Without this core functionality, the app is "broken" or rendered unusable. The core functionality, as well as any core features that comprise this core functionality, must all be prominently documented and promoted in the app's description.

And if you are planning to create a file in an external directory and you are not able to find it, it's because you'd have to tell the device to refresh for the files. So I'd recommend using this package and passing your newly created file path to it or if you wanna do it manually with kotlin here's the code

    private fun broadcastFileUpdate(path: String) {
        context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(File(path))))
        println("updated!")
    }

Upvotes: 5

Related Questions