Skip to content
0

数据格式转换

Buffer 和 string

const str = "Hello有趣的12"
const buffer = Buffer.from(str)

console.log(buffer)
// <Buffer 48 65 6c 6c 6f e6 9c 89 e8 b6 a3 e7 9a 84 31 32>
console.log(buffer.toString())
// Hello有趣的12

如下的方法是等价的:

console.log(readFileSync('./public/image/xxx.png').toString())
console.log(readFileSync('./public/image/xxx.png', 'utf-8'))

甚至可以拓展更深:

type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "base64url" | "latin1" | "binary" | "hex";

const encoding: BufferEncoding
console.log(readFileSync('./public/image/xxx.png').toString(encoding))
console.log(readFileSync('./public/image/xxx.png', encoding))

Buffer 和 Base64

例如从本地读取一张图片,并且得到 Base64 的格式, 这里使用了 broofa/mime 来得到资源的 mime 类型

import { readFileSync } from 'fs'
import mime from 'mime'

const filePath = '../public/avatar.png'

const stream = readFileSync(filePath)
// 将图片数据转换为 Base64 字符串
const base64String = Buffer.from(stream).toString('base64')

const base64Path = `data:${mime.getType(filePath)};base64,${base64String}`

console.log(base64Path)
// data:image/png;base64,iVBORw0KGgoAAAA...

将 Base64 写入文件

const base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANSUh...'

const base64Image = base64Data.split(';base64,').pop()!

writeFileSync('./avatar.png', base64Image, { encoding: 'base64' })

Stream 和 Blob

场景:通常使用 axios + stream 的方式接收一些来自后端的二进制信息

const { data: stream } = await axios.post(
  `https://path/from/some/server`,
  {
    query: 'xxx',
  },
  {
    headers: {
      'content-type': 'application/json',
    },
    responseType: 'stream',
  },
);

const response = new Response(stream);

// 然后,使用 Response.blob() 方法将其转换为 Blob 对象
const blob = await response.blob();

// 例如还可以使用 FormData 可以将 blob 数据传给 CDN 服务
const fd = new FormData()
fd.append('file', blob)

await axios.post('https://path/to/your/server', fd, {
  headers: {
    // 'content-type': 'multipart/form-data',
  },
})

Stream 和 Buffer

Stream 转为 Buffer

Stream 的来源可以是任意的, 例如从接口返回:

const { data: stream } = await axios.post(
  `https://path/from/some/server`,
  {
    query: 'xxx',
  },
  {
    headers: {
      'content-type': 'application/json',
    },
    responseType: 'stream',
  },
);

或者是本地的 Buffer

const stream = new Readable()
stream.push('Hello, ')
stream.push('world!')
stream.push(null) // 表示数据结束

然后可以使用 stream.on 来监听数据流, 并将数据流转换为 Buffer

const writableBuffer = []
stream.on('data', (chunk) => {
  writableBuffer.push(chunk);
});
stream.on('end', () => {
  const bufferData = Buffer.concat(writableBuffer);
  console.log(bufferData);
});

浏览器中 Blob

在文件上传的场景中,通过 <input type="file" /> 读取到的 files 就是 File 类型的数据, File 继承自 Blob, 所以我们可以将 File 设置为 FormData 的 value,来进行文件的上传



<h2>文件上传</h2>
<input type="file" id="fileInput">
<button id="uploadButton">上传文件</button>
<div id="status"></div>

<script>
  const fileInput = document.getElementById('fileInput')
  const uploadButton = document.getElementById('uploadButton')
  const status = document.getElementById('status')

  uploadButton.addEventListener('click', async () => {
    const file = fileInput.files[0]
    if (!file) {
      status.textContent = '请选择文件'
      return
    }
    console.log(file instanceof File, file instanceof Blob) // => true true

    // const formData = new FormData()
    // formData.append('file', file)
  })
</script>

base64ToFile

下面是一个在浏览器中,将图片的 base64 转为 File 对象的例子

export function base64ToFile({ base64, fileType }: { base64: string; fileType: string }) {
    const bytes = window.atob(base64);
    const ab = new ArrayBuffer(bytes.length);
    const ia = new Uint8Array(ab);

    for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
    }
    const type = fileType === 'jpg' ? 'jpeg' : fileType;
    const blobFile: ExtendedBlob = new Blob([ia], { type: 'image/' + type });
    blobFile.lastModifiedDate = new Date();
    blobFile.name = `img_${new Date()}.${type || 'jpg'}`;
    return new File([blobFile], blobFile.name, { type: 'image/' + type, lastModified: Date.now() });
}
// source: https://peterroe.icu/download.png
  const base64Str = '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'

const file = base64ToFile({
  base64: base64Str,
  fileType: 'png'
})

用 FileReader 读取 file 得到 base64,然后展示:

<img class="preview" />
<script>
  const reader = new FileReader();

  reader.onload = function (event) {
    document.querySelector('.preview').src = event.target.result;
  };

  reader.readAsDataURL(file)
</script>

Released under the MIT License.