Capacitor / Ionic Filesystem writeFile to csv - ionic-framework

I am using Capacitor 3, Filesystem and I'm saving data into a file.
Here is the code:
writeToCSVFile = async () => {
await Filesystem.writeFile({
path: 'text.csv',
data: `0123445544,4556677`,
directory: Directory.Documents
});
};
The file is saving but there is some data in cell 1 of the csv with some strange characters.
In my can there should be 2 cells each with one of the numbers in the data.
How can I fix this?

You have to set the encoding parameter to Encoding.UTF8:
import { Filesystem, Directory, Encoding } from '#capacitor/filesystem';
writeToCSVFile = async () => {
await Filesystem.writeFile({
path: 'text.csv',
data: `0123445544,4556677`,
directory: Directory.Documents,
encoding: Encoding.UTF8
});
};

Related

Unhandled Exception: FileSystemException: Cannot open file, path ... (OS Error: No such file or directory, errno = 2)

I'm trying to download *.xlsx file using dio.download, and it's throwing the errors:
Unhandled Exception: FileSystemException: Cannot open file, path = '/storage/emulated/0/Android/data/com.example.foodagator_app/files/file.xlsx' (OS Error: No such file or directory, errno = 2)
Another one error from try/catch block:
FileSystemException: Creation failed, path = 'File: '' (OS Error: Read-only file system, errno = 30)
I wrote the permission in androidmanifest for external storage, and also tried temporary directory, but it's not working. Can anyone help me with this? Here is my code
void download() async {
var tempDir = await getExternalStorageDirectory();
File file = File(tempDir!.path + '/file.xlsx');
try {
Response response = await dio.download(
url,
file,
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
),
);
var raf = file.openSync(mode: FileMode.write);
// response.data is List<int> type
raf.writeFromSync(response.data);
await raf.close();
} catch (e) {
print('Error is: $e');
}
}
void readFile() async {
var tempDir = await getExternalStorageDirectory();
var filePath = tempDir!.path + "/file.xlsx";
var bytes = File(filePath).readAsBytesSync();
var decoder = SpreadsheetDecoder.decodeBytes(bytes, update: true);
for (var table in decoder.tables.keys) {
print(table);
print(decoder.tables[table]!.maxCols);
print(decoder.tables[table]!.maxRows);
for (var row in decoder.tables[table]!.rows) {
print('$row');
}
}
}
This error is getting because there is no file named file.xlsx you can check if file exists or not
if(file.existsSync())
if file does not exist, you can create one using,
new File('$path/file.xlsx').create(recursive: true);
in android 11 and higher use below permission, without tools:ignore="ScopedStorage"
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
In my case, it was caused because I had moved a dart file to another folder but my other files were still referencing that file using the old path, you can import the file again using the new path and using the "package:" keyword to solve this error.
Moral: Don't use relative paths to import a file anywhere in your project, always use the "package:" scheme.
You could make a custom name as well.
String createDownloadDocName(){
return'${fileName}-${DateTime.now().microsecond}';
}
Sorry, I had problem with await usage - I tried to get access to file before I downloaded it

Writting and Reading files into mobile devices

