当前位置: 首页 > 工具软件 > fs-lock > 使用案例 >

12.React Native文件创建、查看、下载、上传-react-native-fs

袁鸿畴
2023-12-01

目录

1.react-native-fs是什么?

2.react-native-fs支持哪些功能?

3.react-native-fs如何使用?

4.react-native-fs功能介绍?

5.文件操作说明

5.1文件目录说明

5.2文件创建

5.3文件删除

5.4文件读取

5.5文件上传(支持IOS和Android)

5.6文件修改

5.7文件移动和复制

5.8文件是否存在

5.9创建文件夹

5.10文件下载


在移动端实际开发中难免会涉及涉及缓存:
a.AsyncStorage:一些简单文本、用户身份Token或者JSON文件等可以用AsyncStorage,类似h5的数据存储LocalStorage;在 iOS 上,AsyncStorage在原生端的实现是把较小值存放在序列化的字典中,而把较大值写入单独的文件。在 Android 上,AsyncStorage会尝试使用RocksDB,或退而选择 SQLite。

可参考:

https://blog.csdn.net/ahou2468/article/details/88954215

b.Realm:Realm不是ORM(对象关系映射数据库),也不是建立在sqlite之上。相反,我们为移动应用程序开发人员构建了一个完整的数据库,它使用动态映射到完整的自定义数据库引擎(而不仅仅是一个键值存储)的本机JavaScript对象。这允许我们在保持性能的同时提供一个简单的API。使用Realm,您可以建模复杂的数据,链接图形中的对象,以及组成高级查询。

可参考:
 https://blog.csdn.net/ahou2468/article/details/94384048

c.文件存储(react-native-fs):

实现了react native的访问本地文件系统

主要介绍一下本地文件存储(react-native-fs);

注意事项:

对于rn<0.57和/或gradle<3,您必须安装react native fs的版本2.11.17!
对于rn>=0.57和/或gradle>=3,您必须时安装react native fs的版本2.13.2!

1.react-native-fs是什么?

实现了react native的访问本地文件系统;

2.react-native-fs支持哪些功能?

支持文件的创建、删除、查看、上传、下载;

3.react-native-fs如何使用?

a.安装(install)

npm install react-native-fs --save

b.链接(link)

react-native link react-native-fs

执行结果:

rnpm-install info Linking react-native-fs ios dependency 
rnpm-install info Platform 'ios' module react-native-fs has been successfully linked 
rnpm-install info Linking react-native-fs android dependency 
rnpm-install info Platform 'android' module react-native-fs has been successfully linked 

如果link失败,或者link之后仍旧不能import,则考虑手动link,详情查看官网教程,传送门

4.react-native-fs功能介绍?

文件创建,修改,读取,删除,上传,下载 ;

5.文件操作说明

5.1文件目录说明

参数说明:

import RNFS from 'react-native-fs'

MainBundlePath (String) 主bundle目录的绝对路径; (在Android上不适合)
CachesDirectoryPath (String) 缓存目录的绝对路径;
ExternalCachesDirectoryPath (String) 外部缓存目录的绝对路径 (仅在Android上支持)
DocumentDirectoryPath (String) 文档目录的绝对路径
TemporaryDirectoryPath (String) 临时目录的绝对路径(返回到Android上的缓存目录)
LibraryDirectoryPath (String) NSLibraryDirectory绝对路径; (在iOS上支持)
ExternalDirectoryPath (String) 外部文件的绝对路径,共享目录(在android上支持)
ExternalStorageDirectoryPath (String) 外部存储的绝对路径,共享目录 (在android上支持)

Android打印日志:

MainBundlePath: undefined
CachesDirectoryPath: /data/user/0/com.helloworld/cache
ExternalCachesDirectoryPath: /storage/emulated/0/Android/data/com.helloworld/cache
DocumentDirectoryPath: /data/user/0/com.helloworld/files
ExternalDirectoryPath: /storage/emulated/0/Android/data/com.helloworld/files
ExternalStorageDirectoryPath: /storage/emulated/0
TemporaryDirectoryPath: /data/user/0/com.helloworld/cache
LibraryDirectoryPath: undefined
PicturesDirectoryPath: /storage/emulated/0/Pictures
FileProtectionKeys: undefined

android使用注意事项:

使用ExternalStorageDirectoryPath时,需要请求权限(在Android上)才能读取和写入外部存储;在Android23版本以后需要申请权限;申请权限示例:https://facebook.github.io/react-native/docs/permissionsandroid

 

IOS的打印日志

MainBundlePath: /Users/fandong/Library/Developer/CoreSimulator/Devices/2186A64F-
70D4-4BF2-A2F8-AE357F828D33/data/Containers/Bundle/Application/88D43269-12E3-4720-80D1-5618EBEF75DE/HelloWorld.app
CachesDirectoryPath: /Users/fandong/Library/Developer/CoreSimulator/Devices/2186A64F-70D4-4BF2-A2F8-
AE357F828D33/data/Containers/Data/Application/DA44823E-A4B6-4C4A-B020-294C75AF374D/Library/Caches
ExternalCachesDirectoryPath: undefined
DocumentDirectoryPath: /Users/fandong/Library/Developer/CoreSimulator/Devices/2186A64F-70D4-4BF2-A2F8-
AE357F828D33/data/Containers/Data/Application/DA44823E-A4B6-4C4A-B020-294C75AF374D/Documents
ExternalDirectoryPath: null
ExternalStorageDirectoryPath: null
TemporaryDirectoryPath: /Users/fandong/Library/Developer/CoreSimulator/Devices/2186A64F-70D4-4BF2-A2F8-
AE357F828D33/data/Containers/Data/Application/DA44823E-A4B6-4C4A-B020-294C75AF374D/tmp/
LibraryDirectoryPath: /Users/fandong/Library/Developer/CoreSimulator/Devices/2186A64F-70D4-4BF2-A2F8-
AE357F828D33/data/Containers/Data/Application/DA44823E-A4B6-4C4A-B020-
294C75AF374D/Library
PicturesDirectoryPath: undefined
FileProtectionKeys: undefined

这里可以简单了解一下ios的沙盒模型。
1、Documents 目录:您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据。该路径可通过配置实现iTunes共享文件。可被iTunes备份。
2、AppName.app 目录:这是应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。
3、Library 目录:这个目录下有两个子目录:
3.1 Preferences 目录:包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.
3.2 Caches 目录:用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。
可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份。
4、tmp 目录:这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。该路径下的文件不会被iTunes备份。

5.2文件创建

let path = RNFS.DocumentDirectoryPath + '/test.txt';
        RNFS.writeFile(path, 'Lorem ipsum dolor sit amet', 'utf8')
            .then((success)=>{
                console.log('FILE WRITTEN'+' '+path);
            })
            .catch((err)=>{
                console.log(err.message);
            });

5.3文件删除

//创建删除路径
        let delpath = RNFS.DocumentDirectoryPath + '/test.txt';
        //执行删除
        RNFS.unlink(delpath)
            .then(()=>{
                console.log('FILE DELETED');
                //如果文件不存在,会抛出异常
            }).catch((err)=>{
                console.log(err.message);
            });

File does not exist

