0

I'm trying to write a large multidimensional array into an ascii file in order to debug my program. (My phone has Android 8.0.0)

I added this line to my AndroidManifest.xml

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

The function is called within a subclass, so no context is available here:

  public void writeAsAscii(float [][][][] labelProbArray, int Nx, int Ny, int Nz ) {

    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
      Log.i("State","External storage is writable");
    } else{
      Log.i("State","Error: External storage NOT WRITABLE");
    }
    File path = Environment.getExternalStorageDirectory();
    File file = new File(path, "MyFile.txt");

    try {
      FileWriter writer = new FileWriter(file, true);

      for (int i = 0; i < Nx; i++) {
        for (int j = 0; j < Ny; j++) {
          for (int k = 0; k < Nz; k++){
            writer.write(String.valueOf(labelProbArray[0][i][j][k])+" ");
          }
          writer.write("\n");   // write new line
        }
      }
      writer.close();
    } catch (IOException e) {
      e.printStackTrace();
    }

  }

I'm following the advice given in related posts, but the writing fails. In debug mode I can see that path is set do /storage/emulated/0/MyFile.txt , but I cannot find the file anywhere on my phone that I use for debugging. So the file is probably never created. The try block is failing and the catch block reports:

java.io.FileNotFoundException: /storage/emulated/0/MyFile.txt (Permission denied)

I'm not sure what is going wrong. Is the file not created? Do I need to add more Permissions? A short clear toy example how to write custom ascii files anywhere in the code would be nice, as it is crucial for debugging large arrays.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
mcExchange
  • 6,154
  • 12
  • 57
  • 103
  • 1
    You need to add runtime permission for API level greater than 22. – pvrforpranavvr Aug 07 '19 at 15:13
  • "The function is called within a subclass, so no context is available here" -- are you going to need to fix that, as your code will not work on Android Q (by default) or Android R+ (for all apps). [All local storage I/O, whether using the filesystem or the Storage Access Framework, will need a `Context`](https://commonsware.com/blog/2019/06/07/death-external-storage-end-saga.html). Move your storage I/O code into a singleton repository that you initialize with the `Application` singleton `Context` (e.g., via dependency injection). – CommonsWare Aug 07 '19 at 15:17
  • That last comment I didn't understand. But I could grant "Access to storage" permissions to the app via "Settings -> Apps -> App-Permissions -> swiping the respective button". However I still cannot find the file on the phone... – mcExchange Aug 07 '19 at 15:23
  • 1
    "However I still cannot find the file on the phone" -- use Android Studio's Device File Explorer or `adb shell ls` to examine the device. To be able to see this file in your desktop OS file manager, use `MediaScannerConnection.scanFile()` to get your newly-created file indexed by the `MediaStore`. "That last comment I didn't understand" -- see https://stackoverflow.com/a/50579403/115145 and https://stackoverflow.com/q/36224343/115145 and https://developer.android.com/jetpack/docs/guide for more about the repository pattern. – CommonsWare Aug 07 '19 at 15:31
  • Indeed Android Studio's Device File Explorer was showing different paths and files than my OS file explorer. The file was found under `/sdcard/MyFile.txt` – mcExchange Aug 07 '19 at 16:12

1 Answers1

0

WRITE_EXTERNAL_STORAGE is a dangerous permission so you need to request this permission programmatically before trying to create a file in the file system.

Use this code to request permission from your activity onCreate():

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 12)

And after that check if it is granted or not:

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    when (requestCode) {
        12 -> {
            // If request is cancelled, the result arrays are empty.
            if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // permission was granted
            } else {
                // permission denied
            }
        return
        }

        // Add other 'when' lines to check for other
        // permissions this app might request.
        else -> {
            // Ignore all other requests.
        }
    }
}

More about permmission: https://developer.android.com/guide/topics/permissions/overview

kimwii
  • 81
  • 1
  • 7