Working With the File API in HTML5

Introduction

 
In HTML5 we have to communicate with local files by the use of the file API. The File API can be used to create a concise viewing of images, it helps with sending to the server. It provides access by an application to save a file with reference but the user is offline.
 
Here we have to use the client-side logic to verify and upload a file that matches its file extension or restricts the size of an upload.
 
The are several interfaces for accessing the local filesystem.
  • File: An individual file; provides read-only information such as name, file size, mimetype, and a reference to the filehandle.
  • Filelist: An array-like sequence of Fileobjects. (Think <input type="file" multiple> or dragging a directory of files from the desktop).
  • Blob: Allows for slicing a file into byte ranges.
The file reader interface can be used to asynchronously read a file through the familiar JavaScript event handling. It is possible to monitor the progress of a read, catch errors, and determine when a load is complete.
 

Selecting files

 
The first thing to do is to check that the browser fully supports the File API.
  1. // Check for the various File API support.  
  2. if (window.File && window.FileReader && window.FileList && window.Blob) {  
  3. // Great success! All the File APIs are supported.  
  4. } else {  
  5. alert('The File APIs are not fully supported in this browser.');  
  6. }  
Using form input for selecting
 
The most straightforward way to load a file is to use a standard <input type="file"> element. JavaScript returns the list of selected File objects as a filelist.
  1. <input type="file" id="files" name="files[]" multiple />  
  2. <output id="list"></output>  
  3. <script>  
  4.     function handleFileSelect(evt) {  
  5.         var files = evt.target.files; // FileList object  
  6.         // files is a FileList of File objects. List some properties.  
  7.         var output = [];  
  8.         for (var i = 0, f; f = files[i]; i++) {  
  9.             output.push('  
  10.     <li>  
  11.         <strong>', f.name, '</strong> (', f.type || 'n/a', ') - ',  
  12.                   f.size, ' bytes, last modified: ',  
  13.                   f.lastModifiedDate.toLocaleDateString(), '  
  14.     </li>');  
  15.        }  
  16.         document.getElementById('list').innerHTML = '  
  17.     <ul>' + output.join('') + '</ul>';  
  18.     }  
  19.     document.getElementById('files').addEventListener('change', handleFileSelect, false);    
  20. </script>  
Example: Using form input for selecting file and load a file. Uses the multiple attribute to allow selecting several files at once.
 
 

Reading files

 
After getting a file reference, instantiate a filereader object to read its contents into memory. When the load finishes, the reader is onload event is fired and its result attribute can be used to access the file data.
 
FileReader includes four options for reading a file.
  • FileReader.readAsBinaryString(Blob|File) - In this property will contain the file/blob's data as a binary string. 
  • FileReader.readAsText(Blob|File, opt_encoding) - Thisproperty will contain the file/blob's data as a text string.
  • FileReader.readAsDataURL(Blob|File) - The result property will contain the file/blob's data encoded as a data url.
  • FileReader.readAsArrayBuffer(Blob|File) -The result property will contain the file/blob's data as arraybuffer object.
Example: The given example filters out images from the user's selection, call reader.readAsDATAURL() on the file, and renders a thumbnail by setting the src attribute to a data URL.
 
Code:
  1. <style>  
  2.   .thumb {  
  3.     height: 75px;  
  4.     border: 1px solid #000;  
  5.     margin: 10px 5px 0 0;  
  6.   }  
  7. </style>  
  8. <input type="file" id="files" name="files[]" multiple />  
  9. <output id="list"></output>  
  10. <script>  
  11.     function handleFileSelect(evt) {  
  12.         var files = evt.target.files; // FileList object  
  13.         // Loop through the FileList and render image files as thumbnails.  
  14.         for (var i = 0, f; f = files[i]; i++) {  
  15.             // Only process image files.  
  16.             if (!f.type.match('image.*')) {  
  17.                 continue;  
  18.             }  
  19.             var reader = new FileReader();  
  20.             // Closure to capture the file information.  
  21.             reader.onload = (function (theFile) {  
  22.                 return function (e) {  
  23.                     // Render thumbnail.  
  24.                     var span = document.createElement('span');  
  25.                     span.innerHTML = ['  
  26.     <img class="thumb" src="', e.target.result,  
  27.                             '" title="', theFile.name, '"/>'].join('');  
  28.                     document.getElementById('list').insertBefore(span, null);  
  29.                 };  
  30.             })(f);  
  31.             // Read in the image file as a data URL.  
  32.             reader.readAsDataURL(f);  
  33.         }  
  34.     }  
  35.     document.getElementById('files').addEventListener('change', handleFileSelect, false);  
  36. </script>  
Example: Reading files.
 
 
In this example, we have to read a directory of images.
 

Slicing a file

 
In some cases reading the entire file into memory is not the best option.
 
For example
 
We wanted to write an async file uploader. One way to speed up the upload would be to read and send the file in separate byte-range chunks. The server component would then be responsible for reconstructing the file content in the correct order.
 
The file interface supports a slice method to support this use case. The method takes a starting byte as its first argument, ending byte as its second, and an optional content-type string as a third. The semantics of this method changed recently.
 
Code
  1. if (file.webkitSlice)   
  2. {  
  3.   var blob = file.webkitSlice(startingByte, endindByte);  
  4. } else if (file.mozSlice)   
  5. {  
  6.   var blob = file.mozSlice(startingByte, endindByte);  
  7. }  
  8. reader.readAsBinaryString(blob);  
ForExample
 
The following example, that reads chunks of a file, uses the onloadend and checks the evt.target.readyState instead of using the onload event.
 
Code
  1. <style>  
  2.   #byte_content {  
  3.     margin: 5px 0;  
  4.     max-height: 100px;  
  5.     overflow-y: auto;  
  6.     overflow-x: hidden;  
  7.   }  
  8.   #byte_range { margin-top: 5px; }  
  9. </style>  
  10. <input type="file" id="files" name="file" /> Read bytes:  
  11.   
  12. <span class="readBytesButtons">  
  13.     <button data-startbyte="0" data-endbyte="4">1-5</button>  
  14.     <button data-startbyte="5" data-endbyte="14">6-15</button>  
  15.     <button data-startbyte="6" data-endbyte="7">7-8</button>  
  16.     <button>entire file</button>  
  17. </span>  
  18. <div id="byte_range"></div>  
  19. <div id="byte_content"></div>  
  20. <script>  
  21.     function readBlob(opt_startByte, opt_stopByte) {  
  22.         var files = document.getElementById('files').files;  
  23.         if (!files.length) {  
  24.             alert('Please select a file!');  
  25.             return;  
  26.         }  
  27.         var file = files[0];  
  28.         var start = parseInt(opt_startByte) || 0;  
  29.         var stop = parseInt(opt_stopByte) || file.size - 1;  
  30.         var reader = new FileReader();  
  31.         // If we use onloadend, we need to check the readyState.  
  32.         reader.onloadend = function (evt) {  
  33.             if (evt.target.readyState == FileReader.DONE) { // DONE == 2  
  34.                 document.getElementById('byte_content').textContent = evt.target.result;  
  35.                 document.getElementById('byte_range').textContent =  
  36.             ['Read bytes: ', start + 1, ' - ', stop + 1,  
  37.              ' of ', file.size, ' byte file'].join('');  
  38.             }  
  39.         };  
  40.         if (file.webkitSlice) {  
  41.             var blob = file.webkitSlice(start, stop + 1);  
  42.         } else if (file.mozSlice) {  
  43.             var blob = file.mozSlice(start, stop + 1);  
  44.         }  
  45.         reader.readAsBinaryString(blob);  
  46.     }  
  47.     document.querySelector('.readBytesButtons').addEventListener('click'function (evt) {  
  48.         if (evt.target.tagName.toLowerCase() == 'button') {  
  49.             var startByte = evt.target.getAttribute('data-startbyte');  
  50.             var endByte = evt.target.getAttribute('data-endbyte');  
  51.             readBlob(startByte, endByte);        }  
  52. }, false);  
  53. </script>  