I wrote the below code that reads a tring from URL, writting the cotent into a file data.csv then trying to open the file to read its contents as csv but got an error that:
I/flutter ( 6145): FileSystemException: Cannot open file, path =
'data.csv' (OS Error: No such file or directory, errno = 2) I/flutter
( 6145): File is now closed. E/flutter ( 6145):
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception:
FileSystemException: Cannot open file, path = 'data.csv' (OS Error:
Read-only file system, errno = 30)
My code is:
import 'dart:convert';
import 'dart:io';
import 'dart:async';
void _incrementCounter() {
setState(() {
new HttpClient().getUrl(Uri.parse('https://docs.google.com/spreadsheets/d/e/2PACX-1vQvf9tp4-fETDJbC-HRmRKvVFAXEAGO4lrYPpVeiYkB6nqqXdSs3CjX0eBMvjIoEeX9_qU6K2RWmzVk/pub?gid=0&single=true&output=csv'))
.then((HttpClientRequest request) => request.close())
// .then((HttpClientResponse response) => response.transform(new Utf8Decoder()).listen(print));
.then((HttpClientResponse response) => response.pipe(new File('data.csv').openWrite()));
final File file = new File("data.csv");
Stream<List> inputStream = file.openRead();
inputStream
.transform(utf8.decoder) // Decode bytes to UTF-8.
.transform(new LineSplitter()) // Convert stream to individual lines.
.listen((String line) { // Process results.
List row = line.split(','); // split by comma
String city = row[0];
String branches = row[1];
print('$city, $branches');
},
onDone: () { print('File is now closed.'); },
onError: (e) { print(e.toString()); });
// List<List<dynamic>> rowsAsListOfValues = const CsvToListConverter().convert(yourString);
_counter++;
});
}
Your code are not running in the order that you think so you will end up trying to read the file before it has been written. I think you code is going to be easier to understand if you use my answer for a other question you have asked: Reading data from url in List
And again, please read: https://dart.dev/codelabs/async-await

Unhandled Exception: FileSystemException

When I upload .zip file or .docx ,it deos not work ,but when I choose .c files they work fine
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Failed to decode data using encoding 'utf-8', path = '/storage/emulated/0/New Text Document.zip'
File _file;
Future upload() async {
if (_file == null) { return; }
String path = _file.path.split("/").last;
var pdf = _file.readAsStringSync();
var url ="http://192.168.1.112/flutter/upload_file.php";
var data = { "path": path, "pdf": pdf };
var response = await http.post(url, body: data);
}
Future pickFile() async {
final myfile = await FilePicker.getFile();
setState(() {
_file = File(myfile.path);
});
}
Here is my php file I tried to use readAsBytesSync and it gave me error
<?php
include 'connection.php';
include 'register.php';
$pdf = $_POST['pdf'];
$file_name = $_POST['path'];
file_put_contents("uploads\\".$file_name, $pdf);
?>
_file.readAsStringSync()
This assumes that your file is plain text. A *.c file most likely is. Neither zip, nor doc nor pdf files are.
What you need to do is read your file as bytes:
var contents = _file.reasAsBytesSync();
Now, I don't know what your API expects to get, so I cannot really help you with how to get the bytes transferred. But this is the way to go.

ionic 3 capacitor return file paths from document directory

