【问题标题】:Cordova file plugin - save file in deviceCordova 文件插件 - 将文件保存在设备中
【发布时间】:2016-08-08 15:02:39
【问题描述】:

我在 Android 中保存文件时遇到了很多麻烦。
该项目是一个使用 Ionic 开发的混合应用程序,带有以下插件:

com.phonegap.plugins.fileopener 1.0.0 "File Opener"
com.telerik.plugins.nativepagetransitions 0.4.2 "Native Page Transitions"
cordova-plugin-compat 1.0.0 "Compat"
cordova-plugin-crosswalk-webview 2.0.0 "Crosswalk WebView Engine"
cordova-plugin-file 4.2.0 "File"
cordova-plugin-network-information 1.2.2-dev "Network Information"
cordova-plugin-whitelist 1.2.3-dev "Whitelist"
cordova-plugin-wkwebview-engine 1.0.4-dev "Cordova WKWebView Engine"
ionic-plugin-keyboard 2.2.1 "Keyboard"

Android平台版本为5.2.1
我使用的设备是Samsung A7

这是来自AndroidManifest.xml的摘要

<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

案例1

如果我尝试使用这个 sn-p(实际上是在做另一个项目)

var storagePath = "/storage/emulated/0";
var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
var fileName = $scope.ngDocument.documentId + ".pdf"
var filePath = storagePath + "/" + fileDir + fileName;
$cordovaFile.writeFile(filePath, BINARY_ARR, {'append': false}).then(function(result) {}, function(err) {});

我从$cordovaFile.writeFile 得到{"code":5,"message":"ENCODING_ERR"} 作为回调,无论我使用绝对路径、相对路径,只是文件名,并且没有创建任何文件。

案例2

有了这个sn-p

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
  console.log('file system open: ' + fs.name);
  fs.root.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
    console.log("fileEntry:" + JSON.stringify(fileEntry));
    writeFile(fileEntry, BINARY_ARR);
  }, function(data){});
}, function(data){});

发生两件不同的事情

案例2.1

如果在 config.xml 中未指定任何配置选项,则应用会在 /storage/emulated/0/Android/media/{myAPP} 中创建一个空文件夹

案例2.2

有这两个偏好

<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="cache" />

/storage/emulated/0(外部 SSD)中的文件已创建,logcat中的错误为:

E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/cache/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/cache

奇怪的事实是/storage/extSdCard/mnt/extSdCard 的符号链接)没有安装,而外部 SSD 安装在 /mnt/sdcard

请帮忙:我正在头疼。
第一个 sn-p 在另一个项目中用作魅力。会不会是 ngCordova 的版本?

