In Elm, how can I access a file on my local drive?
For example, I need to access the file:
c:\MyFolder\somefile.txt
(I'm assuming you're targeting the browser and not Node. If you want Node support, here is the documentation for it's fs module. The high-level usage will be similar to what I'm describing below for browsers.)
There is not (yet) an Elm-only API for this, so you'll have to use ports. This article is very helpful, I will adapt its example.
In short, you have to use File and FileReader API (caniuse.com), and on load of the file send the data to Elm through port. (In my example below, Elm will get a GetFile {name : String, content : String} message for every file submitted.) Here is a working example in Ellie.
Msg:
type Msg
= GetFile File
type alias File =
{ name : String
, content : String
}
Port:
port getFile : (File -> msg) -> Sub msg
(don't forget port module instead of module on top of the Elm source)
Subscription:
subscriptions : Model -> Sub Msg
subscriptions model =
getFile GetFile
HTML file input:
<input type="file" id="files" name="files[]" multiple />
JS (the main part!):
<script>
var app = Elm.Main.fullscreen();
function handleFileSelect(evt) {
var files = evt.target.files;
for (var i = 0, f; f = files[i]; i++) {
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
app.ports.getFile.send({name: theFile.name, content: e.target.result});
};
})(f);
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
EDIT: this example only accepts images. If you don't want that, remove the
if (!f.type.match('image.*')) {
continue;
}
part and do something different in the viewFile function (ie. don't try to interpret the content data as an image src).
Elm is now able open files as of 0.19.
Steps are as follows:
Attach an event handler to a button that sends the appropriate message to the update function.
Update function receives message and runs the file-opening function, which tells Elm runtime to ask browsers to open a file selection dialogue.
Once user action has completed, Elm runtime returns a data of type File to the update function, and the update function can decide what to do.
To read file's content, a file-reading function has to be invoked. Again, the function tells the Elm runtime to read the content of the file. The runtime again invokes your update function, this time passing the content of the file.
Please refer to this thread on Elm discourse, which includes this example on Ellie app
Related
I am trying to upload images to Real time Firebase Database by creating two folders using Compressor library and need to display image like messenger with username but i am unable to display image due to url issue
var filePath = mStorageRef!!.child("chat_profile_images")
.child(userId + ".jpg")
//Create another directory for thumbimages ( smaller, compressed images)
var thumbFilePath = mStorageRef!!.child("chat_profile_images")
.child("thumbs")
.child(userId + ".jpg")
filePath.putFile(resultUri)
.addOnCompleteListener{
task: Task<UploadTask.TaskSnapshot> ->
if (task.isSuccessful) {
//Let's get the pic url
var donwloadUrl = task.result?.storage?.downloadUrl.toString()
Log.d(TAG, "Profilepic link: $donwloadUrl")
//Upload Task
var uploadTask: UploadTask = thumbFilePath
.putBytes(thumbByteArray)
uploadTask.addOnCompleteListener{
task: Task<UploadTask.TaskSnapshot> ->
var thumbUrl = task.getResult()?.storage?.downloadUrl.toString()
Log.d(TAG, "Profilepic link: $thumbUrl")
i tried to change downloadUrl
filepath.downloadUrl.toString
thumbFilePath.downloadUrl.toString
but both these values getting "com.google.android.gms.tasks.zzu"
i also tried to change
task.result.sessionurl.downloadUrl.toString
for this one i am getting downloadUrl but not a complete solution for my problem as still i cannot display image i need to get thumbUrl downloadUrl
You have the exact same and very common misunderstanding as in this question, except it's in java. You should follow the documentation here to understand get getDownloadUrl works. As you can see from the linked API documentation, it's not a property getter, it's actually a method that returns a Task<Uri> that tracks the asynchronous fetch of the URL you want, just like the upload task:
filePath.downloadUrl
.addOnSuccessListener { urlTask ->
// download URL is available here
val url = urlTask.result.toString()
}.addOnFailureListener { e ->
// Handle any errors
}
This will only work after the upload is fully complete.
Correct way of getting download link after uploading
here
Just putting out there, I also encounter the same problem,
but both these values getting "com.google.android.gms.tasks.zzu"
but it wasn't the same mistake from the OP
used addOnCompleteListener instead of addOnSuccesslistener
My Error code:
imageRef.downloadUrl.addOnCompleteListener { url ->
val imageURL = url.toString()
println("imageURL: $imageURL , url: $url")
addUserToDatabase(imageURL)
}
I'm creating an image upload API that takes files with POST requests. Here's the code:
def upload = Action(parse.temporaryFile) { request =>
val file = request.body.file
Ok(file.getName + " is uploaded!")
}
The file.getName returns something like: requestBody4386210151720036351asTemporaryFile
The question is how I could get the original filename instead of this temporary name? I checked the headers. There is nothing in it. I guess I could ask the client to pass the filename in the header. But should the original filename be included somewhere in the request?
All the parse.temporaryFile body parser does is store the raw bytes from the body as a local temporary file on the server. This has no semantics in terms of "file upload" as its normally understood. For that, you need to either ensure that all the other info is sent as query params, or (more typically) handle a multipart/form-data request, which is the standard way browsers send files (along with other form data).
For this, you can use the parse.multipartFormData body parser like so, assuming the form was submitted with a file field with name "image":
def upload = Action(parse.multipartFormData) { request =>
request.body.file("image").map { file =>
Ok(s"File uploaded: ${file.filename}")
}.getOrElse {
BadRequest("File is missing")
}
}
Relevant documentation.
It is not sent by default. You will need to send it specifically from the browser. For example, for an input tag, the files property will contain an array of the selected files, files[0].name containing the name of the first (or only) file. (I see there are possibly other properties besides name but they may differ per browser and I haven't played with them.) Use a change event to store the filename somewhere so that your controller can retrieve it. For example I have some jquery coffeescript like
$("#imageFile").change ->
fileName=$("#imageFile").val()
$("#imageName").val(fileName)
The value property also contains a version of the file name, but including the path (which is supposed to be something like "C:\fakepath" for security reasons, unless the site is a "trusted" site afaik.)
(More info and examples abound, W3 Schools, SO: Get Filename with JQuery, SO: Resolve path name and SO: Pass filename for example.)
As an example, this will print the original filename to the console and return it in the view.
def upload = Action(parse.multipartFormData(handleFilePartAsFile)) { implicit request =>
val fileOption = request.body.file("filename").map {
case FilePart(key, filename, contentType, file) =>
print(filename)
filename
}
Ok(s"filename = ${fileOption}")
}
/**
* Type of multipart file handler to be used by body parser
*/
type FilePartHandler[A] = FileInfo => Accumulator[ByteString, FilePart[A]]
/**
* A FilePartHandler which returns a File, rather than Play's TemporaryFile class.
*/
private def handleFilePartAsFile: FilePartHandler[File] = {
case FileInfo(partName, filename, contentType) =>
val attr = PosixFilePermissions.asFileAttribute(util.EnumSet.of(OWNER_READ, OWNER_WRITE))
val path: Path = Files.createTempFile("multipartBody", "tempFile", attr)
val file = path.toFile
val fileSink: Sink[ByteString, Future[IOResult]] = FileIO.toPath(file.toPath())
val accumulator: Accumulator[ByteString, IOResult] = Accumulator(fileSink)
accumulator.map {
case IOResult(count, status) =>
FilePart(partName, filename, contentType, file)
} (play.api.libs.concurrent.Execution.defaultContext)
}
I am trying to write a plugin which parses the source code of any opened (java) file.
All I have found so far is IResourceChangeListener, but what I need is a Listener for some kind of "onRecourceOpenedEvent".
Does something like that exist?
The nearest you can get to this is to use an IPartListener to list to part events:
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService().addPartListener(listener);
In the listener the partOpened tells you about a new part opening:
public void partOpened(IWorkbenchPart part) {
// Is this an editor
if (part instanceof IEditorPart) {
IEditorPart editor = (IEditorPart)part;
// Get file being edited
IFile file = (IFile)editor.getAdapter(IFile.class);
// TODO file is the current file - may be null
}
}
How do I open an existing file on the server when a user clicks an actionlink? The following code works for downloading a file but I want to open a new browser window, or tab, and display the file contents.
public ActionResult Download()
{
return File(#"~\Files\output.txt", "application/text", "blahblahblah.txt");
}
You must add "inline" for a new tab.
byte[] fileBytes = System.IO.File.ReadAllBytes(contentDetailInfo.ContentFilePath);
Response.AppendHeader("Content-Disposition", "inline; filename=" + contentDetailInfo.ContentFileName);
return File(fileBytes, contentDetailInfo.ContentFileMimeType);
The way you're using the File() method is to specify a file name in the third argument, which results in a content-disposition header being sent to the client. This header is what tells a web browser that the response is a file to be saved (and suggests a name to save it). A browser can override this behavior, but that's not controllable from the server.
One thing you can try is to not specify a file name:
return File(#"~\Files\output.txt", "application/text");
The response is still a file, and ultimately it's still up to the browser what to do with it. (Again, not controllable from the server.) Technically there's no such thing as a "file" in HTTP, it's just headers and content in the response. By omitting a suggested file name, the framework in this case may omit the content-disposition header, which is your desired outcome. It's worth testing the result in your browser to see if the header is actually omitted.
Use a target of blank on your link to open it in a new window or tab:
Download File
However, forcing the browser to display the contents is out of your control, as it entirely depends on how the user has configured their browser to deal with files that are application/text.
If you are dealing with text, you can create a view and populate the text on that view, which is then returned to the user as a regular HTML page.
please try this and replace your controller name and action name in html action link
public ActionResult ShowFileInNewTab()
{
using (var client = new WebClient()) //this is to open new webclient with specifice file
{
var buffer = client.DownloadData("~\Files\output.txt");
return File(buffer, "application/text");
}
}
OR
public ActionResult ShowFileInNewTab()
{
var buffer = "~\Files\output.txt"; //bytes form this
return File(buffer, "application/text");
}
this is action link which show in new blank tab
<%=Html.ActionLink("Open File in New Tab", "ShowFileInNewTab","ControllerName", new { target = "_blank" })%>
I canĀ“t vote your answered as is useful, follow dow. Thanks very much !
public FileResult Downloads(string file)
{
string diretorio = Server.MapPath("~/Docs");
var ext = ".pdf";
file = file + extensao;
var arquivo = Path.Combine(diretorio, file);
var contentType = "application/pdf";
using (var client = new WebClient())
{
var buffer = client.DownloadData(arquivo);
return File(buffer, contentType);
}
}
In the file picker Windows 8 sample a file is saved like this:
CachedFileManager.DeferUpdates(file);
await FileIO.WriteTextAsync(file, stringContent);
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
I'm serialising an object as XML so doing it slightly differently:
// CachedFileManager.DeferUpdates(file);
var ras = await file.OpenAsync(FileAccessMode.ReadWrite);
var outStream = ras.GetOutputStreamAt(0);
var serializer = new XMLSerializer();
serializer.Write(myObject, outStream);
// FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
It works with or without the CachedFileManager (commented out above).
So, should I include the CachedFileManager and if I do use it am I saving the file in the right way.
This code works and saves the file fine, but I don't like including code that I don't understand.
Yes, this code will work without CachedFileManager. But, when you use CachedFileManager, you inform the file provider that the file is in process of change. If your file is located on SkyDrive it is faster to create a file and upload it at once instead of update it multiple times.
You can have the full story there : http://www.jonathanantoine.com/2013/03/25/win8-the-cached-file-updater-contract-or-how-to-make-more-useful-the-file-save-picker-contract/
It simply tells the "repository" app to upload the file.