File upload and download Refers to the process of uploading local files such as pictures, videos, and audio files to the server for other users to browse or download.
Form upload
The main characteristics of this approach are:
- The most primitive method, now the browser basically support;
- Method must be the size of the GET request because it is an upload file
POST
; - Input must be set
name
Attribute to identify form data after submission to the server. Only form elements with the name attribute can pass their values when submitting the form. - Accept: Specifies the file type that can be submitted through file upload. This attribute is not set and the file upload type should be verified on the server.
- Multiple: Whether you can select multiple files.
- The encType property specifies how the form data should be encoded before being sent to the server, i.e. in the request header
Content-Type
There are three main types of values,application/x-www-form-urlencoded
,multipart/form-data
,text/plain
. If encType in the form does not specify a value, the form defaults to the first submission, but all that is submitted is a string of file names, with ampersands in multiple name=value key-value pairs. So you need to usemultipart/form-data
,multipart/form-data
Is used to upload binary files in HTML documents; - Styles need to be optimized, usually set
input.style.opacity = 0
To hide the input and design the label to look like a button.
<form method="post" action="xxx" enctype="multipart/form-data">
<div>
<label for="file">Choose file to upload</label>
<input type="file" id="file" name="file" multiple>
</div>
<div>
<button>Submit</button>
</div>
</form>
<script>
const input = document.querySelector('input');
input.style.opacity = 0;
input.addEventListener('change', function(e) {
console.log(e.target.files[0]);
let formData = new FormData();
formData.append("fileName", e.target.files[0]);
console.log(formData);
})
})
</script>
Copy the code
The printed results are as follows:
You can see some information about the file in the print result, but the FormData is printed with an empty {} because it cannot be viewed. You need to use the built-in method, which we’ll explain later.
However, the Form will jump to the page after uploading the file because of the target attribute of the Form. If you want to make users feel like uploading files asynchronously, you can use Framename to specify iframe. If you set the target property of the form to an invisible iframe, the returned data will be accepted by the iframe. Therefore, only the iframe will be refreshed, and the returned result can also be obtained by parsing the text within the iframe.
Ajax upload
- The server provides the interface, sets the corresponding request header, front-end submission
FormData
Form of file data; - Gets the DOM object of the download input box, listening
change
Event to get the contents of the file; - Use the FormData
append
Method to add values,e.target.files
It is aFileList
Instance, an array-like object used to store the files selected by the user; - If xhr.send is of FormData type, encType is automatically set.
- The XMLHttpRequest object provides one
progress
Event, which returns the uploaded size and total size of the file. From these two values, upload progress can be calculated.
<input type="file"> <script> const input = document.querySelector('input'); input.addEventListener('change', function(e) { let fileList = e.target.files; let formdata = new FormData(); // single file formdata.append('file', fileList[0]); / multiple file uploads need to be traversed to add to the fromData object for(let I = 0; i < fileList.length; i++){ formdata.append('f1', fileList[i]); } let xhr = new XMLHttpRequest(); xhr.open("POST","xxxxx"); xhr.onreadystatechange = function () { if(xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); Xhr.upload. onprogress = function(e) {if (e.lengthcomputable) {let percent = math.floor (event.loaded / event.total * 100); } } xhr.send(formdata); }) </script>Copy the code
Drag and drop to upload
- Div. Drop-box defines a drag-and-drop area for files and listens for drag-and-drop events.
- A complete drag-and-upload behavior covers four events:
Dragover, Dragenter, drop, dragLeave
, just focus on the element being draggeddragover
和drop
; - Cancels the default behavior of the DROP event
e.preventDefault()
Otherwise, the browser’s default behavior is to open the file directly; - To bind events to the drag region, mouse over the drag region
dragover
, mouse away from the drag areadragleave
To release the file on the drag areadrop
; - Drag-and-drop data information is stored when dragging and dropping
DataTransfer
In the object; - The remaining steps and
Form
The form upload is consistent.
<script> const dragBox = document.querySelector('drag'); dragBox.addEventListener("dragover",function (e) { e.preventDefault(); }) dragBox.addEventListener("drop", function (e) { e.preventDefault(); const fileList = e.dataTransfer.files; }) </script>Copy the code
Large file upload
The main problem with large file uploads is that a large amount of data has to be uploaded in the same request, resulting in a lengthy process and the need to start all over again after a failure. If we split the request into multiple requests, the time for each request is shortened, and if a request fails, we only need to resend the request. Form upload and iframe upload without refreshing page are actually file upload via form tag. In this way, the entire request is completely handed over to the browser. When uploading a large file, the request may time out and cannot be divided into multiple requests. FromData actually encapsulates a set of request parameters in XHR to simulate form requests, and you can’t avoid large file upload timeouts. So by using coded upload, we can control the content of upload more flexibly.
Based on the above problems, the following requirements need to be realized:
- Support split upload requests (i.e. slices)
- Support breakpoint continuation
- Display upload progress and pause upload
File section
The FIle object is a subclass of the Blob object, which contains an important method, slice, through which we can slice binary files.
- Define the size variable of each shard file as chunkSize.
- Chunks are obtained by FileSize and chunkSize.
- Use the for loop and file.slice() method to fragment the file, numbered 0-n;
- Compare with the uploaded slice list to get all unuploaded slices;
- Push to the requestList.
Here is an example
function slice(file, piece = 1024 * 1024 * 5) { let totalSize = file.size; // let start = 0; // let end = start + piece; // End byte let chunks = [] while (start < totalSize) {// End byte let chunks = [] while (start < totalSize) { So include the slice method let blob = file.slice(start, end); chunks.push(blob) start = end; end = start + piece; } return chunks }Copy the code
Restore section
Breakpoint continuingly
Upload to suspend
The relevant knowledge
In Web development, when we work with files (create, upload, download), we often encounter binary data. All of this can be handled in JavaScript, and binary operations are more efficient. The main ones are FormData, ArrayBuffer, Blob, and File
ArrayBuffer
ArrayBuffer
Is a basic binary object, the basis of everything, a reference to a contiguous memory space of fixed length. You can think of it as a (large) block of memoryArrayBuffer
The point of existence is to write in memory ahead of time as a data source, that is, to pin in some area ahead of time, and the length is fixed for ten thousand years, so when we’re dealing with thisArrayBuffer
Binary data in, for example, 8 -, 16 -, and 32 – bit conversions will not change, and the three conversions share data- We can get through
new ArrayBuffer(length)
To get a contiguous piece of memory that we can’t access directlyArrayBuffer
Bytes inside, which can be passed to as neededTypedArray
View orDataView
Object to interpret the raw buffer. The view really just gives you some kind of read-write interface that you can manipulateArrayBuffer
The view object itself doesn’t store anything. It is a pair of “glasses” through which to interpret storage inArrayBuffer
The byte
There is a constructor:
let buffer = new ArrayBuffer(16); // Create a buffer of 16 bytes and allocate a contiguous memory space of 16 bytesCopy the code
To manipulate an ArrayBuffer, we need to use a “view” object, the generic term being TypedArray:
Uint8Array
Treat each byte in the ArrayBuffer as a single number between 0 and 255 (each byte is 8 bits, so it can only hold so many). This is called”An 8-bit unsigned integer
“Uint16Array
— Treat every 2 bytes as an integer between 0 and 65535. This is called”16 - bit unsigned integer
“Uint32Array
— Treat every 4 bytes as an integer between 0 and 4294967295. This is called”32 - bit unsigned integer
“Float64Array
Treat every 8 bytes as a floating point number between 5.0×10-324 and 1.8×10308
Like:
FormData
FormData is a native HTML5 object that represents an object for FormData. The constructor is:
let formData = new FormData([form]);
Copy the code
We can modify fields in FormData using the following methods:
formData.append(name, value)
— Add has a givenname
和value
Form field offormData.append(name, blob, fileName)
Add a field as if it were<input type="file">
, the third parameterfileName
Set the file name (not the form field name) because it is the name of the file in the user’s file systemformData.delete(name)
— Removes a givenname
The field offormData.get(name)
— Gets with a givenname
The field values of theformData.has(name)
If there exists with a givenname
Is returnedtrue
Otherwise returnfalse
FormData allows you to wrap a Form or a series of fields as an object, simulate a series of Form controls through key-value pairs, and send them Ajax via standard XHR.
This is different from the & concatenation argument, which is encoded as multipart/form-data, and has the same form as sending data using the form submit() method with the form encType attribute set to multipart/form-data. The request header is content-Type: multipart/form-data. A boundary = – WebKitFormBoundaryVXQzCH5gOtjud1Xu WebKitFormBoundary72yvM25iSPYZ4a3F behind for 16 random Base64 encoded string
------WebKitFormBoundary72yvM25iSPYZ4a3F
Copy the code
Blob
Blob
One of the general terms used in computer science:BLOB (binary large object)
Represents a binary large objectMySql/Oracle
There’s one in the databaseBlob
Type for storing binary data- Binary raw data but file-like objects that can be manipulated as file objects
Blob
Object, soBlob
Is binary data with type, so it can be convenientBlob
Used to upload or download files in the browser Blob
Consists of an optional stringtype
(usually MIME type) andblobParts
Composition,blobParts
Can beBlob/BufferSource/String
Type, as follows
The constructor is:
new Blob(blobParts, options);
Copy the code
It has two properties:
size
(read-only) : Represents the size, in bytes, of the data contained in the Blob object.type
(read only) : A string indicating the MIME type of the data contained in the Blob object. If the type is unknown, the value is an empty string
Blobs can easily be used as urls for A and IMG or other tags to display their contents
Blob as a URL
Below is a simulated user click to download automatically
let link = document.createElement('a');
link.download = 'hello.txt';
let blob = new Blob(['Hello, world!'], {type: 'text/plain'});
console.log(blob)
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);
Copy the code
The print result is as follows:
Url.createobjecturl takes a Blob and creates a unique URL for it of the form Blob :
/
. Note that even with the same binary data, every time url.createObjecturl is called, a different Blob URL is obtained. Url.revokeobjecturl (URL) removes references from the internal map and frees memory
let link = document.createElement('a'); link.download = 'hello.txt'; let blob = new Blob(['Hello, world!'], {type: 'text/plain'}); let reader = new FileReader(); reader.readAsDataURL(blob); // Convert Blob to base64 and call onload reader.onload = function() {link.href = reader.result; // data url link.click(); }Copy the code
Blob converts to Base64
- will
Blob
convertbase64
The encoded string can also create a URL - This encoding represents binary data as a string of 0 to 64 ASCII characters, which is very secure and “readable”. What’s more — we can do it in the”
data-url
“To use this encoding. - “
data-url
Is in the form ofdata:[<mediatype>][;base64],<data>
. We can use this url anywhere, just as we would use a “regular” URL - However, if the picture is large and the color level of the picture is relatively rich, it is not suitable to use this method, because
Base64
It turns three bytes into four bytes, so the encoded text is about a third larger than the original text and it slows down the load speed.
Like:
<img src="data:image/png; base64,R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mA biwWtuf0uxFAgA7">Copy the code
We use a built-in FileReader object to convert the Blob to Base64. It can read data in a Blob in a variety of formats
Here’s how to download blobs in Base64:
let link = document.createElement('a'); link.download = 'hello.txt'; let blob = new Blob(['Hello, world!'], {type: 'text/plain'}); let reader = new FileReader(); reader.readAsDataURL(blob); // Convert Blob to base64 and call onload reader.onload = function() {link.href = reader.result; // data url link.click(); }Copy the code
Image is converted to bloB
- We can create an image, a portion of an image, or even a screenshot of a page
Blob
. This makes it easy to upload to other places - Image manipulation is through
canvas
Element - use
canvas.drawImage
在canvas
Draw image on - call
canvas
methods.toBlob(callback, format, quality)
To create aBlob
And run with it after it is createdcallback
.
// Get any image let img = document.querySelector('img'); <canvas> let canvas = document.createElement('canvas'); canvas.width = img.clientWidth; canvas.height = img.clientHeight; let context = canvas.getContext('2d'); Context. DrawImage (img, 0, 0); Function (blob) {// We context.rotate() and do a lot of other things on the canvas. Let link = document.createElement('a'); link.download = 'example.png'; link.href = URL.createObjectURL(blob); link.click(); RevokeObjectURL (link.href); // Delete the internal blob reference so that the browser can clear it from memory. }, 'image/png');Copy the code
Blobs are converted to arrayBuffers
// Get fileReader from blob let fileReader = new fileReader (); fileReader.readAsArrayBuffer(blob); fileReader.onload = function(event) { let arrayBuffer = fileReader.result; };Copy the code
File
File
The name si means “document” and, generally speaking, it means we usefile
controls<input type="file">
Select theFileList
Object, or using a drag-and-drop operationDataTransfer
object- Here,
File
Object is also binary object, based onBlob
It also extends file system-related functionalityFile
- Inherited from
Blob
Object,Blob
Object properties and methods, and provides the name, lastModifiedDate, size, type and other basic metadata
There are two ways to get it
The first, similar to Blob, has a constructor:
new File(fileParts, fileName, [options])
Copy the code
Second, and more commonly, we get the file from or drag and drop or some other browser interface. In this case, file will get its this information from the operating system (OS)
<input type="file" onchange="showFile(this)"> <script> function showFile(input) { let file = input.files[0]; alert(`File name: ${file.name}`); // 115b.... -zoom-1.png alert(`Last modified: ${file.lastModified}`); // 1624268059721 } </script>Copy the code
FileReader
FileReader
Is an object whose sole purpose is to beBlob
(also fromFile
) object to read data- It uses events to pass data, since reading data from disk can be time-consuming
There is a constructor:
let reader = new FileReader(); // No argumentsCopy the code
Main method (to convert bloBs to other formats) :
readAsArrayBuffer(blob)
Read data in binary formatArrayBuffer
readAsText(blob, [encoding])
— Reads data into the given encoding (defaultutf-8
Encoded) text stringreadAsDataURL(blob)
— Reads binary data and encodes it asbase64
的data url
abort()
— Cancel operation
FileReader reads not only files, but also any Blob object
The choice of the read* method depends on which format we prefer and how we use the data
readAsArrayBuffer
— For binary files, performing low-level binary operations. For things like slicing (slicing
) and so on,File
Is inherited fromBlob
So we can call them directly without reading themreadAsText
— For text files, when we want to get stringsreadAsDataURL
When we want to use this data in SRC and use it for img or other tags. As we did in theBlob
There is an alternative to reading files for this, as described in chapter 1:URL.createObjectURL(file)
During reading, the following events occur:
loadstart
— Start loadingprogress
— occurs during readingload
— Read complete, no errorabort
— Call abort()error
– appear errorloadend
The read completes, whether it succeeds or fails
After the read is complete, we can access the read results in the following ways:
reader.result
Is the result (if successful)reader.error
Yes error (if failed)
The most widely used events are undoubtedly Load and error
<input type="file" onchange="readFile(this)">
<script>
function readFile(input) {
let file = input.files[0];
let reader = new FileReader();
reader.readAsText(file);
reader.onload = function() {
console.log(reader.result);
};
reader.onerror = function() {
console.log(reader.error);
}
}
</script>
Copy the code
Use a picture from the Internet to illustrate the relationship between them
Related information:
zh.javascript.info/formdata
Useful. Javascript. The info/arraybuffer…
zh.javascript.info/blob
zh.javascript.info/file
Learn the whole process of file uploading
Front-end large file upload
Bytedance Interviewer: Please implement a large file upload and resumable breakpoint
File upload. It’s enough to understand these 8 scenarios