This article mainly introduces how JavaScriptFileAPI implements file upload preview. FileAPI greatly facilitates file upload and other operations on the Web end. This article will introduce the overview of FileAPI and use two instances to demonstrate FileAPI applications, for more information, see
I. Overview
In the past, accessing local files is a headache for browser-based applications. Despite the continuous development of Web 2.0 application technology, JavaScript is playing an increasingly important role, but for security reasons, JavaScript has been unable to access local files. Therefore, in order to implement functions such as drag and drop and upload local files in a browser, we have to turn to the various technologies provided by a specific browser. For example, for IE, we need to use ActiveX controls to obtain access to local files. For Firefox, we also need to use plug-ins for development. Because different browsers have different technical implementations, in order to allow programs to support multiple browsers, our programs become very complex and difficult to maintain. But now, all this has been completely changed because of the emergence of File APIs.
File API is a draft submitted by Mozilla to W3C. It aims to introduce a set of standard JavaScript APIs. Its basic function is to use JavaScript to operate on local files. For security reasons, this API only provides limited access to local files. With it, we can easily use pure JavaScript to read and upload local files. Currently, FireFox 3.6 is the first browser to support this function. In addition, the latest version of Google Chrome and Safari also have corresponding support. The File API is expected to become part of the future HTML 5 specification currently being developed by W3C.
Ii. File API Overview
The File API consists of a set of JavaScript objects and events. Grant operations to developers inFile Selection control. Figure 1 shows the combination of all the JavaScript codes of the File API.
FileList contains a set of File objects. Normally, the FileList object can be (. Blob objects represent a group of original binary streams that the browser can read. In the Blob object, the attribute size indicates the stream size. The function slice () can split a long Blob Object into small pieces. The File object inherits from the Blob Object and adds File-related attributes to the Blob Object. The attribute name indicates the file name. This name removes the file path information and only keeps the file name. The property type indicates the MIME type of the file. The urn attribute indicates the URN information of the file. To complete File read operations, a FileReader object instance is associated with a File or Blob Object, and provides three different File read functions and six events.
Specific content of the file reading function:
ReadAsBinaryString ()Reads the file content and returns a binary string. Each byte in the file is represented as an integer in the range [0 .. 255. The function accepts a File object as a parameter.
ReadAsText ()Reads the file content and returns a string of text that represents the file content. The function accepts a File object and text encoding name as the parameter.
ReadAsDataURLReads the file content and returns a data: URL. DataURL is defined by RFC2397.
File Read event details:
Event name Event Description
OnloadstartTriggered when File Reading starts.
SSTimed trigger when reading is in progress. The event parameter contains the total amount of data read.
AbortTriggered when the read is aborted.
ErrorTriggered when a read error occurs.
LoadTriggered when the read is successful.
LoadendWhen the read is complete, both success and failure are triggered.
Iii. Simple Example of File API
Next we will use a simple example to demonstrate the basic usage of the File API. This example contains two code files. index.html contains the HTML code on the Web Side and JavaScript code for processing uploads. upload. jsp contains the code for receiving uploaded files on the server side. See sourcecode.zip in the attachment. In this example, we will display a traditional form with a File selection field. When you select a File and click Submit, we use the File API to read the File content and use the XMLHttpRequest object to upload the File to the server in Ajax mode. Figure 2 shows the running demo.
The code is gradually displayed. Listing 1 shows the HTML part of the code.
The HTML section of the sample code in Listing 1
File API Demo
Progessing (in Bytes ):/
We can see that we use a common
Label to contain a traditional Element. InThere is also a submit element. InIn addition, some elements are used to indicate the read and total data volume.The action property points to a JavaScript function uploadAndSubmit (). This function completes the process of reading and uploading files. For the function code, see List 2.
List 2 JavaScript Functions used to read and upload files
Function uploadAndSubmit () {var form = document. forms ["demoForm"]; if (form ["file"]. files. length> 0) {// findLabel var file = form ["file"]. files [0]; // try sending var reader = new FileReader (); reader. onloadstart = function () {// This event triggers the console at the start of reading. log ("onloadstart"); document. getElementById ("bytesTotal "). textContent = file. size;} reader. onprogress = function (p) {// This event triggers the console periodically during reading. log ("onprogress"); document. getElementById ("bytesRead "). textContent = p. loaded;} reader. onload = function () {// This Events trigger the console after the read is successful. log ("load complete");} reader. onloadend = function () {// This event triggers if (reader. error) {console. log (reader. error);} else {document. getElementById ("bytesRead "). textContent = file. size; // construct the XMLHttpRequest object and send the file Binary data var xhr = new XMLHttpRequest (); xhr. open (/* method */"POST",/* target url */"upload. jsp? FileName = "+ file. name/*, async, default to true */); xhr. overrideMimeType ("application/octet-stream"); xhr. sendAsBinary (reader. result); xhr. onreadystatechange = function () {if (xhr. readyState = 4) {if (xhr. status = 200) {console. log ("upload complete"); console. log ("response:" + xhr. responseText) ;}}}} reader. readAsBinaryString (file);} else {alert ("Please choose a file. ");}}
In this function, we first findElementAnd findElement. For exampleThe element does not contain any files, indicating that the user has not selected any files and an error is returned.
Listing 3 foundElement
var form = document.forms["demoForm"]; if (form["file"].files.length > 0) { var file = form["file"].files[0]; … … } else { alert ("Please choose a file."); }
Here, the object type returned from form ["file"]. files is the mentioned FileList. Take the first element from it. Then, we construct the FileReader object:
Var reader = new FileReader ();
When the onloadstart event is triggered, the fill page shows the elements that read the total amount of data. See Listing 4.
Listing 4 onloadstart events
Reader. onloadstart = function () {console. log ("onloadstart"); document. getElementById ("bytesTotal "). textContent = file. size;} when the onprogress event is triggered, the elements of the data volume read on the page are updated. See list 5
Listing 5 onprogress events
reader.onprogress = function(p) { console.log("onloadstart"); document.getElementById("bytesRead").textContent = p.loaded; }
In the final onloadend event, if there is no error, we will read the file content and upload it through XMLHttpRequest.
Listing 6 onloadend events
Reader. onloadend = function () {if (reader. error) {console. log (reader. error);} else {// construct the XMLHttpRequest object and send the file Binary data var xhr = new XMLHttpRequest (); xhr. open (/* method */"POST",/* target url */"upload. jsp? FileName = "+ file. name/*, async, default to true */); xhr. overrideMimeType ("application/octet-stream"); xhr. sendAsBinary (reader. result );... ... }}
According to the File API specification, we can also split the onloadend event processing into event error and event load processing.
In this example, a JSP is used in the background to process the upload. The JSP code is shown in listing 7.
Listing 7 process uploaded JSP code
<% @ Page import = "java. io. * "%> <% BufferedInputStream fileIn = new BufferedInputStream (request. getInputStream (); String fn = request. getParameter ("fileName"); byte [] buf = new byte [1024]; // receives the File and uploads it to d: \ file File = new File ("d: /"+ fn); BufferedOutputStream fileOut = new BufferedOutputStream (new FileOutputStream (file); while (true) {// read data int bytesIn = fileIn. read (buf, 0, 1024); System. out. println (bytesIn); if (bytesIn =-1) {break;} else {fileOut. write (buf, 0, bytesIn) ;}} fileOut. flush (); fileOut. close (); out. print (file. getAbsolutePath (); %>
In this JSP code, we accept the file name and binary data from the POST request. Write binary data to the "D: \" Path of the server. And return the complete path of the file. The above code can be debugged through the latest Firefox 3.6.
4. Use drag and drop to upload files
We have introduced how to use the HTML5 File API to read local File content and upload it to the server. This method can meet the needs of most users. One disadvantage is that you can only click the "Browse" button to add files one by one. If you need to upload files in batches, the user experience will be unfriendly. In desktop applications, users can easily upload files by dragging the mouse. Drag and Drop is always a weakness of Web applications. Generally, browsers do not support drag and drop operations. Although Web programmers can drag and drop through events such as mouse mouseenter, mouseover, and mouseout, this method can only limit the drag scope to the browser. The good news is that HTML5 not only supports File APIs, but also supports drag and drop operations. Firefox 3.5 has already supported File APIs and drag and drop operations. Next, we will briefly introduce the use of drag and drop, and then use an example to illustrate how to upload a file by dragging and dropping.
1. Drag and Drop
Drag generally involves two objects: Drag Source and drag target.
Drag Source: In the HTML5 draft, if an object can be dragged as the source, you need to set the draggable attribute to true to identify the object as the Drag Source. Then listen to the dragstart event of the source object and set DataTransfer In the event processing function. You can set the drag data type and value in DataTransfer. For example, if it is a plain text value, you can set the type to "text/plain", and the url will set the type to "text/uri-list ". In this way, the target object can select data based on the expected type.
Drag target:A drag-and-drop target must listen for three events.
Dragenter:The target object determines whether to receive the drag by responding to this event. If you receive the message, you need to cancel the event and resume the propagation at the stop time.
Dragover:Respond to this event to display the drag and drop prompts.
Drop:The target object processes the drag data by responding to this event. In the following example, we will obtain the DataTransfer object in the drop event handler and retrieve the file to be uploaded.
This article mainly introduces the File API and does not explain this part in detail. For more information, see the HTML5 draft (see references ).
2. Drag and Drop an upload file instance
The following is a specific example to illustrate how to upload documents using the drag and drop and File APIs. Because it interacts directly with the desktop, we do not need to process the drag-and-drop source. We can directly obtain data from the DataTransfer object in the target object.
First, we need to create a target container to receive drag events and add a p element. Then, a list is used to display the thumbnails, progress bars, and file names of the uploaded files. See the HTML code in listing 8 and figure 3. For detailed code, see the dnd.html file in the attachment.
Listing 8 dragging the HTML code of the target
Drag and drop files here to upload.
After the drag and drop target is created, we need to listen to its corresponding events dragenter, dragover and drop. In the dragenter event processing function, we simply clear the file list and then cancel the propagation of the dragenter event, which means we receive the event. It is more appropriate to determine whether the data in DataTransfer is a file. Here we assume that all the drag and drop sources are files. In the dragover event, we cancel the event and use the default drag-and-drop display effect. In the drop event, we registered the handleDrop event handler to obtain the file information and upload the file. Listing 9 shows the event processing functions.
Listing 9 setting event processing functions
Function addDNDListeners () {var container = document. getElementById ("container"); var fileList = document. getElementById ("fileList"); // The container is triggered when the object is dragged to the target object. addEventListener ("dragenter", function (event) {fileList. innerHTML = ''; event. stopPropagation (); event. preventDefault () ;}, false); // triggers container when you drag the target object. addEventListener ("dragover", function (event) {event. stopPropagation (); event. preventDefault () ;}, false); // triggers container when the drag ends. addEventListener ("drop", handleDrop, false);} window. addEventListener ("load", addDNDListeners, false );
Handle drop events
When the drag ends, you can open the mouse to trigger the drop event. In the drop event, we can get the files data through the DataTransfer object of the event parameter, and get the information of each file by traversing the files array. Create HTML elements for each file to display thumbnails, progress bars, and file names. The getAsDataURL of the File object can return the File content as a URL, which can be used to display thumbnails for image files. It should be noted that, in the drop event processing function, the continuation propagation of the event and the default processing function should be canceled to end the processing of the drop event. Listing 10 shows the processing code for the drop event.
Listing 10 Handling of drop events
Function handleDrop (event) {// obtain the list of dragged files var files = event. dataTransfer. files; event. stopPropagation (); event. preventDefault (); var fileList = document. getElementById ("fileList"); // displays the file thumbnails, file names, and upload progress. the uploaded file is for (var I = 0; I <files. length; I ++) {var file = files [I]; var li = document. createElement ('lil'); var progressbar = document. createElement ('P'); var img = document. createElement ('img '); var name = document. createElement ('span '); progressbar. className = "progressBar"; img. src = files [I]. getAsDataURL (); img. width = 32; img. height = 32; name. innerHTML = file. name; li. appendChild (img); li. appendChild (name); li. appendChild (progressbar); fileList. appendChild (li); uploadFile (file, progressbar )}}
Upload files
We can use the sendAsBinary method of the XMLHttpRequest object to upload files. By listening to the upload progress, load, and error events, we can monitor the File upload progress, whether the file upload is completed successfully, or whether an error occurs. In the progress event processing function, we can determine the position of the progress bar by calculating the uploaded proportion. See listing 11. Figure 4 shows the object to be uploaded.
Listing 11 uploading files
Function uploadFile (file, progressbar) {var xhr = new XMLHttpRequest (); var upload = xhr. upload; var p = document. createElement ('P'); p. textContent = "0%"; progressbar. appendChild (p); upload. progressbar = progressbar; // sets the upload function for file upload. addEventListener ("progress", uploadProgress, false); upload. addEventListener ("load", uploadSucceed, false); upload. addEventListener ("error", uploadError, fa Lse); // upload the file xhr. open ("POST", "upload. jsp? FileName = "+ file. name); xhr. overrideMimeType ("application/octet-stream"); xhr. sendAsBinary (file. getAsBinary ();} function uploadProgress (event) {if (event. lengthComputable) {// converts progress to percentage var percentage = Math. round (event. loaded * 100)/event. total); console. log ("percentage:" + percentage); if (percentage <100) {event.tar get. progressbar. firstChild. style. width = (percentage * 2) + "px"; event.tar get. progressbar. firstChild. textContent = percentage + "%" ;}} function uploadSucceed (event) {event.tar get. progressbar. firstChild. style. width = "200px"; event.tar get. progressbar. firstChild. textContent = "100%";} function uploadError (error) {alert ("error:" + error );}
By explaining the File API specifications and two examples of using them, this article gives you a full picture of the JavaScript File API that is an important part of HTML5 in the future. Using it, combined with other HTML5 new features, such as Drag & Drop, we can use the pure JavaScript solution to provide users with better user experience for Web applications. At the same time, this consistent solution also avoids the huge cost of cross-browser support. I believe that the emergence and wide application of File APIs will be the trend of Web 2.0 applications in the future.