How to create an empty file in Deno? - deno

As per deno documentation for writeFile if I want to write in a file and overwrite if the file already exists I need this command -
await Deno.writeFile("hello1.txt", data); // overwrite "hello1.txt" or create it
What I need is to create an empty file and if a file with the same name already exists overwrite it with an empty file, so I tried to run the function without data and I am getting this error.
await Deno.writeFile("hello1.txt");
An argument for 'data' was not provided.
data: Uint8Array,
How can I create an empty file in Deno and overwrite any file exists with the same name?

Pass an empty Uint8Array to Deno.writeFile
await Deno.writeFile("./hello1.txt", new Uint8Array());
You can also use Deno.open with truncate: true
await Deno.open("./hello1.txt", { create: true, write: true, truncate: true });
or Deno.create:
await Deno.create("./hello1.txt")
Alternatively, if you know the file already exists you can use Deno.truncate
await Deno.truncate("./hello1.txt");

You can use Deno.create:
Creates a file if none exists or truncates an existing file and resolves to an instance of Deno.File.
await Deno.create("hello1.txt")
Process deeper file paths with possibly not existent directories safely:
import { ensureFile } from "https://deno.land/std/fs/ensure_file.ts";
const file = "./deep/hello1.txt"; // `deep` doesn't need to exist
await ensureFile(file); // ensures file and containing directories
await Deno.truncate(file);

You can use writeTextFile and pass an empty string. Rest as suggested above, use ensureFile and truncate for other needs.
(async function() {
await Deno.writeTextFile("./helloworld.txt", "")
})()

Related

How do you store extra information of files stored in Cloud Storage for Firebase with Flutter

I'm trying to store some files in Firebase storage and when the user accesses or downloads those files, I want to show some extra information about each file (such as a description, date, etc). File metadata can only store name, size and contentType so where and how can I store the extra information?
As explained in the doc, when uploading a file you can add some "custom metadata" via the SettableMetadata Class, as follows:
// Create your custom metadata.
firebase_storage.SettableMetadata metadata =
firebase_storage.SettableMetadata(
cacheControl: 'max-age=60',
customMetadata: <String, String>{
'userId': 'ABC123',
},
);
try {
// Pass metadata to any file upload method e.g putFile.
await firebase_storage.FirebaseStorage.instance
.ref('uploads/file-to-upload.png')
.putFile(file, metadata);
} on firebase_core.FirebaseException catch (e) {
// e.g, e.code == 'canceled'
}
You can use custom meta along with file in firebase storage like the other answer, or you could create a firestore document for it. Let me know if you need some sample code

Edge browser Native File System removeEntry use

I'm working with the newest version of Edge (Canary release 86.0.615.0) and I can get the new Native File System API showOpenFilePicker to let me access files but I can't find a reference to the directoryHandle functions including the removeEntry function if the user elects to remove the file. Am I missing a special flag? I have an Origin-Tracker code and I also have the experimental flag set for the Native File System API.
If you have a directory handle, you can delete files or folders as in the example below:
// Delete a file.
await directoryHandle.removeEntry('Abandoned Projects.txt');
// Recursively delete a folder.
await directoryHandle.removeEntry('Old Stuff', { recursive: true });
You can obtain a directory handle from the picker:
const directoryHandle = await window.showDirectoryPicker();
To iterate over the entries of a directory, you can use the code snippet below:
for await (const entry of directoryHandle.values()) {
console.log(entry.kind, entry.name);
}

Restore Firestore database to exact state found in previous export

