Site icon AranaCorp

Ler e escrever um ficheiro com o React Native

Vamos criar um aplicativo React Native que permite ler ou gravar um arquivo em um espaço de armazenamento interno ou externo. Ter acesso ao arquivo do sistema pode ser útil para salvar dados de uma sessão do aplicativo para outra, ou para usar ou modificar os dados em um arquivo.

Hardware

Configurar o projeto React Native

Para ler e escrever num ficheiro, vamos utilizar a biblioteca do Sistema de Ficheiros, react-native-fs

npm install --save react-native-fs

Utilizar uma biblioteca

A partir da biblioteca, importamos os objectos e funções que nos interessam

import { DocumentDirectoryPath, writeFile, readDir, readFile, unlink } from 'react-native-fs'; //send files for testing

Em seguida, criamos um componente funcional com os estados desejados

const FileSysComp = () =>  {
  const [dirPath, setDirPath] = useState(DocumentDirectoryPath);
  const [filename, setFilename] = useState("myfile.txt");
  const [textToWrite, setTextToWrite] = useState("");
  const [textFromFile, setTextFromFile] = useState("");
  const [fileInDir, setFileInDir] = useState([]);

Em seguida, adicionamos as funções úteis para o sistema de ficheiros read, write, delete

	const makeFile = async (filePath : string, content : string) => {
	  try {
		  //create a file at filePath. Write the content data to it
		  await writeFile(filePath, content, "utf8");
		  console.log("written to file");
	  } catch (error) { //if the function throws an error, log it out.
		  console.log(error);
	  }
	};

	const getFile = async (filePath : string) => {
	  try{
		  const response = await readFile(filePath);
		  setTextFromFile(response)
		  console.log("File read : ",response)
	  } catch (error) {
		  console.log(error);
	  }
	};

  const deleteFile = async (filePath : string) => {
    try {
      await unlink(filePath); //delete the item present at 'path'
      console.log("deleted : ",filePath);
    } catch (error) {
      console.log(error);
    }
  };

Quando o componente é criado, lemos o diretório predefinido

  useEffect(() => {
    /* file system*/
    console.log("FS directory path : ",dirPath);
    readDir(dirPath).then((files) => {
      console.log("files on FS: ",files);
      setFileInDir(files);
    });
  }, [filename,dirPath]);

Por fim, criamos a renderização da aplicação com os seguintes elementos

  return (
    <View style={styles.mainBody}>
      <Text
        style={styles.mainTitle}>
        AC File System
      </Text>


      <View style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Directory"
          value={dirPath}
          onChangeText={setDirPath} />
      </View>
      <View style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Filename"
          value={filename}
          onChangeText={setFilename} />
      </View>

      <View
        style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Text to write"
          value={textToWrite}
          onChangeText={setTextToWrite} />
        <TouchableOpacity
          onPress={() => makeFile(dirPath + "/" + filename, textToWrite)}
        style={[styles.sendButton]}>
        <Text
          style={styles.buttonText}>
          WRITE
        </Text>
      </TouchableOpacity>
    </View>
    
    
        <Text>Directory:</Text>

        <ScrollView style={styles.textOutput}>
          {fileInDir.length>0 ? fileInDir.map((filedir, idx) => (
            <Text key={idx}>{filedir.name}</Text>
          )) : <Text>Folder empty or unknown</Text>}
        </ScrollView>


        <View style={{ flexDirection: 'row', justifyContent:'space-between'}}>
          <Text>Text from file:</Text>
          <TouchableOpacity
            onPress={() => getFile(dirPath + "/" + filename)}
            style={[styles.sendButton]}>
            <Text
              style={styles.buttonText}>
              READ
            </Text>
          </TouchableOpacity>
        </View>
        <ScrollView style={styles.textOutput}>
          {textFromFile ? <Text>{textFromFile}</Text> : null}
        </ScrollView>


        <TouchableOpacity
            onPress={() => deleteFile(dirPath + "/" + filename)}
            style={[styles.sendButton]}>
            <Text
              style={styles.buttonText}>
              DELETE
            </Text>
          </TouchableOpacity>

      
    </View>
  );

Resultados

Com esta aplicação, podemos visualizar o conteúdo de um diretório e ler, escrever e apagar um ficheiro.

Ler e escrever um ficheiro num espaço de armazenamento externo

Por defeito, uma aplicação só tem autoridade sobre o seu próprio diretório

É possível atribuir direitos de acesso a um espaço de armazenamento externo, como uma chave USB.

Para tal, pode conceder direitos a partir da interface Android. Vá a Definições > Aplicações e notificações > Gestor de permissões > Ficheiros e conteúdos multimédia

Ligue a pen USB ao seu dispositivo, utilizando o adb para encontrar o caminho para o espaço de armazenamento em ls /storage/ (ex /storage/70A8-C229)

Uma vez activada a autorização, poderá visualizar e criar ficheiros na pen USB.

Código de gestão de ficheiros completo com React Native

/**
 * https://www.npmjs.com/package/react-native-fs?activeTab=readme
 * https://github.com/itinance/react-native-fs
 */

import React, {useState, useEffect, useCallback} from 'react';
import {   
  View, 
  ScrollView, 
  Text,
  TextInput,
  TouchableOpacity, 
  StyleSheet,
  Alert} from 'react-native';
import { DocumentDirectoryPath, writeFile, readDir, readFile, unlink } from 'react-native-fs'; //send files for testing

let storagePath = "/storage/70A8-C229"

/**
 * Maincomp
 */
const FileSysComp = () =>  {
  const [dirPath, setDirPath] = useState(storagePath) //DocumentDirectoryPath);
  const [filename, setFilename] = useState("myfile.txt");
  const [textToWrite, setTextToWrite] = useState("");
  const [textFromFile, setTextFromFile] = useState("");
  const [fileInDir, setFileInDir] = useState([]);

	const makeFile = async (filePath : string, content : string) => {
	  try {
		  //create a file at filePath. Write the content data to it
		  await writeFile(filePath, content, "utf8");
		  console.log("written to file");
	  } catch (error) { //if the function throws an error, log it out.
		  console.log(error);
      Alert.alert("Cannot write file. Permission denied")
	  }
	};

	const getFile = async (filePath : string) => {
	  try{
		  const response = await readFile(filePath);
		  setTextFromFile(response)
		  console.log("File read : ",response)
	  } catch (error) {
		  console.log(error);
	  }
	};

  const deleteFile = async (filePath : string) => {
    try {
      await unlink(filePath); //delete the item present at 'path'
      console.log("deleted : ",filePath);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    /* file system*/
    console.log("FS directory path : ",dirPath);
    readDir(dirPath).then((files) => {
      console.log("files on FS: ",files);
      setFileInDir(files);
    }).catch((e) =>{
      console.log("foler does not exist");
      setFileInDir([])
    });
  }, [filename,dirPath]);

  return (
    <View style={styles.mainBody}>
      <Text
        style={styles.mainTitle}>
        AC File System
      </Text>

      <View style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Directory"
          value={dirPath}
          onChangeText={setDirPath} />
      </View>
      <View style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Filename"
          value={filename}
          onChangeText={setFilename} />
      </View>

      <View
        style={styles.inputBar}>
        <TextInput
          style={styles.textInput}
          placeholder="Text to write"
          value={textToWrite}
          onChangeText={setTextToWrite} />
        <TouchableOpacity
          onPress={() => makeFile(dirPath + "/" + filename, textToWrite)}
        style={[styles.sendButton]}>
        <Text
          style={styles.buttonText}>
          WRITE
        </Text>
      </TouchableOpacity>
    </View>
    
    
        <Text>Directory:</Text>

        <ScrollView style={styles.textOutput}>
          {fileInDir.length>0 ? fileInDir.map((filedir, idx) => (
            <Text key={idx}>{filedir.name}</Text>
          )) : <Text>Folder empty or unknown</Text>}
        </ScrollView>


        <View style={{ flexDirection: 'row', justifyContent:'space-between'}}>
          <Text>Text from file:</Text>
          <TouchableOpacity
            onPress={() => getFile(dirPath + "/" + filename)}
            style={[styles.sendButton]}>
            <Text
              style={styles.buttonText}>
              READ
            </Text>
          </TouchableOpacity>
        </View>
        <ScrollView style={styles.textOutput}>
          {textFromFile ? <Text>{textFromFile}</Text> : null}
        </ScrollView>


        <TouchableOpacity
            onPress={() => deleteFile(dirPath + "/" + filename)}
            style={[styles.sendButton]}>
            <Text
              style={styles.buttonText}>
              DELETE
            </Text>
          </TouchableOpacity>

    </View>
  );
}

export default FileSysComp;


let BACKGROUND_COLOR = "#161616"; //191A19
let BUTTON_COLOR = "#346751"; //1E5128
let ERROR_COLOR = "#C84B31"; //4E9F3D
let TEXT_COLOR = "#ECDBBA"; //D8E9A8
var styles = StyleSheet.create({

  mainBody: { flex: 1, justifyContent: 'center',  backgroundColor: BACKGROUND_COLOR},

  mainTitle:{
    color: TEXT_COLOR,
    fontSize: 30,
    textAlign: 'center',
    borderBottomWidth: 2,
    borderBottomColor: ERROR_COLOR,
  },

  backgroundVideo: {
    borderWidth: 2,
    borderColor: 'red',
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },

  webVideo: {
    borderWidth: 2,
    borderColor: 'green',
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },

  buttonText: {
    color: TEXT_COLOR,
    fontWeight: 'bold',
    fontSize: 12,
	  textAlign: 'center',
    textAlignVertical: 'center',
  },

  sendButton: {
    backgroundColor: BUTTON_COLOR,
    padding: 15,
    borderRadius: 15,
    margin: 2,
    paddingHorizontal: 20,
    right:0,
    },

    deviceItem: {
      flexDirection: 'row',
      flex: 3,
      marginBottom: 2,
    },
    deviceName: {
      fontSize: 14,
      fontWeight: 'bold',
    },
    deviceInfo: {
      fontSize: 8,
    },
    deviceButton: {
      backgroundColor: '#2196F3',
      padding: 10,
      borderRadius: 10,
      margin: 2,
      paddingHorizontal: 20,
    },

  inputBar:{
    flexDirection: 'row',
    justifyContent: 'space-between',
    margin: 5,
  },  

  textInput:{
    backgroundColor: '#888888',
    margin: 2,
    borderRadius: 15,
    flex:3,
  },

  textOutput:{
    backgroundColor: '#333333',
    margin: 10,
    borderRadius: 2,
    borderWidth: 1,
    borderColor: '#EEEEEE',
    textAlignVertical: 'top',
    minHeight : 50,
  }

});

Fontes

Exit mobile version