Cordova 文件插件 - 在设备中保存文件
Cordova file plugin - save file in device
我在 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" />
案例一
如果我尝试使用此代码段(实际上是在处理另一个项目)
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
有了这个片段
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
的符号 link)在 /mnt/sdcard
上安装外部 SSD 时未安装
请帮忙:我在撞头。
第一个片段在另一个项目中起到了魅力的作用。难道是ngCordova的版本?
使用 FileTransfer 插件:https://github.com/apache/cordova-plugin-file-transfer for downloads and 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);
}
);
}
已解决:
经过多次尝试我这样解决了
在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
好的,这里是如何保存文件的完整说明。使用文件插件 cordova:
假设您必须将文本为 "Hello Mr. Vaibhav Mojidra" 的文件保存在内部存储中的 .txt 中。
所以如果你像这样在 HTML 中点击按钮,它就会出现:
现在在 SaveFile 函数中:
var textt="";
function SaveFile(text)
{
textt=text; /* initialize global variable with text to be written in file */
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,onFileSystemSuccess, fail);
/* This will check permission for storage read and write, and if got permission then
function send parameter will be called else if not granted then third parameter ie
fail function will be called */
}
function onFileSystemSuccess(fileSystem)
{
fileSystem.root.getFile("Demo.txt",{create: true, exclusive:
false},gotFileEntry,fail);
/* This will create a file with name Demo.txt in internal storage . and similarly on
sucessfully create it will call second parameter function i.e. gotFileEntry */
}
function gotFileEntry(fileEntry) {
fileEntry.createWriter(gotFileWriter, fail);
/* This will get a file object with path call createWriter in which 1st parameter is
use to write content in file and second parameter of fail to create writer */
}
function gotFileWriter(writer)
{
writer.write(textt);/* passing parameter of the textt which is global and initialize
at first called function*/
writer.onwriteend = function(evt) {
alert("File Saved");
}; /*This function will be called once file is written with text and saved */
}
function fail(error)
{
alert("Error","There was some problem\nError:"+error.code,"Ok");
}
使用此功能写入和创建新文件夹
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) })
});
我在 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" />
案例一
如果我尝试使用此代码段(实际上是在处理另一个项目)
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
有了这个片段
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
的符号 link)在 /mnt/sdcard
请帮忙:我在撞头。
第一个片段在另一个项目中起到了魅力的作用。难道是ngCordova的版本?
使用 FileTransfer 插件:https://github.com/apache/cordova-plugin-file-transfer for downloads and 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);
}
);
}
已解决:
经过多次尝试我这样解决了
在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
好的,这里是如何保存文件的完整说明。使用文件插件 cordova:
假设您必须将文本为 "Hello Mr. Vaibhav Mojidra" 的文件保存在内部存储中的 .txt 中。
所以如果你像这样在 HTML 中点击按钮,它就会出现: 现在在 SaveFile 函数中:
var textt=""; function SaveFile(text) { textt=text; /* initialize global variable with text to be written in file */ window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,onFileSystemSuccess, fail); /* This will check permission for storage read and write, and if got permission then function send parameter will be called else if not granted then third parameter ie fail function will be called */ } function onFileSystemSuccess(fileSystem) { fileSystem.root.getFile("Demo.txt",{create: true, exclusive: false},gotFileEntry,fail); /* This will create a file with name Demo.txt in internal storage . and similarly on sucessfully create it will call second parameter function i.e. gotFileEntry */ } function gotFileEntry(fileEntry) { fileEntry.createWriter(gotFileWriter, fail); /* This will get a file object with path call createWriter in which 1st parameter is use to write content in file and second parameter of fail to create writer */ } function gotFileWriter(writer) { writer.write(textt);/* passing parameter of the textt which is global and initialize at first called function*/ writer.onwriteend = function(evt) { alert("File Saved"); }; /*This function will be called once file is written with text and saved */ } function fail(error) { alert("Error","There was some problem\nError:"+error.code,"Ok"); }
使用此功能写入和创建新文件夹
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) })
});