I have the following https callable cloud function that imports all documents found in a backup.
const path = `${timestamp}`;
const projectId = await auth.getProjectId();
// we change the action for importDocuments
const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default):importDocuments`;
const backup_route = `gs://${BUCKET_NAME}/${path}`;
return client.request({
url,
method: 'POST',
data: {
inputUriPrefix: backup_route,
}
}).then(async (res: any) => {
console.log(`Began backup restore from folder ${backup_route}`);
return Promise.resolve(res.data.name);
}).catch(async (e) => {
return Promise.reject(new functions.https.HttpsError('internal', e.message));
})
I use to this function to restore the database to the exact state it was when it was exported.
The problem is that the import operation, does not affect documents that are not found in the export. So new documents added after the export will remain in the database.
The following quote from the documentation explains this behaviour:
If a document in your database is not affected by an import, it will remain in your database after the import.
Is deleting the whole database before starting the import operation my only option? I can not find an operation that achieves the desired behaviour.
The provided export mechansim isn't meant for what what most people would call a "backup" that would be "restored" in the event of data loss. It's simply an export. It useful for making a copy of a database to be imported elsewhere, making it easy to duplicate a database across environments without having to write a lot of code.
If you want a fresh copy of the database from an import with no other documents, you will have to wipe out what's there before importing.

Download a file from a URL to a user accessible location

I am building an app using Nativescript/Angular 2
I want to be able to download a file from a URL and save it to the device in a location the average user would have no problems finding it. I believe downloads would be the best place for this on both iOS and Android. Please correct me if I am wrong.
The file can be any file type, not just an image. So mainly spreadsheet, word document, pdf, png, jpg, etc.
I have searched online and through the documentation. The documentation describes a method called getFile which gets a file and saves it to your device.
I have implemented this in my code as follows:
download (id) {
console.log('Download Started');
getFile("https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png").then(function (r) {
console.log(r.path);
}, function (e) {
//// Argument (e) is Error!
});
}
The problem with this is that it saves it to a non-user accessible location such as:
/data/user/0/com.myapp.example/files/logo.png
Update:
I have also tried specifying the path directly with:
fs.knownFolders.documents();
However, this method gets the documents folder for the current application that is NOT accessible by the user or external applications
After some unsuccessful attempts, I finally found how to save file to user "Downloads" folder (something like sdcard/Download). You can use android.os.Environment method to get this folder.
Add this in your component:
import { getFile } from 'tns-core-modules/http';
import * as fileSystem from "tns-core-modules/file-system";
import { isAndroid } from "tns-core-modules/platform";
import { alert } from "tns-core-modules/ui/dialogs";
declare var android;
<...>
public download (url, fileName) {
if (isAndroid) {
const permissions = require("nativescript-permissions");
permissions.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, "I need these permissions because I'm cool")
.then(() => {
let downloadedFilePath = fileSystem.path.join(android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(), fileName);
getFile(url, downloadedFilePath).then(resultFile => {
alert({
title: 'Saved!',
okButtonText: 'OK',
message: `File saved here:\n${resultFile.path}`
});
}, error => {
alert({
title: 'Error',
okButtonText: 'OK',
message: `${error}`
});
});
});
}
}
What else you should know:
1) There is no any kind of download indicator, standard system download bar also not appears, and I don't know how to solve this.
2) For iOS you may try to use
const filePath = fileSystem.path.join(fileSystem.knownFolders.ios.downloads().path, fileName);
getFile(url, filePath).then((resultFile) => {}, (error) => {});
I think, it's the shame that NS docs don't talk straight, that you can't save files in user accessible location only with NS functions. I figured it out only when I read comments in file /node_modules/tns-core-modules/file-system/file-system.d.ts
Hope this helps you.
To get it working on iPhone, you can do the following (TypeScript):
import { knownFolders, path } from "tns-core-modules/file-system";
let destination = path.join(knownFolders.documents(), "file_name.txt");
// logic to save your file here ...
// the important thing is that you have to save your file in knownFolders.documents()
Then in Info.plist, you have to add the following permissions:
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
Now if you go to your iPhone's Files app > On My iPhone > Your App's Name, you should see the file there.
Basically, the Documents folder is a private folder inside your application's directory that only you can see. However, when you enable the two permissions above, it allows file sharing so that your user can access the folder and its contents.
The same documentation says that you can specify the file location like this:
download (id) {
console.log('Download Started');
var folder = fs.knownFolders.documents();
var file = fs.path.join(folder.path, "logo.png");
var url = "https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png"
getFile(url, file).then(function (r) {
console.log(r.path);
}, function (e) {
//// Argument (e) is Error!
});
}
disclaimer: never tried it myself, just read the docs ...
You can specify a filesystem path directly, like this:
var folder = fs.Folder.fromPath('/sdcard/Download');
Note that /sdcard/Download will only work on Android; you can replace it with whatever (publicly accessible) folder you want to save your data to.
There doesn't yet seem to be a cross-platform way to choose a folder path, so you'll have to work out something manually. See this GitHub thread for more.
I realize that this is an older thread, but perhaps this can help someone:
If you use currentApp(), instead of documents(), you can access the folder you need. For example:
var directories = fs.knownFolders.currentApp();
var folder = directories.getFolder('./nameofaccessiblefolder');
I know this thread is 3 years ago but in case you have the same issue, I hope this solution will save time for you.
I solved the same issue by adding android:requestLegacyExternalStorage="true" inside the AndroidManifest.xml file
follow the thread here