5.4文件读取

 
//获取文件列表和目录
        RNFS.readDir(RNFS.DocumentDirectoryPath)
            .then((result)=>{
                console.log('GOT RESULT', result);
                // stat the second file,找到第二个 文件
                return Promise.all([RNFS.stat(result[1].path), result[1].path]);
            }).then((statResult)=>{
                /**
                 * stat
                 *return {
                    'path': filepath,
                    'ctime': new Date(result.ctime * 1000),
                    'mtime': new Date(result.mtime * 1000),
                    'size': result.size,
                    'mode': result.mode,
                    'originalFilepath': result.originalFilepath,
                    isFile: () => result.type === RNFSFileTypeRegular,
                    isDirectory: () => result.type === RNFSFileTypeDirectory,
      };
                 */
                // if we have a file, read it
                if(statResult[0].isFile()){ //返回的是数组,第一个是对象,第二个是文件
                    return RNFS.readFile(statResult[1], 'utf8');
                }
                // console.log(statResult[0].path);
                return 'no file';
            }).then((contents)=>{
                // log the file contents,输出文件内容
                console.log(contents);
            }).catch((err) => {
                console.log(err.message, err.code);
            });

文件读取方法:

读取文件ReadDirItem定义:

type ReadDirItem = {
  ctime: date;     // The creation date of the file (iOS only)
  mtime: date;     // The last modified date of the file
  name: string;     // The name of the item
  path: string;     // The absolute path to the item
  size: string;     // Size in bytes
  isFile: () => boolean;        // Is the file just a file?
  isDirectory: () => boolean;   // Is the file a directory?
};

a.readDir(dirpath: string): Promise<ReadDirItem[]>

读取路径下的内容。这必须是绝对路径。使用下面路径常量形成可用的文件路径。

export const MainBundlePath: string
export const CachesDirectoryPath: string
export const ExternalCachesDirectoryPath: string
export const DocumentDirectoryPath: string
export const ExternalDirectoryPath: string
export const ExternalStorageDirectoryPath: string
export const TemporaryDirectoryPath: string
export const LibraryDirectoryPath: string
export const PicturesDirectoryPath: string
export const FileProtectionKeys: string

返回的Promise使用具有以下属性的对象数组解析:

type ReadDirItem = {
  ctime: date;     // The creation date of the file (iOS only)
  mtime: date;     // The last modified date of the file
  name: string;     // The name of the item
  path: string;     // The absolute path to the item
  size: string;     // Size in bytes
  isFile: () => boolean;        // Is the file just a file?
  isDirectory: () => boolean;   // Is the file a directory?
};

b.readDirAssets(dirpath: string): Promise<ReadDirItem[]>(Android)

读取android应用程序的assets文件夹中dirpath的内容。dirpath是从assets文件夹根目录到文件的相对路径。

c.readdir(dirpath: string): Promise<string[]>

返回目录下的文件名数组:["movies.realm.management", "test.txt", "ReactNativeDevBundle.js", "movies.realm.lock", "movies.realm", "movies.realm.note"]

d.stat(filepath: string): Promise<StatResult>

在filepath查找文件信息。如果文件路径链接到虚拟文件(例如android content uri),则可以使用原始路径查找指向的文件路径。Promise使用具有以下属性的对象解析:

type StatResult = {
  path:            // The same as filepath argument
  ctime: date;     // The creation date of the file
  mtime: date;     // The last modified date of the file
  size: string;     // Size in bytes
  mode: number;     // UNIX file mode
  originalFilepath: string;    // ANDROID: In case of content uri this is the pointed file path, otherwise is the same as path
  isFile: () => boolean;        // Is the file just a file?
  isDirectory: () => boolean;   // Is the file a directory?
};

e.readFile(filepath: string, encoding?: string): Promise<string>

读取路径处的文件并返回内容。编码可以是utf8(默认)、ascii、base64之一。使用base64读取二进制文件。

注意如果读取大文件,会等待比较久;

f.read(filepath: string, length = 0, position = 0, encodingOrOptions?: any): Promise<string>

从路径处文件的给定位置读取长度字节并返回内容。编码可以是utf8(默认)、ascii、base64之一。使用base64读取二进制文件。
注意:分段读取大文件可以改善性能。

g.readFileAssets(filepath:string, encoding?: string): Promise<string>

读取android应用程序的assets文件夹中路径处的文件并返回内容。编码可以是utf8(默认)、ascii、base64之一。使用base64读取二进制文件。
file path是从assets文件夹根目录到文件的相对路径。
注:仅限Android。

