目錄
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