How to Read File as Array From SD Card with cordova-plugin-file

I use audio files in my app that I need to get as an buffer array. For this I let the user choose a file (using Ionic/Cordova FileChooser Plugin) and then I get an URL like:

content://com.android.providers.media.documents/document/audio%3A8431

After that, I sent this to Cordova Plugin File resolveNativePath function and I get a Path Like:

file:///storage/emulated/0/Prueba interno/Interno, Teddybär, Dreh Dich Um__320kbps.mp3

Here I make my audioFileInfo Object

audioFileInfo = {name: "Interno, Teddybär, Dreh Dich Um__320kbps.mp3",
                 originalPath: "content://com.android.providers.media.documents/document/audio%3A8431",
                  path: "file:///storage/emulated/0/Prueba interno"}

and finally I call filePlugin.readAsArrayBuffer(audioFileInfo.path, audioFileInfo.name) to get the buffer array.

It works ok when the file is in the device internal storage, but when the file comes from the SDCard it does not work because the readAsArrayBuffer returns “not found”.

SD Card:

File Chooser URL

content://com.android.externalstorage.documents/document/3D91-1C14%3AM%C3%BAsica%20Dana%2F1%20-%20Teddyb%C3%A4r%2C%20Teddyb%C3%A4r%2C%20Dreh%20Dich%20Um__320kbps.mp3

resolveNativePath:

file:///sdcard/Música Dana/1 - Teddybär, Teddybär, Dreh Dich Um__320kbps.mp3

audioFileInfo:

audioFileInfo = {
    name :"1 - Teddybär, Teddybär, Dreh Dich Um__320kbps.mp3"
    originalPath : "content://com.android.externalstorage.documents/document/3D91-1C14%3AM%C3%BAsica%20Dana%2F1%20-%20Teddyb%C3%A4r%2C%20Teddyb%C3%A4r%2C%20Dreh%20Dich%20Um__320kbps.mp3",
    path : "file:///sdcard/Música Dana"
}

readAsArrayBuffer:

FileError {code: 1, message: "NOT_FOUND_ERR"}

I have tried FilePlugins’s resolveLocalFilesystemUrl() and I get this Entry object:

{
    filesystem: {
        name: "content",
        root: {
            filesystem {
                name: "content",
                root: "...."
            }
        },

        fullPath: "/",
        isDirectory: true,
        isFile: false,
        name: "",
        nativeURL: "content://",
    },
    fullPath: "/com.android.externalstorage.documents/document/3D91-1C14:Música Dana/1 - Teddybär, Teddybär, Dreh Dich Um__320kbps.mp3",
    isDirectory: false,
    isFile: true,
    name: "1 - Teddybär, Teddybär, Dreh Dich Um__320kbps.mp3",
    nativeURL: "content://com.android.externalstorage.documents/document/3D91-1C14%3AM%C3%BAsica%20Dana%2F1%20-%20Teddyb%C3%A4r%2C%20Teddyb%C3%A4r%2C%20Dreh%20Dich%20Um__320kbps.mp3",
}

Bue I have no idea what to use as path in the first parameter of the readAsArrayBuffer function.

If I use fullPath and name it throws encoding error.
If I get just the “path” without the name from fullPath, it also throws encoding error.

Does anybody had a similar experience?

2 Likes

Facing similar problem. External Storage (sdcard) is not resolving.in both the encodeUrl or decodeUrl way. Decoded: file:///sdcard/New Folder (2)/Testing Files/download.jpeg and Encoded: file:///sdcard/New%20Folder%20(2)/Testing%20Files/download.jpeg

I am trying to convert a file in sdcard into base64 format:
this.base64.encodeFile(imgUri).then(). It is returning me empty string. But if i choose the file from internal storage its ok. imgUri is the sdcard path of the file. Please help somebody.

did you fixed that issue?

Anybody still reading this thread today should evaluate whether they can use Capacitor’s Filesystem instead of Cordova here.

for me this issue is only in android 10,it is working fine in other android version

Sorry I missed your message.

I migrated from Buffer Array to just use the file as an audio Source. And instead of using the filePlugin I use Ionic’s webview ‘convertFileSrc’ with the file URI. But it also has some problems.

I wonder, if I (find the time to) migrate to Capacitor, how would I resolve the native src path since ionic-webview is not supported and it says there it uses WKWebView that is just for iOS

I don’t believe you have to bother.

the Filesystem API supports using full file:// paths, or reading content:// files on Android. Simply leave out the directory param to use a full file path.

In my Use case I let the user choose an audio file from the device and then I assign it to an Audio element, like (super simplified example):

const audio = new Audio();
audio.src = webview.converFileSrc(fileUriOrNativePathDepending);
audio.play();

You mean I could just do ?

audio.src = capacitorPlugin.getUri({path: filePickerNativePathHere})

Or I am understanding it wrong?

Because if I can do what I wrote above I will really focus my efforts in migrate to capacitor.

I believe you would want convertFileSrc.

1 Like

Thanks a lot for your pointers!

I will migrate and try capacitor as soon as posible :slight_smile:

my solution using cordova-plugin-file

//tested with this three types 
let url_file = "file:///sdcard/content.txt";
//let url_file = "file:///storage/emulated/0/content.txt";
//let url_file = "content://com.asus.filemanager.OpenFileProvider/file/storage/3266-3836";

url_file = url_file.replace("file:///sdcard/", "");

let file_name;
if(url_file.indexOf("content://") !== -1 || url_file.indexOf("file://") !== -1) {
    window.resolveLocalFileSystemURL(url_file, gotFile, fail);
} else {
   let aux = url_file.split("/");
   file_name = aux[aux.length - 1];
   aux.splice(aux.length - 1, 1);
   url_file = aux.join("/");

   window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
}

function gotFS(fileSystem) {
     fileSystem.root.getDirectory(url_file, { create: false, exclusive: false }, gotDirEntry, fail);
}

function gotDirEntry(dirEntry) {
    dirEntry.getFile(file_name, { create: false, exclusive: false }, gotFile, fail);
}

function gotFile(fileEntry) {
      fileEntry.file(function (file) {
         let reader = new FileReader();
         reader.onloadend = function (evt) {
             console.log(this.result);
         }
         reader.readAsText(file);
     }, fail);
}

function fail(error) {
    console.log(error);
}
2 Likes