Thứ năm, 23/01/2020 | 00:00 GMT+7

Đọc và xử lý tệp với API JavaScript FileReader


Đọc, viết và phân tích file là một thành phần thiết yếu của phát triển phần mềm. Vì lý do bảo mật, trong JavaScript, ta không thể truy cập trực tiếp vào file của user . Nếu ta có thứ gì đó giống như fs trong Node.js, ta có thể lấy cắp tài liệu từ user !

Đầu tiên, để lấy file từ user , ta cần sử dụng phần tử đầu vào:

<input id="my-input" type="file" onChange="handleFileChange">

Đoạn mã nhỏ này sẽ cho phép user của ta tải file lên từ máy của cô ấy. Hàm handleFileChange mà ta sẽ tạo sẽ nhận một số thông tin về các file đã tải lên, nhưng để có thể thao tác chúng, ta cần sử dụng API FileReader .

Tải lên file của bạn

Đây là đoạn mã để tải file lên bằng biểu mẫu HTML.

<form enctype="multipart/form-data" action="/upload" method="post">
  <input id="file-input" type="file" />
</form>

Chỉ có rất nhiều thứ bạn có thể nhận được từ một POST biểu mẫu HTML. Nếu bạn muốn sử dụng JavaScript để thực hiện các yêu cầu của bạn , bạn có thể làm như sau:

let file = document.getElementById("file-input").files[0];
let formData = new FormData();

formData.append("file", file);
fetch('/upload/image', {method: "POST", body: formData});

Thuộc tính Tệp Blob

Trong nhiều trình duyệt, Tệp có thuộc tính / chức năng Blob. Các chức năng này cho phép ta đọc file . Ta sẽ sử dụng một file có tên myFile.txt trông giống như sau:

File content!
(async () => {
  // .text() transforms the file into a stream and then into a string
  const fileContent = await file.text();
  console.log(fileContent);
  // logs "File content!"

  // .stream() returns a ReadableStream
  const fileContentStream = await file.stream();
  console.log(await streamToText(fileContentStream));
  // logs "File content!"

  const buffer = await file.arrayBuffer();
  console.log(bufferToText(buffer))
  // logs "File content!"

  // .slice() allows you to get slices of the file here we take a slice of the entire file
  const fileSliceBlob = file.slice(0, file.length);
  // we convert to blob to a stream
  const fileSliceBlobStream = await fileSliceBlob.stream();
  console.log(await streamToText(fileSliceBlobStream));
  // logs "File content!"

})()

// We just use this function to convert streams to text
const streamToText = async (blob) => {
  const readableStream = await blob.getReader();
  const chunk = await readableStream.read();
  return new TextDecoder('utf-8').decode(chunk.value);
}

// Not the best way to get text from a file!
const bufferToText = (buffer) => {
  const bufferByteLength = buffer.byteLength;
  const bufferUint8Array = new Uint8Array(buffer, 0, bufferByteLength);
  return new TextDecoder().decode(bufferUint8Array);
}

Vấn đề là một số trình duyệt quan trọng không hỗ trợ các thuộc tính File Blob.

Một số mã FileReader

API FileReader được sử dụng rộng rãi hơn nhiều. Như bạn sẽ thấy, ta có các tính năng tương tự như giao diện Tệp. Ta cũng có các tính năng bổ sung.

Vòng đời của FileReader

Có 6 sự kiện chính được đính kèm với FileReader:

  • loadstart: Kích hoạt khi ta bắt đầu tải file .
  • tiến trình: Bắt lửa khi đốm màu được đọc trong bộ nhớ.
  • hủy bỏ: .abort khi ta gọi .abort
  • error: Cháy khi xảy ra lỗi
  • tải: Kích hoạt khi đọc thành công.
  • loadend: Kích hoạt khi file được tải và nếu lỗi hoặc hủy bỏ không được gọi hoặc nếu tải bắt đầu đọc mới.

Phương thức FileReader

