Reputation: 1886
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?
Upvotes: 16
Views: 13721
Reputation: 33
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 ");
}
Upvotes: 0
Reputation: 11
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!
Upvotes: 1
Reputation: 5248
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
Upvotes: 5
Reputation: 500
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')
...
})
Upvotes: 2
Reputation: 3190
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.
Upvotes: 0