Example: Here we have to browse a file and read it in slices.
 
 
Read bytes: 1 - 5 of 1969 byte file.
 

Monitoring the progress of a read

 
One of the nice things that we get for free when using async event handling is the ability to monitor the progress of the file read; useful for large files, catching errors, and figuring out when a read is complete.
 
The onloadstart and onprogress events can be used to monitor the progress of a read.
 
For Example, The example displaying a progress bar to monitor the status of a read. To see the progress indicator in action, try a large file or one from a remote drive.
 
Code
  1. <style>  
  2. #progress_bar {  
  3.     margin: 10px 0;  
  4.     padding: 3px;  
  5.     border: 1px solid #000;  
  6.     font-size: 14px;  
  7.     clear: both;  
  8.     opacity: 0;  
  9.     -moz-transition: opacity 1s linear;  
  10.     -o-transition: opacity 1s linear;  
  11.     -webkit-transition: opacity 1s linear;  
  12.   }  
  13.   #progress_bar.loading {  
  14.     opacity: 1.0;  
  15.   }  
  16.   #progress_bar .percent {  
  17.     background-color: #99ccff;  
  18.     height: auto;  
  19.     width: 0;  
  20.   }  
  21. </style>  
  22. <input type="file" id="files" name="file" />  
  23. <button onclick="abortRead();">Cancel read</button>  
  24. <div id="progress_bar">  
  25.     <div class="percent">0%</div>  
  26. </div>  
  27. <script>  
  28.     var reader;  
  29.     var progress = document.querySelector('.percent');  
  30.   function abortRead() {  
  31.         reader.abort();  
  32.     }  
  33.     function errorHandler(evt) {  
  34.         switch (evt.target.error.code) {  
  35.             case evt.target.error.NOT_FOUND_ERR:  
  36.                 alert('File Not Found!');  
  37.                 break;  
  38.             case evt.target.error.NOT_READABLE_ERR:  
  39.                 alert('File is not readable');  
  40.                 break;  
  41.             case evt.target.error.ABORT_ERR:  
  42.                 break// noop  
  43.             default:  
  44.                 alert('An error occurred reading this file.');  
  45.         };  
  46.     }  
  47.     function updateProgress(evt) {  
  48.   
  49.         if (evt.lengthComputable) {  
  50.             var percentLoaded = Math.round((evt.loaded / evt.total) * 100);  
  51.             // Increase the progress bar length.  
  52.             if (percentLoaded < 100) {  
  53.                 progress.style.width = percentLoaded + '%';  
  54.                 progress.textContent = percentLoaded + '%';  
  55.             }  
  56.         }  
  57.     }  
  58.     function handleFileSelect(evt) {  
  59.         // Reset progress indicator on new file selection.  
  60.         progress.style.width = '0%';  
  61.         progress.textContent = '0%';    
  62.         reader = new FileReader();  
  63.         reader.onerror = errorHandler;  
  64.         reader.onprogress = updateProgress;  
  65.         reader.onabort = function (e) {  
  66.             alert('File read cancelled');  
  67.         };  
  68.         reader.onloadstart = function (e) {  
  69.             document.getElementById('progress_bar').className = 'loading';  
  70.         };  
  71.         reader.onload = function (e) {  
  72.             // Ensure that the progress bar displays 100% at the end.  
  73.             progress.style.width = '100%';  
  74.             progress.textContent = '100%';  
  75.             setTimeout("document.getElementById('progress_bar').className='';", 2000);  
  76.         }  
  77.         // Read in the image file as a binary string.  
  78.         reader.readAsBinaryString(evt.target.files[0]);  
  79.     }  
  80.     document.getElementById('files').addEventListener('change', handleFileSelect, false);  
  81. </script>   
Example
 
Monitoring the progress of a read. We have to browse a file and read it below.