h.readFileRes(filename:string, encoding?: string): Promise<string>

读取android应用的res文件夹中名为filename的文件并返回内容。res/drawable用作图像文件的父文件夹,res/raw用于其他所有文件。编码可以是utf8(默认)、ascii、base64之一。使用base64读取二进制文件。
注:仅限Android。

5.5文件上传(支持IOS和Android)

// require the module,导入react-native-fs库
var RNFS = require('react-native-fs');

var uploadUrl = 'http://requestb.in/XXXXXXX';  // For testing purposes, go to http://requestb.in/ and create your own link,测试上传路径
// create an array of objects of the files you want to upload
// 创建一个想要上传文件的数组
var files = [
  {
    name: 'test1',
    filename: 'test1.w4a',
    filepath: RNFS.DocumentDirectoryPath + '/test1.w4a',
    filetype: 'audio/x-m4a'
  }, {
    name: 'test2',
    filename: 'test2.w4a',
    filepath: RNFS.DocumentDirectoryPath + '/test2.w4a',
    filetype: 'audio/x-m4a'
  }
];
//上传开始回调
var uploadBegin = (response) => {
  var jobId = response.jobId;
  console.log('UPLOAD HAS BEGUN! JobId: ' + jobId);
};
//上传进度回调
var uploadProgress = (response) => {
  var percentage = Math.floor((response.totalBytesSent/response.totalBytesExpectedToSend) * 100);
  console.log('UPLOAD IS ' + percentage + '% DONE!');
};

// upload files
//执行文件上传
RNFS.uploadFiles({
  toUrl: uploadUrl,//文件上传路径
  files: files,    //上传的文件数组
  method: 'POST',    //HTTP请求方法
  headers: {
    'Accept': 'application/json',    //请求header
  },
  fields: {
    'hello': 'world',
  },
  begin: uploadBegin,    //上传开始回调
  progress: uploadProgress    //上传进度回调
}).promise.then((response) => {//HTTP response响应
    if (response.statusCode == 200) {
      console.log('FILES UPLOADED!'); // response.statusCode状态码, response.headers响应header, response.body 响应body
    } else {
      console.log('SERVER ERROR');
    }
  })
  .catch((err) => {    //HTTP请求异常
    if(err.description === "cancelled") {
      // cancelled by user
    }
    console.log(err);
  });

5.6文件修改

a.writeFile(filepath: string, contents: string, encoding?: string): Promise<void>

将内容写入到指定filepath下文件。编码可以是utf8(默认)、ascii、base64之一。选项可以接受指定文件属性的对象,如模式等。

b.appendFile(filepath: string, contents: string, encoding?: string): Promise<void>

将内容追加到filepath。编码可以是utf8(默认)、ascii、base64之一。

c.write(filepath: string, contents: string, position?: number, encoding?: string): Promise<void>

在给定的随机访问位置将内容写入filepath。当位置未定义或-1时,内容将附加到文件末尾。编码可以是utf8(默认)、ascii、base64之一。

5.7文件移动和复制

a.moveFile(filepath: string, destPath: string): Promise<void>

移动文件到指定目录;

b.copyFile(filepath: string, destPath: string): Promise<void>

复制文件到指定路径 ;

更多复制文件操作方法参考:https://github.com/itinance/react-native-fs

5.8文件是否存在

a.exists(filepath: string): Promise<boolean>

检测指定路径下文件是否存在;

更多检测文件是否存在操作方法参考:https://github.com/itinance/react-native-fs

5.9创建文件夹

a.mkdir(filepath: string, options?: MkdirOptions): Promise<void>

type MkdirOptions = {
  NSURLIsExcludedFromBackupKey?: boolean; // iOS only
};