How to list files in folder

How can I list all files inside a folder with Meteor.I have FS collection and cfs:filesystem installed on my app. I didn't find it in the doc.
Another way of doing this is by adding the shelljs npm module.
To add npm modules see: https://github.com/meteorhacks/npm
Then you just need to do something like:
var shell = Meteor.npmRequire('shelljs');
var list = shell.ls('/yourfolder');
Shelljs docs:
https://github.com/arturadib/shelljs
The short answer is that FS.Collection creates a Mongo collection that you can treat like any other, i.e., you can list entries using find().
The long answer...
Using cfs:filesystem, you can create a mongo database that mirrors a given folder on the server, like so:
// in lib/files.js
files = new FS.Collection("my_files", {
stores: [new FS.Store.FileSystem("my_files", {"~/test"})] // creates a ~/test folder at the home directory of your server and will put files there on insert
});
You can then access this collection on the client to upload files to the server to the ~test/ directory:
files.insert(new File(['Test file contents'], 'my_test_file'));
And then you can list the files on the server like so:
files.find(); // returns [ { createdByTransform: true,
_id: 't6NoXZZdx6hmJDEQh',
original:
{ name: 'my_test_file',
updatedAt: (Date)
size: (N),
type: '' },
uploadedAt: (Date),
copies: { my_files: [Object] },
collectionName: 'my_files'
}
The copies object appears to contain the actual names of the files created, e.g.,
files.findOne().copies
{
"my_files" : {
"name" : "testy1",
"type" : "",
"size" : 6,
"key" : "my_files-t6NoXZZdx6hmJDEQh-my_test_file", // This is the name of the file on the server at ~/test/
"updatedAt" : ISODate("2015-03-29T16:53:33Z"),
"createdAt" : ISODate("2015-03-29T16:53:33Z")
}
}
The problem with this approach is that it only tracks the changes made through the Collection; if you add something manually to the ~/test directory, it won't get mirrored into the Collection. For instance, if on the server I run something like...
mkfile 1k ~/test/my_files-aaaaaaaaaa-manually-created
Then I look for it in the collection, it won't be there:
files.findOne({"original.name": {$regex: ".*manually.*"}}) // returns undefined
If you just want a straightforward list of files on the server, you might consider just running an ls. From https://gentlenode.com/journal/meteor-14-execute-a-unix-command/33 you can execute any arbitrary UNIX command using Node's child_process.exec(). You can access the app root directory with process.env.PWD (from this question). So in the end if you wanted to list all the files in your public directory, for instance, you might do something like this:
exec = Npm.require('child_process').exec;
console.log("This is the root dir:");
console.log(process.env.PWD); // running from localhost returns: /Users/me/meteor_apps/test
child = exec('ls -la ' + process.env.PWD + '/public', function(error, stdout, stderr) {
// Fill in this callback with whatever you actually want to do with the information
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if(error !== null) {
console.log('exec error: ' + error);
}
});
This will have to run on the server, so if you want the information on the client, you'll have to put it in a method. This is also pretty insecure, depending on how you structure it, so you'd want to think about how to stop people from listing all the files and folders on your server, or worse -- running arbitrary execs.
Which method you choose probably depends on what you're really trying to accomplish.

Resources