How do I read file with content-URI in React Native on Android?
Asked Answered
A

5

16

I'm using React Native (0.48.3) for Android development. It seems, I'm stuck with a really trivial task: select a file and read it's content as a string. I have react-native-document-picker v2.0.0 for file selection, and it works fine: I can choose file and get it's URI. The problem is, I cannot make any package to read file with this link. I've already tried react-native-filesystem and react-native-fs, but it seems, they can work only with files in application directory. Anyway I get an error like this:

Error: File was not found: content://com.android.providers.downloads.documents/document/7

What package or function I need to use?

UPD: retrieving real, not content:// path, with react-native-get-real-path makes things work. But is this conversion really necessary, can one use content:// path for loading files?

Algonkian answered 18/9, 2017 at 11:18 Comment(0)
C
5

Say you are using react-native-fs, using copyFile can convert content uri to file uri.

if (url.startsWith('content://')) {
    const uriComponents = url.split('/')
    const fileNameAndExtension = urlComponents[uriComponents.length - 1]
    const destPath = `${RNFS.TemporaryDirectoryPath}/${fileNameAndExtension}`
    await RNFS.copyFile(uri, destPath)
}

Then you can use 'file://' + destPath as expected

Conoscenti answered 1/7, 2020 at 13:3 Comment(3)
what a precious answer!Repetition
What is urlComponents?Coffeng
you have to replace % characters const destPath = ${RNFS.TemporaryDirectoryPath}/${fileNameAndExtension}.replace(/%/g, "")Descriptive
D
2

There is already merged pull request #395 in react-native-fs which added a possibility to read from URI starting with content:// directly. I'm using Android URI in this code without any problem:

DocumentPicker.show({ filetype: ['*/*'] }, async (error, res) => {
  ...
  const exportedFileContent = await fs.readFile(res.uri, 'base64')
  ...
})
Dough answered 29/3, 2019 at 19:0 Comment(0)
I
1

This is 2023 and incase anybody still needs help, you can try the package react-native-blob-util

I faced the issue when I used react-native-document-picker to select files. What helped me was using the RNBU.fs.readStream() function. I first used it to convert to base64 then used react-native-fs to save the file to my device directory with the RNFS.writeFile() function. React Native Blob util I hope this helps!

Intensify answered 22/3, 2023 at 10:26 Comment(0)
B
0

On Android devices, you will need to append "file://" to load any file. You can do this using the package you mentioned or just manually. If you append it manually, react-native-fs can then be used to read the URI.

Blumenfeld answered 2/12, 2018 at 3:7 Comment(0)
L
0

Content URI to absolute path in React native ( ANDROID )

const isInternalStorage = res?.uri.startsWith('content://com.android.externalstorage.documents/tree/primary');
const isSdCardStorage = res?.uri.startsWith('content://com.android.externalstorage.documents/tree/') && !isInternalStorage;

to convert the path from content URI to absolute to read file or directory using react-native-fs library

For SD card reading ->

const  convertExternalStoragePathToAbsolutePath  = (path: string) => {
let dirToRead = path.split('tree')[1];   
dirToRead = '/storage' + dirToRead.replace(/%3A/g, '%2F');
// console.log("prePath:",path ,"cov: ",dirToRead)
return decodeURIComponent(dirToRead);
}

For Internal Storage reading->

const convertInternalStoragePathToAbsolutePath =  (path: string) => {
let dirToRead = path?.split('primary')[1];   
const InternalStoragePath =  RNFS.ExternalStorageDirectoryPath;
dirToRead = InternalStoragePath + dirToRead.replace(/%3A/g, '%2F');
// console.log("prePath:",path ,"cov: ",decodeURIComponent(dirToRead))
return decodeURIComponent(dirToRead);
}

Results

Sd card -> From react-native-directory-picker we'll get -

ContentURI = content://com.android.externalstorage.documents/tree/777B- 
D380%3ADownload
absolute path = /storage/777B-D380/Download

This absolute path can be used with react-native-fs to read files

Internal Storage ->

ContentURI= content://com.android.externalstorage.documents/tree/primary%3ADownload%2FMeet
absolute path = /storage/emulated/0/Download/Meet

example to read all the videos from a directory

 const searchFiles = async (path: string) => { 
 const files = await RNFS.readDir(path);     
const videoFiles = files.filter(file => {
  const fileExtension = file.name.split('.').pop();
  return ['mp4', 'avi', 'mov', 'mkv','ts'].includes(fileExtension ?? '');
  });
  setVideoList(videoFiles);
    // save it inside storage
    storage.save({
      key: 'videoList',
      data: videoFiles,
    }).then(() => {
      console.log("videoList saved successfully");
    
    })
  console.log("Directory changed ");
 }
Leroy answered 27/12, 2023 at 20:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.