Để bắt đầu tải file của ta , ta có bốn phương pháp:

  • readAsArrayBuffer(file) : Đọc file hoặc blob dưới dạng cache mảng. Một trường hợp sử dụng là gửi các file lớn đến một nhân viên dịch vụ.
  • readAsBinaryString(file) : Đọc file dưới dạng chuỗi binary
  • readAsText(file, format) : Đọc file dưới dạng USVString (gần giống như một chuỗi) và bạn có thể chỉ định một định dạng tùy chọn.
  • readAsDataURL(file) : Kết quả sẽ trả về một URL nơi bạn có thể truy cập nội dung của file , nó được mã hóa Base64 và sẵn sàng gửi đến server của bạn

Đây là một số mã bạn có thể sử dụng để thấy API FileReader đang hoạt động.

<body>
  <input type='file' id='input'>
  <progress value="0" max="100" id="progress-bar"></progress>
  <div id="status"></div>
  <script>

  //
  document.getElementById('input').addEventListener('change', (e) => {
    const file = document.getElementById('input').files[0];
    if (file) {
      processFile(file);
    }
  })

  const processFile = (file) => {
    // we define fr as a new instance of FileReader
    const fr = new FileReader();

    fr.readAsDataURL(file);
    // Handle progress, success, and errors
    // fr.onprogress = updateProgress;
    fr.onerror = errorHandler;
    fr.onabort = () => changeStatus('Start Loading');
    fr.onloadstart =   () => changeStatus('Start Loading');
    fr.onload = ()=> {changeStatus('Loaded')};
    fr.onloadend = () => loaded;
    // Here you can perform some operations on the data asynchronously
    fr.onprogress = setProgress;
  }

  // Updates the value of the progress bar
  const setProgress = (e) => {
    // The target is the file reader
    const fr = e.target;
    const loadingPercentage =  100 * e.loaded / e.total;
    document.getElementById('progress-bar').value = loadingPercentage;
  }

  const changeStatus = (status) => {
    document.getElementById('status').innerHTML = status
  }

  const loaded = (e) => {
    changeStatus('Load ended!');
    const fr = e.target
    var result = fr.result;
    console.log('result:')
    console.log(result)
    // Here we can send the result to a server for example
  }

  const errorHandler = (e) => {
    changeStatus("Error: " + e.target.error.name)
  }

</script>
</body>

Bạn có thể xem mã trực tiếp tại đây (mở console dành cho nhà phát triển của bạn) và mã nguồn tại đây .

Trình đọc file trên chuỗi

FileReader là một API không đồng bộ vì ta không muốn chặn stream chính trong khi đọc file . Ví dụ: ta không muốn giao diện user của bạn ngừng hoạt động khi trình duyệt đang cố đọc một file rất lớn. Tuy nhiên, có một version đồng bộ của FileReader được gọi là FileReaderSync. Ta chỉ có thể sử dụng FileReaderSync trong Web Worker. Nhân viên web có stream riêng nên họ sẽ không chặn stream chính. FileReaderSync sử dụng các phương pháp tương tự như FileReader:

  • FileReaderSync.readAsArrayBuffer ()
  • FileReaderSync.readAsBinaryString ()
  • FileReaderSync.readAsText ()
  • FileReaderSync.readAsDataURL ()

Không có trình xử lý sự kiện nào vì nó đồng bộ.


Tags:

Các tin liên quan

Tìm hiểu ký hiệu Big O qua JavaScript
2020-01-20
Cách sử dụng API BroadcastChannel trong JavaScript
2020-01-13
Đa năng hóa chuỗi trong JavaScript bằng Simplur
2020-01-10
Hướng dẫn nhanh về phương pháp đối sánh chuỗi trong JavaScript
2020-01-07
Tham quan API quyền JavaScript
2020-01-05
V8 của V8: Chuỗi liên kết tùy chọn và kết hợp Nullish trong JavaScript
2019-12-29
Phân tích cú pháp, xác thực, thao tác và hiển thị ngày và giờ trong JavaScript với Day.js
2019-12-28
Cách bắt đầu với API hiệu suất JavaScript
2019-12-25
Xem xét tất cả 13 bẫy proxy JavaScript
2019-12-19
Khám phá phương thức indexOf cho chuỗi và mảng trong JavaScript
2019-12-17