天天看點

12.React Native檔案建立、檢視、下載下傳、上傳-react-native-fs1.react-native-fs是什麼?2.react-native-fs支援哪些功能?3.react-native-fs如何使用?4.react-native-fs功能介紹?5.檔案操作說明

目錄

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

繼續閱讀