I'm still new to React Native may I know how can I create csv file in react native using expo? I've seen people suggesting expo-file-system as they said it is not recommended to use react-native-fs if using expo but I not sure how to use it. is it using FileSystem.writeAsStringAsync(fileUri, contents, options)?
Here is an example of a function that creates a simple .csv file
I'm using react-native-csv to generate the .csv.
expo-media-library is used to move the file from a folder accessible from the app to a publicly accessible folder.
import { jsonToCSV, readRemoteFile } from 'react-native-csv';
import * as FileSystem from 'expo-file-system';
import * as Permissions from 'expo-permissions';
import * as MediaLibrary from 'expo-media-library';
export async function makeCSV() {
const jsonData = `[
{
"Column 1": "Name",
"Column 2": "Surname",
"Column 3": "Email",
"Column 4": "Info"
}
]`;
const CSV = jsonToCSV(jsonData);
// Name the File
const directoryUri = FileSystem.documentDirectory;
const fileUri = directoryUri + `formData.csv`;
// Ask permission (if not granted)
const perm = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
if (perm.status != 'granted') {
console.log("Permission not Granted!")
return;
}
// Write the file to system
FileSystem.writeAsStringAsync(fileUri, CSV)
try {
const asset = await MediaLibrary.createAssetAsync(fileUri);
const album = await MediaLibrary.getAlbumAsync('forms');
console.log(album)
if (album == null) {
await MediaLibrary.createAlbumAsync('forms', asset, true);
} else {
await MediaLibrary.addAssetsToAlbumAsync([asset], album, true);
}
} catch (error) {
console.log(error);
}
}
Related
I want to create a simple Nuxt 3 file upload implementation that stores the file in the locally in a folder in the Nuxt project. In PHP the server side code is very easy and straight forward but I am finding it difficult doing the same thing in Nuxt 3 server side.
First:
npm install formidable
second:
define formidable in Nuxt config file inside modules list.
export default defineNuxtConfig({
modules: ["formidable"],
});
then in your handler for example upload.post.js :
import formidable from "formidable";
import fs from "fs";
import path from "path";
export default defineEventHandler(async (event) => {
let imageUrl = "";
let oldPath = "";
let newPath = "";
const form = formidable({ multiples: true });
const data = await new Promise((resolve, reject) => {
form.parse(event.req, (err, fields, files) => {
if (err) {
reject(err);
}
if (!files.photo) {
resolve({
status: "error",
message: "Please upload a photo with name photo in the form",
});
}
if (files.photo.mimetype.startsWith("image/")) {
let imageName =
Date.now() +
Math.round(Math.random() * 100000) +
files.photo.originalFilename;
oldPath = files.photo.filepath;
newPath = `${path.join("public", "uploads", imageName)}`;
imageUrl = "./public/upload/" + imageName;
fs.copyFileSync(oldPath, newPath);
resolve({
status: "ok",
url: imageUrl,
});
} else {
resolve({
status: "error",
message: "Please upload nothing but images.",
});
}
});
});
return data;
});
don't forget to name the input field "photo" in the client side or change it here in every "files.photo".
ALso the path of uploaded photos will be in public/uploads directory you can change it too if you like in "path.join" method.
Good luck
The following code works up to Android 10, it is creating a csv file in the DCIM folder:
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
export async function saveCSV() {
const permission = await MediaLibrary.requestPermissionsAsync();
if (permission.status != 'granted') {
console.log("Permission not Granted!")
return;
}
// CSVLocation
const directoryUri = FileSystem.documentDirectory;
const fileUri = directoryUri + `formData.csv`;
// Save to DCIM folder
const asset = await MediaLibrary.createAssetAsync(fileUri);
try {
const album = await MediaLibrary.getAlbumAsync('album');
if (album == null) {
console.log("ASSET", asset)
await MediaLibrary.createAlbumAsync('album', asset, true);
} else {
await MediaLibrary.addAssetsToAlbumAsync([asset], album, true)
.then(() => {
console.log('File Saved Successfully!');
})
.catch((err: string) => {
console.log('Error In Saving File!', err);
});
}
} catch (e) {
console.log(e);
}
}
Previously this line of code was executed in another function to create a file in the fileUri used above:
await FileSystem.writeAsStringAsync(fileUri, CSVheader + newInfo);
This issue has been described here: https://github.com/expo/expo/issues/12060
In short: Expo Media library is able to save image/video/audio assets so it will fail with other file types. Weirdly enough it was working fine with .pdf and .csv up to Android 10.
In the link above, and also on stackoverflow there are solutions using StorageAccessFramework. However, the user needs to create a subdirectory inside Downloads every time a file needs to be saved. I would like to make it automatically without any popups (after permission is granted).
The destination folder doesn't matter as long as it is accessible by the user later.
I'm able to pickup the document from file system using expo-document-picker but can't figure out a way to save it. Please guide on this.
import * as DocumentPicker from 'expo-document-picker';
import * as FileSystem from 'expo-file-system';
const pickDocument = async () => {
let result = await DocumentPicker.getDocumentAsync({});
console.log(result); // was able to get result here
saveDocument(result);
};
const saveDocument = async (image) => {
const fileUri = `${FileSystem.documentDirectory}${image.name}`;
// const savedImage = await FileSystem.downloadAsync(image.uri, fileUri);
const savedImage = await FileSystem.moveAsync(image.uri, fileUri);
console.log('saved image', savedImage);
};
Read about expo file system, https://docs.expo.dev/versions/v46.0.0/sdk/filesystem/#filesystemdocumentdirectory
but couldn't find a method which helps save the document. Tried FileSystem.moveAsync but it gave below error:
Error: An exception was thrown while calling `ExponentFileSystem.moveAsync` with arguments `(
"file:///var/mobile/Containers/...
I want to download the image file from web. This is my code :
import React from 'react'
import * as Sharing from "expo-sharing";
import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import { getCurrentDateTime } from './UtilityHelper';
import { messageBoxOK } from './AlertHelper';
export const downloadFileIOS = async (url, ticker) => {
let filename = ticker + "_" + getCurrentDateTime() + ".png";
MediaLibrary.requestPermissionsAsync();
if (filename !== null) {
FileSystem.downloadAsync(
url,
FileSystem.documentDirectory + filename
).then(async ({uri}) => {
console.log('Finished downloading to ', uri);
MediaLibrary.createAssetAsync(uri).then(asset => {
console.log('asset', asset);
MediaLibrary.createAlbumAsync('My Gallery', asset, false)
.then(() => {
messageBoxOK("Download", "Success");
})
.catch(error => {
messageBoxOK("Download", "Failed");
});
});
}).catch(error => {
console.error(error);
});
}
};
It worked well on Android but not for IOS.
For IOS I got this error :
[Error: Directory for
'file:///Users/dennisliu/Library/Developer/CoreSimulator/Devices/632FD441-0040-4E1A-AA4E-52A5C015C304/data/Containers/Data/Application/EBFB20FF-EAD8-40FE-BE4D-1D1719A633D2/Documents/ASII_2022-09-07
07:37:36.png' doesn't exist. Please make sure directory '(null)'
exists before calling downloadAsync.]
I have allow the permission in IOS.
What could be the problem ?
I found the problem.
The problem is the filename : ASII_2022-09-07 07:37:36.png is not valid and causing the error.
When I change the filename to : AAA.png it worked.
I am using Permissions from the expo-permission Library to get the location coords of the user:
import * as Location from "expo-location";
import * as Permissions from 'expo-permissions';
const granted = await Permissions.askAsync(Permissions.LOCATION);
The above works but keeps giving the warning that expo-permissions is deprecated.
If I use:
import {Location, Permissions } from 'expo';
it says Cannot read property 'askAsync' of undefined.
Does someone know what i should use? I use sdk42
Thx!
As this blog by Brent Vatne says,
expo-permissions has been deprecated in favor of module-specific permissions methods You should migrate from using
Permissions.askAsync and Permissions.getAsync to the permissions
methods exported by modules that require the permissions.
For example: you should replace calls to
Permissions.askAsync(Permissions.CAMERA) with
Camera.requestPermissionsAsync()
There shouldn’t be two ways to do an identical thing in a single SDK,
and so we picked our preferred approach and are consolidating around
it.
So now, you will have to use Permissions from individual packages
For Location,
Firstly, install expo-location
expo install expo-location
Then you can use it like this
import * as Location from 'expo-location';
let { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
console.log('Permission to access location was denied');
return;
}
If someone comes here and wants to get permissions for ImagePicker, then according to the docs you should do this:
import * as ImagePicker from "expo-image-picker";
const getPermissionAsync = async () => {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("...");
}
};
Now with expo, each libs have their own permissions requests methods.
Example with Location:
let { status } = await Location.requestForegroundPermissionsAsync();
Documentation
works:
import { Camera } from 'expo-camera';
import * as ImagePicker from "expo-image-picker";
const resultPermision = await Camera.requestCameraPermissionsAsync();
const resultPermisionCamera = resultPermision.status;
if (resultPermisionCamera === "denied") {
toastRef.current.show("Gallery permissions are needed");
} else {
const result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3]
})
........
Now, expo-camera works great, but also I believe something is pending on the side of the app.json.
Do you still need to add these lines?:
"permissions": [
"CAMERA",
"WRITE_EXTERNAL_STORAGE",
"CAMERA_ROLL"
question for everyone here :)
import { Camera } from "expo-camera";
this.state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
componentDidMount = async () => {
const { status } = await Camera.requestCameraPermissionsAsync();
this.setState({ hasCameraPermission: status === "granted" });
};