NativeScript file.renameSync() fails on Android 12 with "Error: Failed to rename file..." - filesystems

I have file system code that renames a file in the documents folder within a NativeScript JavaScript application. It's worked for years on both iOS and Android, but now fails consistently on Android 12.
The code looks like this:
const fs = require("#nativescript/core/file-system");
let documentsPath = fs.knownFolders.documents().path;
let filePath = fs.path.join(documentsPath, filename);
let tempPath = fs.path.join(documentsPath, filename + ".tmp");
let newFile = await http.getFile(httpRequestOptions, tempPath); // file object
if (fs.File.exists(filePath)) { // if older data file exists
let oldFile = fs.File.fromPath(filePath);
oldFile.removeSync((error) => {
console.log("removeError: " + error );
});
}
newFile.renameSync(filename,(error) => {
console.log("renameError: " + error );
});
On Android 12, this code now fails with the message,
renameError: Error: Failed to rename file '/data/user/0/tech.govia.festivelo/files/FV_22_Thurs_Long.pdf.tmp' to 'FV_22_Thurs_Long.pdf'
But doesn't give any insight into why it failed. This occurs on a Samsung Galaxy S10e device.
I can create and delete files successfully, but can't rename. I'd welcome any insights here, as I haven't found anything in my searches.
Edit Sep 6, 2022: for what it's worth, I can read the new file's content and write it out to a new file to effectively perform a copy, so I have a hacky workaround, 'tho it's way less efficient that simply renaming.

Turns out a fully-qualified path is required on Android 12, not just a filename, so changing
newFile.renameSync(filename,(error) => {
console.log("renameError: " + error );
});
to
newFile.renameSync(filePath,(error) => {
console.log("renameError: " + error );
});
Is sufficient to fix the problem.
Much thanks to triniwiz on the {N} Discord for the pointer.
Edit Sep 8 2022: Testing on iOS reveals file name is still needed, and using a full path causes an error.

Related

Opening a newly created File in Dart

I am new to dart and am currently trying to create a file from a data String.
All looks good so far as the length is not 0. But when i open the file, it instantly closes again, no console output, no errors.
I'd appreciate any pointers in the right direction, if any information is missing, please point it out and i will provide if possible.
void createFile(data) async{
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
var file = new File(tempPath+widget.tileText);
var sink = file.openWrite();
sink.write(data.codeUnits);
await sink.flush();
await sink.close();
print(await file.length());
OpenFile.open(file.path);
}
UPDATE: added flush() and await before close() - loading a little smoother now, but File still closes instantly
Update2: removed create() (was a misunderstanding on my part)
now getting console output when the File closes: D/EGL_emulation(23235): eglCreateContext: 0xef02d650: maj 2 min 0 rcv 2
Running i ton my phone gives no console log, instead a simple "Can't open File" from the viewing application,i doublechecked the Path, it looks ok and it exists
So i found 2 problems and solved it now:
The path was missing a "/"
I didn't format the data right, i had to decode it and use writeAsBytes(), ditched the sink
now it's working
void createFile(data) async{
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
var file = new File(tempPath+"/"+widget.tileText);
await file.writeAsBytes(base64Decode(data));
print(await file.length());
OpenFile.open(file.path);
print(await tempDir.exists());
print(file.path);
}

discord.js saving an attachment "undefined"?