在filepath创建一个目录。自动创建父级,如果已经存在则不抛出(类似于linux mkdir-p)。
(仅限iOS):可以提供nsurlisexcludedfrombackupkey属性以在iOS平台上设置此属性。苹果将拒绝存储没有此属性的离线缓存数据的应用程序。

5.10文件下载

a.文件下载

downloadFile(options: DownloadFileOptions): { jobId: number, promise: Promise<DownloadResult> }

DownloadFileOptions

type DownloadFileOptions = {
  fromUrl: string;          // 下载文件的url
  toFile: string;           // 本地保存文件的路径URL
  headers?: Headers;        // 传递给服务器的请求header
  background?: boolean;     // 进入后台后继续下载(在iOS上支持)
  discretionary?: boolean;  // 允许操作系统控制下载的时间和速度,以提高感知性能 (在iOS上支持)
  cacheable?: boolean;      // 下载是否可以存储在共享的nsurlcache中(在iOS上支持,默认为true)
  progressDivider?: number;
  begin?: (res: DownloadBeginCallbackResult) => void;
  progress?: (res: DownloadProgressCallbackResult) => void;
  resumable?: () => void;    // 仅仅在IOS上支持
  connectionTimeout?: number // 仅仅在Android上支持
  readTimeout?: number       // 在IOS和Android上都支持
};

DownloadResult

type DownloadResult = {
  jobId: number;          // The download job ID, required if one wishes to cancel
 the download. See `stopDownload`.(生成的文件标识ID)
  statusCode: number;     // HTTP状态code
  bytesWritten: number;   // 被写入文件字节数量 
};

从options.fromUrl下载文件到options.toFile。将覆盖任何以前存在的文件。

如果提供了options.begin,则当接收到头并传递具有以下属性的单个参数时,将在下载开始时调用它一次:

type DownloadBeginCallbackResult = {
  jobId: number;          // 下载文件ID, 当取消下载时需要用到文件ID. 见 `stopDownload`.
  statusCode: number;     // HTTP状态码
  contentLength: number;  // 实际下载文件大小
  headers: Headers;       // 来自于服务器HTTP的headers
};

如果提供了options.progress,则将连续调用它,并传递具有以下属性的单个参数:

type DownloadProgressCallbackResult = {
  jobId: number;          // 下载文件ID, 当取消下载时需要用到文件ID. 见 `stopDownload`.
  contentLength: number;  //下载资源的文件大小
  bytesWritten: number;   // 到目前为止被写入文件字节大小
};

如果提供了options.progressdivider,它将返回被progressdivider划分的进度事件。

例如,如果progressdivider=10,您将只收到10个进度值回调:0、10、20、30、40、50、60、70、80、90、100使用它解决性能问题。如果progressdivider=0,则将接收所有progresscallback调用,默认值为0。

(仅限iOS):options.background(boolean)-当应用程序未聚焦时是否继续下载(默认值:false)。此选项当前仅适用于iOS,请参阅后台下载教程(iOS)(https://github.com/itinance/react-native-fs#background-downloads-tutorial-ios)部分。

(仅限iOS):如果提供了options.resumable,则将在下载停止时调用它,并且可以使用resumedownload()继续。

b.停止文件下载

stopDownload(jobId: number): void

通过job ID中断下载的文件 ,已下载的文件会保留在文件系统中;

c.重启继续下载

(仅限iOS) resumeDownload(jobId: number): void

通过job ID重启文件下载;

d.检测是否重启继续下载中

(iOS only) resumeDownload(jobId: number): void

检查具有此ID的下载作业是否可以使用resumeDownload()恢复。

if (await RNFS.isResumable(jobId) {
    RNFS.resumeDownload(jobId)
}

e.监听文件是否下载完成

(iOS only) completeHandlerIOS(jobId: number): void

要在使用后台下载时使用,请告诉iOS您已完成对已完成下载的处理。

 

参考:

https://github.com/itinance/react-native-fs#background-downloads-tutorial-ios

 

 

 类似资料: