Read a contents from Dropbox with documentPicker/FileSystem


#1

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.


#2

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.


#3

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.

#4

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.


#5

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


#6

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.


#7

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


#8

Any updates on this? Still got the same issue.


#9

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!


#10

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})

}

#11

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?


#12

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))