React Native文件系统与文件上传下载组件react-native-fs(适配Android & iOS)
可以实现文件的创建、删除、复制、移动、下载、上传等功能。
项目地址:https://github.com/johanneslumpe/react-native-fs
安装引用
安装组件
npm install react-native-fs --save
安装依赖
rnpm link
注:该命令需要重新编译项目,并且首先需要安装 rmpm
npm install rnpm -g
Android:注册模块(需重新编译)
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(), new RNFSPackage()
);
}
iOS:手动添加库
node_modules/react-native-fs/react-native-fs/RNFS.xcodeproj
API 介绍
常量
MainBundlePath
(String):The absolute path to the main bundle directoryCachesDirectoryPath
(String):The absolute path to the caches directoryDocumentDirectoryPath
(String):The absolute path to the document directoryTemporaryDirectoryPath
(String):The absolute path to the temporary directory (iOS only)ExternalDirectoryPath
(String):The absolute path to the external files, shared directory (android only)ExternalStorageDirectoryPath
(String):The absolute path to the external storage, shared directory (android only)
Android 下输出(小米4):
主要bundle目录:undefined
缓存目录:/data/user/0/com.awesomeproject/cache
文档目录:/data/user/0/com.awesomeproject/files
临时目录iOS:null
外部存储目录Android:/storage/emulated/0/Android/data/com.awesomeproject/files
图片目录:/storage/emulated/0/Pictures
方法
(1)readDir(dirpath: string): Promise<ReadDirItem[]>
读取目录内容,返回
type ReadDirItem = {
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?
};
(2)readdir(dirpath: string): Promise<string[]>
读取目录内容,返回
(3)stat(filepath: string): Promise<StatResult>
统计文件信息,返回文件属性
type StatResult = {
name: string; // The name of the item
path: string; // The absolute path to the item
size: string; // Size in bytes
mode: number; // UNIX file mode
isFile: () => boolean; // Is the file just a file?
isDirectory: () => boolean; // Is the file a directory?
};
(4)readFile(filepath: string, encoding?: string): Promise<string>
读取文件内容,编码可为:utf8 (default), ascii, base64
(5)writeFile(filepath: string, contents: string, encoding?: string): Promise<void>
写入文件内容,编码可为:utf8 (default), ascii, base64
(6)appendFile(filepath: string, contents: string, encoding?: string): Promise<void>
写入文件内容,编码可为:utf8 (default), ascii, base64
(7)moveFile(filepath: string, destPath: string): Promise<void>
移动文件
(8)copyFile(filepath: string, destPath: string): Promise<void>
复制文件
(9)unlink(filepath: string): Promise<void>
删除文件
(10)exists(filepath: string): Promise<boolean>
判断文件是否存在
(11)mkdir(filepath: string, options?: MkdirOptions): Promise<void>
创建目录,该命令会自动创建父目录,并且在目录已存在的情况下也不会抛出异常
MkdirOptions 只在 iOS 平台需要设置:
type MkdirOptions = {
NSURLIsExcludedFromBackupKey?: boolean; // iOS only
};
(12)downloadFile(options: DownloadFileOptions): { jobId: number, promise: Promise<DownloadResult> }
下载文件,适配 Android & iOS 平台
传入参数:
type DownloadFileOptions = {
fromUrl: string; // URL to download file from
toFile: string; // Local filesystem path to save the file to
headers?: Headers; // An object of headers to be passed to the server
background?: boolean;
progressDivider?: number;
begin?: (res: DownloadBeginCallbackResult) => void;
progress?: (res: DownloadProgressCallbackResult) => void;
};
返回参数:
type DownloadResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
statusCode: number; // The HTTP status code
bytesWritten: number; // The number of bytes written to the file
};
下载链接options.fromUrl
的内容到文件options.toFile
中,将会覆盖已存在的文件。
options.begin?
下载文件开始的回调函数,可用于获取一些初始化信息,如任务id、内容长度等。
type DownloadBeginCallbackResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
statusCode: number; // The HTTP status code
contentLength: number; // The total size in bytes of the download resource
headers: Headers; // The HTTP response headers from the server
};
options.progress?
下载过程回调函数,可用于获取实时下载进度信息。
type DownloadProgressCallbackResult = {
jobId: number; // The download job ID, required if one wishes to cancel the download. See `stopDownload`.
contentLength: number; // The total size in bytes of the download resource
bytesWritten: number; // The number of bytes written to the file so far
};
options.progressDivider
下载过程 progressCallback 回调频率,默认值为 0
如果 progressDivider = 10,将只接收10次 progressCallback 回调:0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100;如果 progressDivider = 0,将接收所有 progressCallback 回调。
options.background
只在 iOS 平台有效,默认值为 false
当 APP 失去焦点时是否后台继续下载
(13)stopDownload(jobId: number): Promise<void>
停止下载文件
(14)uploadFiles(options: UploadFileOptions): { jobId: number, promise: Promise<UploadResult> }
上传文件,只适用于 iOS 平台
传入参数:
type UploadFileOptions = {
toUrl: string; // URL to upload file to
files: UploadFileItem[]; // An array of objects with the file information to be uploaded.
headers?: Headers; // An object of headers to be passed to the server
fields?: Fields; // An object of fields to be passed to the server
method?: string; // Default is 'POST', supports 'POST' and 'PUT'
begin?: (res: UploadBeginCallbackResult) => void;
progress?: (res: UploadProgressCallbackResult) => void;
};
文件结构对象 UploadFileItem:
type UploadFileItem = {
name: string; // Name of the file, if not defined then filename is used
filename: string; // Name of file
filepath: string; // Path to file
filetype: string; // The mimetype of the file to be uploaded, if not defined it will get mimetype from `filepath` extension
};
返回参数:
type UploadResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
statusCode: number; // The HTTP status code
headers: Headers; // The HTTP response headers from the server
body: string; // The HTTP response body
};
options.begin
上传文件开始的回调函数,可用于获取一些初始化信息,如任务id
type UploadBeginCallbackResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
};
options.progress
上传过程回调函数,可用于获取实时上传进度信息。
type UploadProgressCallbackResult = {
jobId: number; // The upload job ID, required if one wishes to cancel the upload. See `stopUpload`.
totalBytesExpectedToSend: number; // The total number of bytes that will be sent to the server
totalBytesSent: number; // The number of bytes sent to the server
};
(15)stopUpload(jobId: number): Promise<void>
停止上传文件,只适用于 iOS 平台
(16)getFSInfo(): Promise<FSInfoResult>
返回存储空间信息
type FSInfoResult = {
totalSpace: number; // The total amount of storage space on the device (in bytes).
freeSpace: number; // The amount of available storage space on the device (in bytes).
};
范例源码
index.android.js & index.ios.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
// let RNFS = require('react-native-fs');
import RNFS from 'react-native-fs';
let downloadUrl = 'http://dldir1.qq.com/qqfile/qq/QQ8.6/18804/QQ8.6.exe';
let jobId1 = -1, jobId2 = -1;
let testImage1Path = RNFS.PicturesDirectoryPath + '/test-image-11.png';
class FsDemo extends Component {
constructor(props) {
super(props);//这一句不能省略,照抄即可
this.state = {
output: '文档目录路径: ' + RNFS.DocumentDirectoryPath,
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
React Native RNFS 文件管理
</Text>
<Text style={styles.text}>{this.state.output}</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.basic}>列出文件</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.createFile}>创建文件</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.delFile}>删除文件</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.printPath}>输出各种路径</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.downloadFile.bind(this, true, downloadUrl) }>下载文件</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.stopDownload}>停止下载</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.getFileInfo}>获取文件大小信息</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.uploadFile}>上传文件iOS</Text>
<Text style={{ fontSize: 25, marginTop: 5, marginBottom: 5 }} onPress={this.stopUpload}>停止上传iOS</Text>
<Text style={styles.author}>Powered by RNAPP.CC</Text>
</View>
);
}
basic = () => {
// get a list of files and directories
RNFS.readDir(RNFS.PicturesDirectoryPath).then(
(result) => {
console.log('GOT RESULT', result);
// stat the first file
return Promise.all([RNFS.stat(result[0].path), result[0].path]);
})
.then(
(statResult) => {
if (statResult[0].isFile()) {
// if we have a file, read it
return RNFS.readFile(statResult[1], 'utf8');
}
return 'no file';
})
.then((contents) => {
// log the file contents
console.log('文件内容:' + contents);
})
.catch((err) => {
console.log('错误:' + err.message);
console.log(err.message, err.code);
});
}
downloadFile(background, url) {
var progress = data => {
var percentage = ((100 * data.bytesWritten) / data.contentLength) | 0;
var text = `进度 ${percentage}%`;
this.setState({
output: text
});
};
var begin = res => {
jobId1 = res.jobId;
};
var progressDivider = 1;
RNFS.downloadFile(
{
fromUrl: url,
toFile: testImage1Path,
begin,
progress,
background,
progressDivider
}).promise.then(
res => {this.setState({
output: JSON.stringify(res)
});
}).catch(
err => this.showError(err)
);
}
stopDownload = () => {
console.log('停止下载');
RNFS.stopDownload(jobId1);
}
showError = (err) => {
console.log(err.message);
}
createFile = () => {
// create a path you want to write to
let path = RNFS.PicturesDirectoryPath + '/test.txt';
// write the file
RNFS.writeFile(path, 'Lorem ipsum dolor sit amet', 'utf8')
.then((success) => {
console.log('FILE WRITTEN! 目录是: ' + path);
})
.catch((err) => {
console.log(err.message);
});
}
delFile = () => {
// create a path you want to delete
let path = RNFS.PicturesDirectoryPath + '/test.txt';
return RNFS.unlink(path)
.then(() => {
console.log('FILE DELETED');
})
// `unlink` will throw an error, if the item to unlink does not exist
.catch((err) => {
console.log(err.message);
});
}
uploadFile = () => {
// For testing purposes, go to http://requestb.in/ and create your own link
var uploadUrl = 'http://requestb.in/1mhbfei1';
// create an array of objects of the files you want to upload
var files = [
{
name: 'test1',
filename: 'test1.w4a',
filepath: RNFS.PicturesDirectoryPath + '/test1.w4a',
filetype: 'audio/x-m4a'
}, {
name: 'test2',
filename: 'test2.w4a',
filepath: RNFS.PicturesDirectoryPath + '/test2.w4a',
filetype: 'audio/x-m4a'
}
];
var uploadBegin = (response) => {
jobId2 = response.jobId;
console.log('UPLOAD HAS BEGUN! JobId: ' + jobId2);
};
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',
headers: {
'Accept': 'application/json',
},
fields: {
'hello': 'world',
},
begin: uploadBegin,
progress: uploadProgress
}
).promise.then((response) => {
if (response.statusCode == 200) {
console.log('FILES UPLOADED!'); // response.statusCode, response.headers, response.body
} else {
console.log('SERVER ERROR');
}
})
.catch((err) => {
if (err.description === "cancelled") {
// cancelled by user
}
console.log(err);
});
}
stopUpload = () => {
console.log('停止上传');
}
printPath = () => {
console.log('主要bundle目录:' + RNFS.MainBundlePath); //undefined
console.log('缓存目录:' + RNFS.CachesDirectoryPath);
console.log('文档目录:' + RNFS.DocumentDirectoryPath);
console.log('临时目录iOS:' + RNFS.TemporaryDirectoryPath); //null
console.log('外部存储目录Android:' + RNFS.ExternalDirectoryPath);
console.log('图片目录:' + RNFS.PicturesDirectoryPath);
}
getFileInfo = () => {
return RNFS.getFSInfo().then(info => {
this.setState({
output: JSON.stringify(info)
});
});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
flex: {
flex: 1,
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
text: {
fontSize: 16,
textAlign: 'center',
margin: 10,
color:'red',
},
author: {
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: 10,
marginTop: 50,
textAlign: 'center',
fontSize: 16,
color: '#3BC1FF',
},
});
AppRegistry.registerComponent('AwesomeProject', () => FsDemo);
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-file-system-and-file-upload-download-component-react-native-fs-compatible-with-android-ios/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论