【问题讨论】:

    标签: android cordova cordova-plugins ngcordova cordova-plugin-file


    【解决方案1】:

    已解决:

    经过几次尝试,我以这种方式解决了

    config.xml:

    <preference name="AndroidPersistentFileLocation" value="Compatibility" />
    <preference name="AndroidExtraFilesystems" value="files,cache, sdcard, cache-external, files-external" />
    

    和主要功能:

    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    
        //var absPath = "file:///storage/emulated/0/";
        var absPath = cordova.file.externalRootDirectory;
        var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
        var fileName = "somename.txt";
        var filePath = fileDir + fileName;
    
        fs.root.getFile(filePath, { create: true, exclusive: false }, function (fileEntry) {
            writeFile(fileEntry, BINARY_ARR).then(function(){
              //do something here
            });
        }, function(err) {});
    }, function(err) {});
    
    function writeFile(fileEntry, dataObj) {
        return $q(function (resolve, reject) {
            fileEntry.createWriter(function (fileWriter) {
                fileWriter.onwriteend = function () {
                    resolve();
                };
                fileWriter.onerror = function (e) {
                    reject(e);
                };
                fileWriter.write(dataObj);
            });
        });
    }

    似乎:

    <preference name="AndroidPersistentFileLocation" value="Internal" />
    

    这是默认配置,不允许应用程序写入外部磁盘(无论是物理的还是模拟的)。而是只允许应用写入/data/data/{myApp}/files

    【讨论】:

    • 您好,我正在尝试使用您的代码将 xml 文件保存到设备,但我对将数据传递到何处感到困惑
    • 数据是 BINARY_ARR 变量..顾名思义它必须是一个二进制数组
    • 当我尝试你的代码时,我收到一个名为 writefile.then is not a function 的错误。
    【解决方案2】:

    好的,这里是如何保存文件的完整说明。使用文件插件cordova:

    假设您必须将带有文本 “Hello Mr. Vaibhav Mojidra” 的文件保存在内部存储的 .txt 中。

    所以如果您在 HTML 中单击按钮,则如下所示: 现在在 SaveFile 函数内部:

    var textt=""; 函数保存文件(文本) { 文本=文本; /* 用要写入文件的文本初始化全局变量 */ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,onFileSystemSuccess, 失败); /* 这将检查存储读写权限,如果获得权限则 函数发送参数将被调用,否则如果未授予则第三个参数即 将调用失败函数 */ } 函数onFileSystemSuccess(文件系统) { fileSystem.root.getFile("Demo.txt",{create: true, Exclusive: 假},得到文件条目,失败); /* 这将在内部存储中创建一个名为 Demo.txt 的文件。同样在 成功创建它将调用第二个参数函数,即 gotFileEntry */ } 函数 gotFileEntry(fileEntry) { fileEntry.createWriter(gotFileWriter, 失败); /* 这将获得一个带有路径调用 createWriter 的文件对象,其中第一个参数是 用于在文件中写入内容和第二个参数fail to create writer */ } 函数 gotFileWriter(作家) { writer.write(textt);/* 传递全局文本的参数并初始化 起初调用函数*/ writer.onwriteend = 函数(evt){ alert("文件已保存"); }; /*一旦文件写入文本并保存,该函数将被调用 */ } 功能失败(错误) { alert("Error","出现了一些问题\nError:"+error.code,"Ok"); }

    【讨论】:

      【解决方案3】:

      使用此函数写入和创建新文件夹

      function writeFile(path, filename, blob) {
          return new Promise((resolve, reject) => {
              window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function (dirpar) {
                  dirpar.getDirectory(path, { create: true }, function (dir) {
                      dir.getFile(filename, { create: true, exclusive: false }, function (fileEntry) {
                          fileEntry.createWriter(function (fileWriter) {
                              fileWriter.onwriteend = resolve
                              fileWriter.onerror = reject
                              fileWriter.write(blob);
                          });
                      }, reject);
                  }, reject);
              }, reject);
          });
      }
      

      如何调用函数

      writeFile("AppFolder", 'file.name', blob)
      

      示例下载图像并保存在文件夹中

      var url = "image url"
      
      fetch(url).then(res => res.blob()).then(blob => {
      
          writeFile("pictures/myapp", url.substring(url.lastIndexOf("/") + 1), blob)
              .then(function () { console.log("file donwloaded.") })
              .catch(function (e) { console.error("error:", e) })
      
      });
      

      【讨论】:

        【解决方案4】:

        使用 FileTransfer 插件:https://github.com/apache/cordova-plugin-file-transfer 用于下载,https://github.com/pwlin/cordova-plugin-pdialog 用于显示进度对话框。

        function saveFileDownloaded(url, nameFile) {
            var uri = url;
            var test = isEncoded(url)
            if (test == false) {
                uri = encodeURI(url)
            }
            var fileTransfer = new window.FileTransfer();
            var fileURL = cordova.file.externalRootDirectory + "Direct/" + nameFile;
             cordova.plugin.pDialog.init({
                            theme : 'DEVICE_LIGHT',
                            progressStyle : 'HORIZONTAL',
                            cancelable : false,
                            message : 'Téléchargement en cours...'
                        });
            fileTransfer.onprogress = function(result) {
                var percent = result.loaded / result.total * 100;
                percent = Math.round(percent);   
                 cordova.plugin.pDialog.setProgress(percent);       
            };
            fileTransfer.download(
                uri,
                fileURL,
                function(entry) {
                    cordova.plugin.pDialog.dismiss();
                    navigator.notification.confirm(
                        'Voulez vous ouvrir le fichier', // message
                        function(buttonIndex) {
                            onConfirm(buttonIndex, fileURL);
                        }, // callback to invoke
                        'Téléchargement terminé', // title
                        ['Ok', 'Exit'] // buttonLabels
                    );
                },
                function(error) {
                            cordova.plugin.pDialog.dismiss();
                    console.log(error)
                    alert("Erreur lors du téléchargement, vérifier votre connexion!");
                    console.log("download error source " + error.source);
                    console.log("download error target " + error.target);
                    console.log("upload error code" + error.code);
                }
            );
        }
        

        【讨论】:

        • 当我只需要创建一个新文件时,为什么要使用 FileUpload?
        • 什么时候应该使用 FileUpload ?
        • 感谢您的回答和支持。但是它是OFFTOPIC。即使我不得不投票,我也不会投票。
        • 文件传输插件现已弃用且不支持 android 10+
        猜你喜欢
        • 2012-12-26
        • 1970-01-01
        • 1970-01-01
        • 2018-05-30
        • 1970-01-01
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多