Ionic 3 capacitor on ios.
I have stored jpeg files in the AppData Documents directory. Now I want to display the images. The images are displayed in the HTML with
img src="{{image2}}" ( one option )
This is my working code, it returns the actual path to the file ( based in part on Josh Morony 'ionic capacitor photo save', in part on capacitor source code FileSystem API) :
fileName1 = "photo2.jpeg";
Filesystem.getUri({
directory: FilesystemDirectory.Data,
path: fileName1
}).then((result) => {
this.image1 = result.uri.replace('file://', '_capacitor_');
}, (err) => {
console.log(err);
});
fileName2 = "photo2.jpeg";
Filesystem.getUri({
directory: FilesystemDirectory.Data,
path: fileName2
}).then((result) => {
this.image2 = result.uri.replace('file://', '_capacitor_');
}, (err) => {
console.log(err);
});
fileName3 = "photo3.jpeg";
Filesystem.getUri({
directory: FilesystemDirectory.Data,
path: fileName3
}).then((result) => {
this.image3 = result.uri.replace('file://', '_capacitor_');
}, (err) => {
console.log(err);
});
example of path returned in this.image: capacitor/var/mobile/Containers/Data/Application/1C408C3C-
DB30-47C1-3416-6FB2697DC7AF/Documents/photo2.jpeg
I have 20 photos in the Documents directory; the names of the photos in an array = ["photo1.jpeg","photo2.jpeg","photo3.jpeg"," ...];
I can repeat the code above 20 times and get 20 paths, but I would like to refactor the code so that the code returns an array of 20 paths. I do not know how to achieve that in ionic 3.

Sails.js checking stuff before uploading files to MongoDB with skipper (valid files, image resizing etc)

I'm currently creating a file upload system in my application. My backend is Sails.js (10.4), which serves as an API for my separate front-end (Angular).
I've chosen to store the files I'm uploading to my MongoDB instance, and using sails' build in file upload module Skipper. I'm using the adapter skipper-gridfs (https://github.com/willhuang85/skipper-gridfs) to upload the files to mongo.
Now, it's not a problem to upload the files themselves: I'm using dropzone.js on my client, which sends the uploaded files to /api/v1/files/upload. The files will get uploaded.
To achieve this i'm using the following code in my FileController:
module.exports = {
upload: function(req, res) {
req.file('uploadfile').upload({
// ...any other options here...
adapter: require('skipper-gridfs'),
uri: 'mongodb://localhost:27017/db_name.files'
}, function(err, files) {
if (err) {
return res.serverError(err);
}
console.log('', files);
return res.json({
message: files.length + ' file(s) uploaded successfully!',
files: files
});
});
}
};
Now the problem: I want to do stuff with the files before they get uploaded. Specifically two things:
Check if the file is allowed: does the content-type header match the file types I want to allow? (jpeg, png, pdf etc. - just basic files).
If the file is an image, resize it to a few pre-defined sizes using imagemagick (or something similar).
Add file-specific information that will also be saved to the database: a reference to the user who has uploaded the file, and a reference to the model (i.e. article/comment) the file is part of.
I don't have a clue where to start or how to implement this kind of functionality. So any help would be greatly appreciated!
Ok, after fiddling with this for a while I've managed to find a way that seems to work.
It could probably be better, but it does what I want it to do for now:
upload: function(req, res) {
var upload = req.file('file')._files[0].stream,
headers = upload.headers,
byteCount = upload.byteCount,
validated = true,
errorMessages = [],
fileParams = {},
settings = {
allowedTypes: ['image/jpeg', 'image/png'],
maxBytes: 100 * 1024 * 1024
};
// Check file type
if (_.indexOf(settings.allowedTypes, headers['content-type']) === -1) {
validated = false;
errorMessages.push('Wrong filetype (' + headers['content-type'] + ').');
}
// Check file size
if (byteCount > settings.maxBytes) {
validated = false;
errorMessages.push('Filesize exceeded: ' + byteCount + '/' + settings.maxBytes + '.');
}
// Upload the file.
if (validated) {
sails.log.verbose(__filename + ':' + __line + ' [File validated: starting upload.]');
// First upload the file
req.file('file').upload({}, function(err, files) {
if (err) {
return res.serverError(err);
}
fileParams = {
fileName: files[0].fd.split('/').pop().split('.').shift(),
extension: files[0].fd.split('.').pop(),
originalName: upload.filename,
contentType: files[0].type,
fileSize: files[0].size,
uploadedBy: req.userID
};
// Create a File model.
File.create(fileParams, function(err, newFile) {
if (err) {
return res.serverError(err);
}
return res.json(200, {
message: files.length + ' file(s) uploaded successfully!',
file: newFile
});
});
});
} else {
sails.log.verbose(__filename + ':' + __line + ' [File not uploaded: ', errorMessages.join(' - ') + ']');
return res.json(400, {
message: 'File not uploaded: ' + errorMessages.join(' - ')
});
}
},
Instead of using skipper-gridfs i've chosen to use local file storage, but the idea stays the same. Again, it's not as complete as it should be yet, but it's an easy way to validate simple stuff like filetype and size. If somebody has a better solution, please post it :)!
You can specify a callback for the .upload() function. Example:
req.file('media').upload(function (error, files) {
var file;
// Make sure upload succeeded.
if (error) {
return res.serverError('upload_failed', error);
}
// files is an array of files with the properties you want, like files[0].size
}
You can call the adapter, with the file to upload from there, within the callback of .upload().