You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Realm文件上传后无法读取数据的求助

React Native中Realm文件导出后无法读取数据的问题

问题背景

在React Native环境下,Realm官方没有提供现成的数据导入导出方法,我已成功导出.realm文件,但上传后无法读取其中的数据,以下是相关代码及运行日志,请求协助解决。

导出函数代码

import Realm from 'realm';
import RNFS from 'react-native-fs';
import {getRealm} from './realmService';

export const exportRealmData = async () => {
  try {
    const realm: Realm = await getRealm();
    const exportFileName = 'qqqq.realm';
    const exportFilePath = `${RNFS.DocumentDirectoryPath}/${exportFileName}`;

    if (await RNFS.exists(exportFilePath)) {
      await RNFS.unlink(exportFilePath);
    }

    const config = {
      path: exportFilePath,
      schema: realm.schema,
      schemaVersion: realm.schemaVersion + 1,
      encryptionKey: realm.encryptionKey,
    };

    realm.writeCopyTo(config);

    const downloadsFolder = RNFS.DownloadDirectoryPath;
    const destinationFilePath = `${downloadsFolder}/${exportFileName}`;

    await RNFS.moveFile(exportFilePath, destinationFilePath);

    console.log('Realm data exported to', destinationFilePath);
    return destinationFilePath;
  } catch (error) {
    console.error('Error exporting Realm data', error);
  }
};

上传与读取代码

function normalizePath(path: string | undefined) {
    try {
      if (path === undefined) {
        throw console.error('undefined');
      }
      if (Platform.OS === 'ios' || Platform.OS === 'android') {
        const filePrefix = 'file:';
        if (path.startsWith(filePrefix)) {
          path = path.substring(filePrefix.length);
        }
        path = decodeURIComponent(path);
        return path;
      }
    } catch (e) {
      console.error({msg: 'Failed to normalize path', data: e});
    }
  }

  const handleFilePick = async () => {
    try {
      const result = await DocumentPicker.pick({
        type: [DocumentPicker.types.allFiles],
      });
      console.log(result);
      const {0: file1} = result;

      const path = normalizePath(file1?.uri);
      console.log(path);
      setRealmFile(path);
    } catch (err) {
      console.error(err);
    }
  };

  console.log(realmFile);

  const handleDataSubmit = async () => {
    try {
      if (!realmFile) {
        console.error('Please upload a .realm file');
        return;
      }

      const realm = await getRealm();
      const existingRealm = await Realm.open({path: realmFile.uri});

      console.log('This is the existing realm:', existingRealm);

      realm.write(() => {
        [User, Category, Expense, Currency, Debtor, Debt].forEach(schema => {
          const objects = existingRealm.objects(schema.schema.name);
          console.log(`Data for ${schema.schema.name}:`, objects.toJSON());

          objects.forEach(object => {
            realm.create(schema.schema.name, object, Realm.UpdateMode.Modified);
          });
        });
      });

      await AsyncStorageService.setItem('isOnboarded', JSON.stringify(true));
      dispatch(setIsOnboarded(true));

      console.log('Data updated successfully!');
    } catch (error) {
      console.error('Error updating data:', error);
    }
  };

运行日志

LOG  content://com.android.providers.downloads.documents/document/msf:1000000035
 LOG  [{"fileCopyUri": null, "name": "qqqq.realm", "size": 4848, "type": "application/octet-stream", "uri": "content://com.android.providers.downloads.documents/document/msf%3A1000000035"}]
 LOG  content://com.android.providers.downloads.documents/document/msf:1000000035
 LOG  This is the existing realm: {"beforeNotifyListeners": {"eventType": "beforenotify", "listeners": Set {}, "realm": [Circular]}, "changeListeners": {"eventType": "change", "listeners": Set {}, "realm": [Circular]}, "schemaExtras": {}, "schemaListeners": {"eventType": "schema", "listeners": Set {}, "realm": [Circular]}, "syncSession": null}

问题分析

  1. 路径不兼容:日志显示获取到的是Android的content://内容URI,但Realm的Realm.open()只能识别本地文件系统的绝对路径,无法直接解析内容URI,这是无法读取数据的核心原因。
  2. Schema版本不一致:导出时设置了schemaVersion: realm.schemaVersion + 1,导致导出的Realm版本比原库高,导入时如果本地Schema版本不匹配,会出现数据读取异常。
  3. 变量引用错误:handleDataSubmit中错误使用了realmFile.uri,但setRealmFile(path)存储的是处理后的路径字符串,并非带uri属性的对象。
  4. 加密密钥缺失(如果有加密):如果原Realm使用了加密,打开导入的文件时未传入相同的encryptionKey,会导致无法解密打开。

解决方案

1. 转换内容URI为本地绝对路径

使用RNFS将content://指向的文件复制到App可访问的目录(如DocumentDirectoryPath),再用新路径打开Realm:

// 在handleFilePick中修改路径处理逻辑
const handleFilePick = async () => {
  try {
    const result = await DocumentPicker.pick({
      type: [DocumentPicker.types.allFiles],
    });
    const file1 = result[0];
    // 复制文件到App私有目录
    const destPath = `${RNFS.DocumentDirectoryPath}/${file1.name}`;
    // 对于Android content URI,RNFS.copyFile需要用content://路径作为源
    await RNFS.copyFile(file1.uri, destPath);
    setRealmFile(destPath);
    console.log('文件已复制到:', destPath);
  } catch (err) {
    console.error(err);
  }
};

2. 修正导出时的Schema版本

导出时保持和原Realm相同的版本号,避免版本冲突:

// 导出函数中的config修改
const config = {
  path: exportFilePath,
  schema: realm.schema,
  schemaVersion: realm.schemaVersion, // 去掉+1,保持版本一致
  encryptionKey: realm.encryptionKey,
};

3. 修正变量引用错误

在handleDataSubmit中直接使用realmFile作为路径,同时传入加密密钥(如果原库加密):

const handleDataSubmit = async () => {
  try {
    if (!realmFile) {
      console.error('请上传.realm文件');
      return;
    }

    const realm = await getRealm();
    // 获取原Realm的加密密钥(如果有)
    const originalRealm = await getRealm();
    const existingRealm = await Realm.open({
      path: realmFile,
      schema: realm.schema, // 确保Schema一致
      encryptionKey: originalRealm.encryptionKey, // 原库加密时必须传入
    });

    console.log('已打开导入的Realm:', existingRealm);

    realm.write(() => {
      [User, Category, Expense, Currency, Debtor, Debt].forEach(schema => {
        const objects = existingRealm.objects(schema.schema.name);
        console.log(`${schema.schema.name}的数据:`, objects.toJSON());

        objects.forEach(object => {
          realm.create(schema.schema.name, object, Realm.UpdateMode.Modified);
        });
      });
    });

    await AsyncStorageService.setItem('isOnboarded', JSON.stringify(true));
    dispatch(setIsOnboarded(true));

    console.log('数据更新成功!');
  } catch (error) {
    console.error('更新数据出错:', error);
  }
};

4. 验证文件完整性

确保导出的.realm文件没有损坏,可以用Realm Studio打开导出的文件,确认数据存在,排除文件本身的问题。

内容的提问来源于stack exchange,提问作者Indranil Bhuin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:55:03