I've had a problem recently with users trolling and then deleting images before I can see what they are. So I'm creating a log to download everything into a log. (yes I've instantiated fs.js already). For some reason though, when writing the file... the file is only 9 bytes big (and the content is just "undefined"). Please help.
var attachment = (message.attachments).array();
attachment.forEach(function(attachment) {
console.log(attachment.url);
tempName = attachment.url.split("/");
attachName = tempName[tempName.length-1]
console.log(attachName);
fs.writeFileSync(dir + "/" + attachName, attachment.file, (err) => {
// throws an error, you could also catch it here
if (err) throw err;
// success case, the file was saved
console.log('attachment saved!');
});
theLog += '<img src="'+ "attachments/" + message.channel.name + "/" + attachName + '"> \n';
//theLog += '<img src="'+ attachment.url + '"> \n';
})
Lets start with answering why it saves it as undefined.
If you check the docs for MessageAttachment message.attachments.first().file is undefined. there is fileName and fileSize but no file
To save the file you can do 2 things...
Saving the URLS.
You can save the url in an array in a JSON file like so:
JSON FILE
{
"images":[]
}
JS FILE
let imgs = require(JSON_FILE)
imgs.images.push(attachment.url);
fs.writeFile(JSON_FILE,JSON.stringify(imgs,null,4));
- Saving the IMAGE itself
You can use the request module to pull images from a url
JS FILE
//Start of code
let request = require(`request`);
let fs = require(`fs`);
//Later
request.get(attachment.url)
.on('error', console.error)
.pipe(fs.createWriteStream(`Img-${Date.now()}`));//The "Img-${Date.now}" Guarantees Unique file names.
EDIT: request is deprecated. It's been replaced by fetch I can't confirm this code work's with fetch but the underlining principle is the same.
I ended up solving it with a tiny function. Thanks everyone (especially the guy asking what a variable was... that was super helpful)
function downloadAttachment(url, dest, hash){
console.log('initiating download of '+ url +'...');
request(url).pipe(fs.createWriteStream(dest));
}
the "hash" variable is not used right now. I was hungry and craving corned beef hash...

Google apps script, openByURL returns missing file?

I've been trying to figure out why part of my Google App script doesn't work, but I've failed to come up with an answer.
The script is downloading an attachment, CSV, from an email in Gmail and stores in with a specific name in a specific folder - this works perfectly fine.
But then I want to edit the CSV, and this is where I run into problems.
var newFolderIterator = DriveApp.getFoldersByName(destinationFolderName)
var newFolderId, myFileName, myFileId
while(newFolderIterator.hasNext()) {
newFolderId = newFolderIterator.next().getId()
var newFileList = DriveApp.getFolderById(newFolderId).getFiles()
while(newFileList.hasNext()) {
myFileName = newFileList.next()
myFileId = myFileName.getId()
var myFileURL = myFileName.getUrl()
Logger.log(myFileName.getId() + " " + myFileName.getName()) //Logs the ID and Name
Logger.log(myFileURL) //Logs the URL
var ss = SpreadsheetApp.openById(myFileName.getId()) //Error, cannot find the ID (error message: perhaps it's missing?)
}
}
I've tried using the openByURL as well, with the same error message.
Probably really easy to fix, any hints and tips is appreciated.
Thanks
The problem here is you are uploading a CSV but attempting to open it with SpreadsheetApp. SpreadsheetApp can only open Google Sheets documents, and your CSV is not automatically converted.
The CSV must first be converted to a Google Sheets document before you can access it with SpreadsheetApp.
You may be able to do this on upload, but I haven't tried this personally. This question looks relevant:
How to automatically import data from uploaded CSV or XLS file into Google Sheets

downloading .tar.gz file from nodejs server using MEAN stack

I am trying to download a tar.gz file from server which gets created at run time. Here is the code at the server side
function downloadFile(req, res) {
//some code to generate the tar file
var file = ... code to compute the path ...
res.download(file);
}
The method which calls this from the client side looks like this
continueWithApplication(app) {
this.$http.get('/api/applications/get-agent/' + app._id + '/' + this.nodeName).then(res => {
var data = new Blob([res.data], { type: 'application/x-gzip' });
this.FileSaver.saveAs(data, 'agent-1.0.tar.gz');
})
.catch(err => {
alert('error downloading agent.');
});
}
I am using angular-file-saver to get the file downloaded.
I can see the file getting downloaded but when i try to untar the file it doesn't untar the content but creates a file with .cpgz extension. I have verified that the file that gets generated at server side is a valid .tar.gz file by unzipping it. Below screeen shot shows what happens when i try to untar the dowaloaded file (agent-1.0.tar.tar.gz -> agent-1.0.tar.gz.cpgz)
Any idea what am i doing wrong? Any pointer is deeply appreciated.
P.S. Please pardon my limited knowledge of angular and mean stack.

Cordova + Sencha Touch: Delete file after it has been used

So I'm using Cordova + Sencha Touch for an app and Antair's SQLitePlugin (https://github.com/Antair/Cordova-SQLitePlugin) to import and use an SQLite database in it.
I managed to import my (kinda big) prepopulated database using Antair's importPrepopulatedDatabase ( window.sqlitePlugin.importPrepopulatedDatabase({file:"mydb.db",importIfExists:false}) ) method and it works just fine. The thing is I noticed the app is using twice the size it really needs as it keeps the file after importing it.
I checked and the app works just fine if I delete the file from /cordova/www/db and build again, it keeps the actual db in the app's filesystem I guess, but I can't find a way to programmatically delete that file after it has been imported.
I looked around and found cordova file plugin (https://github.com/apache/cordova-plugin-file/blob/master/doc/index.md), but from what I saw from the docs it only grants read permissions on the www folder, so that won't do it.
Does anyone have any workaround for this? I could really use that extra space.
By using cordova file plugin api you can do this,
please refer this :
deleteFile: function(fileName) {
var that = this;
if (!fileName) {
console.error("No fileName specified. File could not be deleted.");
return false;
}
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, function(fileSystem){ // this returns the tmp folder
// File found
fileSystem.root.getFile(fileName, {create: false}, function(fileEntry){
fileEntry.remove(function(success){
console.log(success);
}, function(error){
console.error("deletion failed: " + error);
});
}, that.get('fail'));
}, this.get('fail'));
}

Resources