44

I'm using the Javascript FileReader to load an image in the browser:

e = e.originalEvent;
e.dataTransfer.dropEffect = 'copy';
this.documentFile = e.dataTransfer.files[0];

var reader = new FileReader();
reader.onloadend = function () {
    if (reader.result) {
        console.log(reader);
        $('#theImage').attr('src', reader.result);
    }
};
reader.readAsDataURL(this.documentFile);

This works fine. I now want to get the original filename of the image, but I've got no clue how and looking around the internet I can't find anything either?

Does anybody know how I can get the filename through the FileReader? All tips are welcome!

kramer65
  • 50,427
  • 120
  • 308
  • 488
  • I do not think the FileReader has the name. How are you loading the files to start? – epascarello Jun 16 '14 at 13:47
  • @epascarello - I'm loading the file using a drag and drop on a textarea. Using Backbone I then use the event to get the documentFile. I added 3 more lines of code to the original question to show how I do that. Does that give you any ideas? – kramer65 Jun 16 '14 at 13:55
  • Maybe this can help you? http://stackoverflow.com/questions/12546775/get-filename-after-filereader-asynchronously-loaded-a-file – Tarmo Saluste Jun 16 '14 at 14:05

7 Answers7

61

This is prob not the best solution, BUT it worked for me.

var reader = new FileReader();
reader.fileName = file.name // file came from a input file element. file = el.files[0];
reader.onload = function(readerEvt) {
    console.log(readerEvt.target.fileName);
};

Not the best answer, but a working one.

Phreak Nation
  • 860
  • 7
  • 10
  • 3
    This way won't work if you have an array on files, I think it better using the accepted answer on http://stackoverflow.com/questions/12546775/get-filename-after-filereader-asynchronously-loaded-a-file – Dor Cohen Oct 13 '15 at 09:39
  • 2
    As I said, wasn't the best answer, but a working one. Also the question was not about an array, but rather about getting the name of the file. I agree, that answer on the other page would be better suited for an array setup. :) – Phreak Nation Feb 27 '17 at 16:23
7

I just faced the same issue, here's how I fixed it:

Using FileReader

 const reader = new FileReader();
 reader.readAsDataURL(event.target.files[0]); // event is from the HTML input
 console.log(event.target.files[0].name);
Dharman
  • 30,962
  • 25
  • 85
  • 135
4

The selected answer will work, but I personally prefer to prevent assigning unknown properties to existing objects.

What I do is using the built-in Map object to store connections between FileReader and its File. It works great, because Map allows the key to be anything, even an object.

Consider this example with drag&drop on the window, where multiple files can be dropped at the same time:

// We will store our FileReader to File connections here:
const files = new Map();

window.addEventListener('drop', e => {
    e.preventDefault();

    for (const file of e.dataTransfer.files) {
        const reader = new FileReader();

        files.set(reader, file);

        reader.addEventListener('load', e => {
            // Getting the File from our Map by the FileReader reference:
            const file = files.get(e.target);

            console.log(`The contents of ${file.name}:`);
            console.log(e.target.result);

            // We no longer need our File reference:
            files.delete(e.target);
        });

        reader.readAsText(file);
    }
});

window.addEventListener('dragover', e => {
    e.preventDefault();
});

And voilà, we made it without altering our FileReader objects!

Robo Robok
  • 21,132
  • 17
  • 68
  • 126
  • This is a decent solution also in Typescript where adding arbitrary properties on the reader object itself is a nogo. – OlleMattsson Jan 12 '23 at 14:31
1

I got the filename and filesize through the FileReader this way

First of all, the reader is a javascript FILE API specification that is so useful to read files from disc.

In your example the file is readed by readAsDataURL.

reader.readAsDataURL(this.documentFile);
var name = this.documentFile.name;
var size = this.documentFile.size;

I tried on my site where use this.files[0] instead and worked fine to catch the name and the size with jQuery into an input element.

 reader.readAsDataURL(this.files[0]);
 $("#nombre").val(this.files[0].name);
 $("#tamano").val(this.files[0].size);
JWBG
  • 1,286
  • 1
  • 14
  • 20
0

I tried the solution of @Robo Robok but was unable to get this to work in my Angular Application. With this as inspiration I came up with the following and wonder if this is a correct approach. Me, I'm a bit skeptic because each upload gets there own FileReader

    export class ImageFileUpload {
      imageData: any;
      imageName!: string;
      fileReader!: FileReader;
    }

  selectedFiles!: FileList | null;
  previews: Array<ImageFileUpload> = [];

uploadRenewals(event: any) { // event of html 
    const target = event.target as HTMLInputElement;
    this.selectedFiles = target.files;
   
    if (this.selectedFiles) {
      const numberOfFiles = this.selectedFiles.length;
      for (let i = 0; i < numberOfFiles; i++) {
        const currentSelectedFile = this.selectedFiles[i];

        const newImageFile = new ImageFileUpload();
        newImageFile.imageName = currentSelectedFile.name;
        newImageFile.fileReader = new FileReader();
       
        newImageFile.fileReader.onload = (e: any) => {
          newImageFile.imageData = e.target.result;
        };

        newImageFile.fileReader.readAsDataURL(currentSelectedFile);

        this.previews.push(newImageFile);
      }
    }

  }
}

HTML Page

<input #fileInput (change)="uploadRenewals($event)" multiple type="file">

  <div class="slider">
    <div *ngFor="let preview of previews; let idx = index">
      <img [src]="preview.imageData" [alt]="preview.imageName">
    </div>    
  </div>
Leroy Meijer
  • 1,169
  • 17
  • 40
0

One other way is to modify the FileReader() object instance with your own desired property. Adding a key like reader.myOwnFileName gets you access to that in the onload callback.

const reader = new FileReader();

reader.onload = function() {

    console.log("Loaded file '" + reader.myOwnFileName + "' contents: ");
    console.log(reader.result); // output file contents of chosen file.

};

reader.readAsText(this.files[0]); // use readAsText(), readAsDataURL() or other method. 

// make your own key on the object instance:
reader.myOwnFileName = this.files[0].name;
andiOak
  • 356
  • 3
  • 9
-1

If you want the filename to a variable:

var filename;
var reader = new FileReader();
reader.onloadend = function () {
    if (reader.result) {
        console.log(reader);
        $('#theImage').attr('src', reader.result);
        filename = reader.result;
    }
};
reader.readAsDataURL(this.documentFile);

If you want it to run in a function:

var reader = new FileReader();
reader.onloadend = function () {
    if (reader.result) {
        console.log(reader);
        $('#theImage').attr('src', reader.result);
        myfunctionafter(reader.result);
    }
};
reader.readAsDataURL(this.documentFile);

If you want to get the info out inside another function:

var reader = new FileReader();
var filename = reader.onloadend = function () {
    if (reader.result) {
        console.log(reader);
        $('#theImage').attr('src', reader.result);
        return reader.result;
    }
};
reader.readAsDataURL(this.documentFile);

There might be a problem when your reader.onloadend might finish before the function you are running it from. Then you should do two functions and trigger the myfunctionafter(reader.result); from inside

Or you could simply get the src after

var filename = $('#theImage').attr('src');
Tarmo Saluste
  • 585
  • 6
  • 18
  • 3
    Unfortunately, an `alert(reader.result);` results in the following: `data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgG etc etc.`. So that is not the filename, but the base64 encoded source of the file. Any idea how I could get the filename of the file instead? – kramer65 Jun 16 '14 at 14:00