目錄
在移動端實際開發中難免會涉及涉及緩存:
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