Read a contents from Dropbox with documentPicker/FileSystem

Hi, community.

(first: sorry my poor english.)

There is a problem that I can not solve alone. please help.

I want to read the content from Dropbox.
so I try to use Expo.documentPicker and Expo.FileSystem
It works well until DocumentPicker.getDocumentAsync()

but FileSystem.readAsStringAsync() catch exception…
give me the code how to read contents from Dropbox(with documentPicker)

handleImport = async () => {
    try {
      const pickerResponse = await DocumentPicker.getDocumentAsync()
      if (pickerResponse.type === 'cancel') {
        return false
      } else if (pickerResponse.type === 'success') {
        console.log(pickerResponse)
        try {
          const fileResponse = await FileSystem.readAsStringAsync(pickerResponse.uri)
          console.log(JSON.parse(fileResponse))
        } catch (exception) {
          console.log(`[FileSystem]: ${exception}`)
        }
      } else {
        return false
      }
    } catch (exception) {
      console.log(`[DocumentPicker]: ${exception}`)
    }
  }
Error: Invalid FileSystem URI 'file:///private/var/mobile/xxxxxxxx', make sure it's in the app's scope.

env is

thanks expo team and community.

Have you updated your app to v19? You may be stuck with an old version of the Assets code that doesn’t play nicely. Try rm -rf node_modules/ && npm i and let us know if you’re still having the issue.

Thank you for your reply.

Yes, the project already updated “expo”: “^19.0.0”

I try to refresh node_modules rm -rf node_moduels && yarn.
but same error occurred…

Error: Invalid FileSystem URI 'file:///private/var/mobile/xxxxxxxx', make sure it's in the app's scope.

You can get past this error by downloading the file to your app’s local file-system:

Expo.FileSystem.downloadAsync('file:///private/var/mobile/xxxxxxxx', Expo.FileSystem.documentDirectory + 'yyy');

I should mention that while testing this, the file is downloaded correctly, but I haven’t been able to read the contents. That may likely be a separate issue.

Thank you for your reply!

I tried your code then I implemented what I wanted to do!! (read a contents from dropbox)
Maybe, the reason of the error was because the file was not downloaded and it was not able to see from the local.

show finally code↓

FileSystem.downloadAsync(
  pickerResponse.uri,
  FileSystem.documentDirectory + 'get_data_from_dropbox.json'
).then(({ uri }) => {
  console.log('Finished downloading to ', uri)
  FileSystem.readAsStringAsync(uri).then(fileResponse => {
    console.log(fileResponse)
  })
}).catch(error => {
  console.error(error)
})

I really appreciate your help @thetc @jforbes

Hey, I’m trying to do the same thing, but picking a file from Downloads (on Android). in FileSystem.downloadAsync it throws the error unexpected url: content://com.android.providers.downloads.documents/document/237 (FileSystem.java:248). Anyone know what the problem is? I am on 19.0.0 according to the Info page.

I tried making a snack to demonstrate the problem (https://snack.expo.io/HJQRWEKPb), but the DocumentPicker doesn’t pop up there, not sure why.

i have the same problem. How to convert content:// to absolute path in EXPO ? @seveneightn9ne did you find out how to do it ?

Any updates on this? Still got the same issue.

Sorry, I have not checked this topic for a long time.
But I solved my question with your support.

Here is my sample code (with TypeScript)(Confirmed works only on iOS)

import { DocumentPicker, FileSystem } from 'expo'

handleImport = async (): Promise<void> => {
    try {
      const picked = await DocumentPicker.getDocumentAsync()
      if (picked.type === 'cancel') {
        return
      } else if (picked.type === 'success') {
        const fileUri = `${FileSystem.documentDirectory}import.json`
        const downloaded = await FileSystem.downloadAsync(picked.uri, fileUri)
        const read = await FileSystem.readAsStringAsync(downloaded.uri)
        const json = JSON.parse(read)
        console.log(json)
      } else {
        return
      }
    } catch (error) {
      console.log(error)
    }
  }

I pray for your help!

I found a solution for android



const picked = await DocumentPicker.getDocumentAsync({})

const { name } = picked

const fileUri = `${FileSystem.documentDirectory}${name}`

if(Platform.OS === 'ios') {

    const downloaded = await FileSystem.downloadAsync(picked.uri, fileUri)
    const read = await FileSystem.readAsStringAsync(downloaded.uri)
    const json = JSON.parse(read)
    console.log({json})

} else {
    
    const copyAsync = await FileSystem.copyAsync({from: picked.uri, to: fileUri})

    const read = await FileSystem.readAsStringAsync(fileUri)
    const json = JSON.parse(read)
    console.log({json})

}

const picked = await DocumentPicker.getDocumentAsync({})

const { name } = picked

const fileUri = ${FileSystem.documentDirectory}${name}

if(Platform.OS === ‘ios’) {

const downloaded = await FileSystem.downloadAsync(picked.uri, fileUri)
const read = await FileSystem.readAsStringAsync(downloaded.uri)
const json = JSON.parse(read)
console.log({json})

} else {

const copyAsync = await FileSystem.copyAsync({from: picked.uri, to: fileUri})

const read = await FileSystem.readAsStringAsync(fileUri)
const json = JSON.parse(read)
console.log({json})

}

i used this code : const read = await FileSystem.readAsStringAsync(fileUri)
but when reading the file as string, convert it to base64 and upload it to the server, i only get the file without the content at all. (just an empty content)
anyone can help me with this?

finally i found the answer for my problem. read the file as blob and use readAsDataURL to get the base64. then upload it to my server.

>  await fetch(fileUri)
>                     .then(response => response.blob())
>                     .then(blob => {
>                         var reader = new FileReader();
>                         reader.readAsDataURL(blob);
>                         reader.onloadend = () => {
>                             var base64 = reader.result;
>                             this.setState({
>                                 fileUrl: fileUri,
>                                 fileName: result.name,
>                                 fileData: base64,
>                             });
>                             console.log(base64);
>                         };
>                     })
>                     .catch(error => console.error(error))

Hi there! i have the same problem as you had. Can you, please, clarify some moments.

  1. Can you explain me step by step the process of converting to base64?
  2. Should I convert to blob after this code?
    const read = await FileSystem.readAsStringAsync(fileUri)
  1. this is my method to selecting the file:

async _selectDocument() {
let result = await DocumentPicker.getDocumentAsync({});
try {
if (result.type === ‘success’) {
const fileUri = ${FileSystem.documentDirectory}${result.name} --> get the fileUri

            await fetch(fileUri)
                .then(response => response.blob())  --> fetch the fileUri to blob
                .then(blob => {							
                    var reader = new FileReader();
                    reader.readAsDataURL(blob);		--> The readAsDataURL method is used to read the contents of the specified Blob or File. 
                    reader.onloadend = () => {
                        var base64 = reader.result;
                        this.setState({
                            fileUrl: fileUri,
                            fileName: result.name,
                            fileData: base64,                --> put the set state on the onloadend method
                        });
                        console.log(base64);
                    };
                })
                .catch(error => console.error(error))

          

        } else if (result.type === 'cancel') {
            alert("Select File Cancelled");
            console.log("Select File Cancelled");
        }
    }
    catch (error) {
        alert("File Not Found! Please Try Again!");
        console.log("File Not Found! Please Try Again!" + error);            
    }
}

for readAsDataURL() method you can prefer to this https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL

  1. i didn’t use the FileSystem.readAsStringAsync. Because when i’m using this, convert to base64, and after i upload it to the server, the file become empty and the size didn’t match.
1 Like

thanks! it solved my problem!

Why can’t expo allow us to use React-Native-File system ??

You want help, but start out with insults and abuse?

If you don’t like react native/expo, go and do something else instead of tweeting your angry negativity.

Or look into EAS Build or expo run:ios/expo run:android