0

I have a asset.json file with content, and need to read it within an react-native app. I already figured that it must be manually copied to the native implementation and I can verify the file is there (and readable: -rw-r--r--). Since its there and I'm using promises to obtain it, please tell me whe the output is still:

{"_40":0,"_65":0,"_55":null,"_72":null}

and not the content of the file.

const path = RNFetchBlob.fs.dirs.DocumentDir + '/' + ASSET_FILENAME;
  if (await RNFS.exists(path)){
    console.log("BLAH EXISTS");
  } else {
    console.log("BLAH DOES NOT EXIST");
  }
  const asset_content = await RNFS.readFile(path);
  console.log("local asset_content:", asset_content);
  const assets = JSON.parse(asset_content);
  console.log("local assets:", assets);

The output is:

[10:03:55] I | ReactNativeJS ▶︎ BLAH EXISTS

[10:03:55] I | ReactNativeJS ▶︎ 'local asset_content:', '{"_40":0,"_65":0,"_55":null,"_72":null}'

[10:03:55] I | ReactNativeJS ▶︎ 'local assets:', { _40: 0, _65: 0, _55: null, _72: null }

if I on the other hand use promisify for what ever reason, as suggested in some posts, the application freezes on the call to the promisified file read. Here the code with applied changes:

 const path = RNFetchBlob.fs.dirs.DocumentDir + '/' + ASSET_FILENAME;
  if (await RNFS.exists(path)){
    console.log("BLAH EXISTS");
  } else {
    console.log("BLAH DOES NOT EXIST");
  }
  const readFileAsync = promisify(RNFS.readFile);
  const asset_content = await readFileAsync(path);
  console.log("local asset_content:", asset_content);
  const assets = JSON.parse(asset_content);
  console.log("local assets:", assets);

And its output:

[10:24:16] I | ReactNativeJS ▶︎ BLAH EXISTS

The file is not big, it's only 81 lines of valid JSON. Now if I use the promise to check for any exception like this:

  const path = RNFetchBlob.fs.dirs.DocumentDir + '/' + ASSET_FILENAME;
  if (await RNFS.exists(path)){
    console.log("BLAH EXISTS");
  } else {
    console.log("BLAH DOES NOT EXIST");
  }
  const readFileAsync = promisify(RNFS.readFile);
  let asset_content = null;
  readFileAsync(path, 'utf8')
    .then((str) => {
      console.log("got result: ", str);
      asset_content = str;
    })
    .catch((e) => {
      console.log("got error:", e);
    });
  console.log("local asset_content:", asset_content);
  const assets = JSON.parse(asset_content);
  console.log("local assets:", assets);

I still have no exception and the result is null:

[10:45:00] I | ReactNativeJS ▶︎ BLAH EXISTS

[10:45:00] I | ReactNativeJS ▶︎ 'local asset_content:', null

[10:45:00] I | ReactNativeJS ▶︎ 'local assets:', null

and when I get rid of promisify and leave the promise handling, I'm back there where I started:

  const path = RNFetchBlob.fs.dirs.DocumentDir + '/' + ASSET_FILENAME;
  if (await RNFS.exists(path)){
    console.log("BLAH EXISTS");
  } else {
    console.log("BLAH DOES NOT EXIST");
  }
  let asset_content = null;
  RNFS.readFile(path, 'utf8')
    .then((str) => {
      console.log("got result: ", str);
      asset_content = str;
    })
    .catch((e) => {
      console.log("got error:", e);
    });
  console.log("local asset_content:", asset_content);
  const assets = JSON.parse(asset_content);
  console.log("local assets:", assets);

output:

[10:49:45] I | ReactNativeJS ▶︎ BLAH EXISTS

[10:49:45] I | ReactNativeJS ▶︎ 'local asset_content:', null

[10:49:45] I | ReactNativeJS ▶︎ 'local assets:', null

[10:49:45] I | ReactNativeJS ▶︎ 'got result: ', '{"_40":0,"_65":0,"_55":null,"_72":null}'

Please help. File handling is crucial to our application.

UPDATE: Here is the content of the file asset.json which is referenced with ASSET_FILE:

{
  "protobuf": [
    {
      "name": "tiny-fovapp-4c",
      "lite": false,
      "compressed": false,
      "selected": false
    },
    {
      "name": "tiny-yolo-4c-quantized",
      "lite": true,
      "compressed": true,
      "selected": false
    },
    {
      "name": "tiny-yolo-4c",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "modelFilePath": "ai/protobuf/tiny-yolo-4c.pb",
      "labelsFilePath": "ai/protobuf/tiny-yolo-4c-labels.txt",
      "lite": false,
      "compressed": false,
      "selected": true
    },
    {
      "name": "tiny-yolo-4c",
      "lite": true,
      "compressed": false,
      "selected": false
    }
  ],
  "testImages": [
    {
      "name": "IMG_6924.jpg",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "filePath": "ai/testimgs/IMG_6924.jpg"
    },
    {
      "name": "IMG_6924.png",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "filePath": "ai/testimgs/IMG_6924.png"
    },
    {
      "name": "IMG_6929.jpg",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "filePath": "ai/testimgs/IMG_6929.jpg"
    },
    {
      "name": "Part1.png",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "filePath": "ai/testimgs/Part1.png"
    },
    {
      "name": "Part1_10.png",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "filePath": "ai/testimgs/Part1_10.png"
    }
  ],
  "parts": [
    {
      "name": "Part1",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "modelFilename": "ai/models/Part1.png",
      "drawingFilename": "ai/drawings/Part1.png",
      "annotationFilename": "ai/annotations/Part1.xml"
    },
    {
      "name": "Part2",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "modelFilename": "ai/models/Part2.png",
      "drawingFilename": "ai/drawings/Part2.png",
      "annotationFilename": "ai/annotations/Part2.xml"
    },
    {
      "name": "Part3",
      "parentFolder": "/data/user/0/com.foviar/files/",
      "modelFilename": "ai/models/Part3.png",
      "drawingFilename": "ai/drawings/Part3.png",
      "annotationFilename": "ai/annotations/Part3.xml"
    }
  ]
}

Macilias
  • 2,132
  • 1
  • 24
  • 35
  • This is not your answer, But i prefer to use https://www.npmjs.com/package/react-native-file-picker instead direct fetch-blob, because there is phones and platforms and os version for different mobile phones which not compatible with each other. And need to spend too much time. – cybercoder Nov 25 '19 at 09:54
  • are you struggling with reading json file in react native application? – abhikumar22 Nov 25 '19 at 09:58
  • yes, very much. I can read files, which I downloaded from a server, but not ones which has been there bundled with the application and saved in `android/app/src/main/assets` – Macilias Nov 25 '19 at 10:00
  • Why don't you try with readFileAssets() : https://github.com/itinance/react-native-fs#readfileassetsfilepathstring-encoding-string-promisestring – dkasipovic Nov 25 '19 at 10:02
  • @VahidAlimohamadi: thanks, I'll take a look into this, but fetch-blob is actually working, as I mentioned above, I can read downloaded files, but not the ones, that has been bundled within the application in `android/app/src/main/assets` and using import/require was leading to the same problem, but is much less flexible because of static paths. – Macilias Nov 25 '19 at 10:03
  • @Macilias can you just share some sample json format from your actual json so that i can help you out when reading it... thanks :) – abhikumar22 Nov 25 '19 at 10:04
  • @DamirKasipovic, I'll try it now, but avoided it because our application should run on multiple os's. Otherwise we would be developing directly in android and do not have this problems at all... – Macilias Nov 25 '19 at 10:05
  • @abhikumar22 I updated the question with the content of the file. – Macilias Nov 25 '19 at 10:07
  • 1
    @Macilias if that works, it means that most likely it's the library problem. There is a library just for reading files from assets in both Android and iOS. It might be worth a shot: https://github.com/IgorBelyayev/React-Native-Local-Resource – dkasipovic Nov 25 '19 at 10:11
  • @DamirKasipovic it seamed for me less likely that a library with 9 stars will do batter job that one with 3.3K but I'm desperate enough to give it a try and will louch if david wins over goliath. – Macilias Nov 25 '19 at 10:17
  • @Macilias it could be just that less people had a need for it, or choose the easy way out (move the file out of the assets folder). Let me know either way if possible – dkasipovic Nov 25 '19 at 10:18
  • @DamirKasipovic, what do you mean by easy way out (move the file out of the assets folder)? The ideal solution would be to not manually copy them over to each os's project, and leave them be distributed from react-native in the first place. – Macilias Nov 25 '19 at 10:20
  • @Macilias No, I mean store them on a server and download on first run if possible (and if files are updated occasionally, it might be easier this way). – dkasipovic Nov 25 '19 at 10:24
  • @DamirKasipovic, that the current workaround that I already implemented and want to replace with proper solution. We want to have some "default" assets to start with, before the user decides to download further assets. – Macilias Nov 25 '19 at 10:35
  • You can read bundle files with using JS ```require``` or ```ìmport``` !! @Macilias – cybercoder Nov 25 '19 at 11:05
  • require/import does not work with dynamic files downloaded from the server, since you can not use variable path's. Also I don't see any way to save them back, once updated and keep them persistent. I basically need a way to treat the assets which has been bundled with the application the same way as the ones which has been downloaded later one. And the asset.json file must be keeped updated. Do you see any way to get this requirements working? – Macilias Nov 25 '19 at 11:07

2 Answers2

0

Steps to read json file in react-native applications :-

1. Import it in your component

import ASSET_FILE from '../assets/files/asset.json';

// import filename from 'path to your asset file';

2. Now in a funtion

jsonParser(){
    var data = JSON.parse(JSON.stringify(ASSET_FILE));
    var tempProtobuf = []
    var temptestImages= []
    var tempparts= []
    tempProtobuf = data.Protobuf
    temptestImages = data.testImages
    tempparts = data.parts
}

// Now three of your objects are there in tempProtobuf, temptestImages, tempparts array respectively.

Iterate if or save in state if you want to show in your application..

Hope this helps...Thanks :)

abhikumar22
  • 1,236
  • 1
  • 7
  • 19
  • I want to use static and dynamic resources. Import/Require approach works only for static resources, and regarding the other difference - adding JSON.stringify() before applying JSON.parse(), this does not change a thing. After applying both, the assets are still `'{"_40":0,"_65":0,"_55":null,"_72":null}'` Beside this, if using static resources this way, is there any way to save the file back? – Macilias Nov 25 '19 at 10:34
  • yeah sure @Macilias for dynamic what you can do just change the variable name from **ASSET_FILE** to your response data variable name when you are dealing with dynamic data – abhikumar22 Nov 25 '19 at 10:38
  • you can not use variables for import/require. Thats why this approach is so *#&D= – Macilias Nov 25 '19 at 10:39
  • getting '{"_40":0,"_65":0,"_55":null,"_72":null}' it means you are doing something wrong inside your promise, any syntax error etc...That's why you are getting this. – abhikumar22 Nov 25 '19 at 10:39
  • Hey @Macilias its working in my end, i have also read tons of json file static/dynamic . That's why i have answered the same. Please have a look and it works ...If you have still some issues, feel free to ask..Thanks :) – abhikumar22 Nov 25 '19 at 10:42
  • you see the 4 examples and how I use the promise. 2 with and 2 without await. 2 with promisify and two without. Neither one is working. Do you see an error there? I basically need a way to treat the assets which has been bundled with the application the same way as the ones which has been downloaded later one. And the asset.json file must be keeped updated. Do you see any way to get this requirements working? – Macilias Nov 25 '19 at 10:59
  • @Macilias you could bundle assets with app, and on first run just copy file from assets to regular storage and use it as any other downloaded file. Further more, you could check if file exists, and if not, copy from assets, that way you have failsafe. Would that work? – dkasipovic Nov 25 '19 at 12:41
  • @DamirKasipovic the files I have been using has been pasted as reference to other components, some of them has been images some tensorflow models. This is working fine, but the assats.json file, which is the library to manage the assets, has been created on the fly. Yes I can save it, but I cant read it because I still don't know "How to read JSON file with React-Native-fs" – Macilias Nov 25 '19 at 13:33
  • @Macilias reading JSON files is same as reading any other file. The issue here, I believe, is because you're trying to read file from assets folder. Download JSON file (as you download other files) and read it, and I think it'll work – dkasipovic Nov 25 '19 at 13:34
  • yes, that's what i have did above ....right ? @DamirKasipovic – abhikumar22 Nov 25 '19 at 13:35
  • But I need it to be persistent, so it keeps track of bundles locally installed and available on the server. With your suggestion, the application would need always to have internet connection, just to obtain a simple file which it could also load directly and It would also have to recreate the knowledge about downloadeded resources, while it would be not necessary to do that if the file could be saved and read back again. – Macilias Nov 25 '19 at 13:38
  • @abhikumar22 you showed how to load a static required file, which is not stored within the application document folder, and it can not be keeped updated. – Macilias Nov 25 '19 at 13:42
0

I managed finally to copy the content of the static file into the application document directory and read and maintain it there by using NRFechtBlob.fs implementation with provided encoding param like this:

let asset_content = null;
try {
    await RNFetchBlob.fs.readFile(assetFile_path, 'utf8')
      .then((data) => {
        asset_content = data;
        console.log("got data: ", data);
      })
      .catch((e) => {
        console.error("got error: ", e);
      })
  } catch (err) {
    console.log('ERROR:', err);
}
const assets = JSON.parse(asset_content);

puh. didn't thought that file handling could be such a pain in 2019.

Macilias
  • 2,132
  • 1
  • 24
  • 35