目 录CONTENT

文章目录

FileReader 读取.txt|.csv|.xlsx文件、上传图片保存到服务器

FanJunyang
2023-03-16 / 0 评论 / 0 点赞 / 617 阅读 / 0 字
温馨提示:
本文最后更新于2024-08-14,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
广告 广告

文章已同步至掘金:https://juejin.cn/post/6925341165000589326
欢迎访问😃,有任何问题都可留言评论哦~

FileReader 对象可以一步读取文件内容,使用 File 对象或 Blob 对象指定要读取的文件或数据。

File 对象:可以是 input 元素上选择文件后返回的 FileList 对象,也可以是来自拖放操作生成的 DataTransfer 对象, 还可以是来自在一个 HTMLCanvasElement 上执行 mozGetAsFile 方法后返回的结果。

Blob 对象:表示一个不可变、原始数据的类文件对象,Blob 表示的不一定是JavaScript原生格式的数据。File 接口继承自 Blob 对象,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。Blob.size 表示包含数据大小(字节),Blob.type 表示该 Blob 对象的 Mime 类型。

方法

FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。

无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。

方法名 参数 描述
readAsBinaryString file 将文件读取为二进制编码,常搭配xlsx库来处理excel文件
readAsText file,[encoding] 将文件读取为文本(.csv、.txt),一般会指定utf-8编码
readAsDataURL file 将文件读取为DataURL,URL格式的Base64字符串,常用来读取本地图片并展示
abort (none) 终端读取操作

属性

  • FileReader.error :表示在读取文件时发生的错误 。

  • FileReader.readyState:表示FileReader状态的数字。取值如下:

常量名 描述
EMPTY 0 还没有加载任何数据.
LOADING 1 数据正在被加载.
DONE 2 已完成全部的读取请求.
  • FileReader.result:文件的内容。该属性仅在读取操作完成后才有效,数据的格式取决于使用哪个方法来启动读取操作。

事件处理程序

事件 调用时机
onabort 当读取操作被中止时调用
onerror 当读取操作发生错误时调用
onload 当读取操作成功完成时调用
onloadend 当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用
onloadstart 当读取操作将要开始之前调用
onprogress 在读取数据过程中周期性调用

input-accept属性

accept 属性规定了可通过文件上传提交的服务器接受的文件类型。

注意: accept 属性仅适用于 <input type="file">

加上multiple可以多选文件,这里暂时不实现多选

语法:

<input accept="audio/*|video/*|image/*|MIME_type">

提示: 如需规定多个值,请使用逗号分隔(比如 <input accept="audio/*,video/*,image/*" />)。

属性值:

描述
audio/* 接受所有的声音文件。
video/* 接受所有的视频文件。
image/* 接受所有的图像文件。
MIME_type 一个有效的 MIME 类型,不带参数。请参阅 IANA MIME 类型,获得标准 MIME 类型的完整列表。

常用MIME类型:

后缀名       MIME名称
*.3gpp      audio/3gpp, video/3gpp
*.ac3       audio/ac3
*.asf       allpication/vnd.ms-asf
*.au        audio/basic
*.css       text/css
*.csv       text/csv
*.doc       application/msword    
*.dot       application/msword    
*.dtd       application/xml-dtd    
*.dwg       image/vnd.dwg    
*.dxf       image/vnd.dxf
*.gif       image/gif    
*.htm       text/html    
*.html      text/html    
*.jp2       image/jp2    
*.jpe       image/jpeg
*.jpeg      image/jpeg
*.jpg       image/jpeg    
*.js        text/javascript, application/javascript 
*.json      application/json    
*.mp2       audio/mpeg, video/mpeg    
*.mp3       audio/mpeg    
*.mp4       audio/mp4, video/mp4    
*.mpeg      video/mpeg    
*.mpg       video/mpeg    
*.mpp       application/vnd.ms-project    
*.ogg       application/ogg, audio/ogg    
*.pdf       application/pdf    
*.png       image/png    
*.pot       application/vnd.ms-powerpoint    
*.pps       application/vnd.ms-powerpoint    
*.ppt       application/vnd.ms-powerpoint    
*.rtf       application/rtf, text/rtf    
*.svf       image/vnd.svf    
*.tif       image/tiff    
*.tiff      image/tiff    
*.txt       text/plain    
*.wdb       application/vnd.ms-works    
*.wps       application/vnd.ms-works    
*.xhtml     application/xhtml+xml    
*.xlc       application/vnd.ms-excel    
*.xlm       application/vnd.ms-excel    
*.xls       application/vnd.ms-excel    
*.xlt       application/vnd.ms-excel    
*.xlw       application/vnd.ms-excel    
*.xml       text/xml, application/xml    
*.zip       aplication/zip    
*.xlsx      application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

示例

前端代码

<template>
  <div>
        <!-- 上传单文件.csv || .txt || .xlsx -->
        <el-button type="primary" 
            @click="$refs.uploadInput.click()">上传单文件
            <i class="el-icon-upload el-icon--right"></i>
        </el-button>

        <input type="file" style="display: none" ref="uploadInput" @change="importFile" accept=".csv, .txt, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />

        <div ref="showFile"></div>
        <hr>
        {{fileData}}
        <hr>

        <!-- 上传多文件.csv || .txt || .xlsx -->
        <el-button type="primary" 
            @click="$refs.uploadInputs.click()">上传多文件
            <i class="el-icon-upload el-icon--right"></i>
        </el-button>

        <input type="file" style="display: none" ref="uploadInputs" @change="importFiles" multiple accept=".csv, .txt, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />

        <div ref="showFile"></div>
        <hr>
        {{fileData}}
        <hr>

        <!-- 上传图片 .jpg || .jpeg || .png -->
        <span class="show-span">
            <span class="span" v-for="item in imgList" :key="item.imgName">
                <img :src="item.url" class="img" alt="">
                <i class="el-icon-error icon" @click="deleteImg(item.imgName)"></i>
            </span>
        </span>
        
        <span @click="$refs.uploadImg.click()" class="img-span">
            <span class="img-inside1 inside"></span>
            <span class="img-inside2 inside"></span>
        </span>
      <input type="file" style="display: none" ref="uploadImg" @change="importImg" accept="image/*" />

  </div>
</template>

<script>
import XLSX from 'xlsx'
import $ from 'jquery'
export default {
  name: 'App',
  data () {
      return {
          fileData: '',
          imgList: []
      }
  },
  methods: {
      importImg (event) {
        let files = event.target.files

        if (!files.length) {
            return;
        }

        let file = files[0];

        if (!/(.png|.jpeg|.jpg)$/.test(file.name)) {
            this.$message('上传文件格式错误')
            return
        }

        let reader = new FileReader();
        reader.readAsDataURL(file)
        reader.onload = () => {
            let base64 = reader.result
            $.ajax({
                url: "http://www.fanjunyang.xyz:9675/uploadImg",
                data: {base64},
                type: "POST",
                dataType: "json",
                success: data => {
                    const {imgName, url} = data.data
                    this.imgList = [{imgName ,url}, ...this.imgList]
                }
            })
        }
        this.$refs.uploadImg.value = ''
      },
      deleteImg (imgName) {
            if (!imgName) {
                return
            }

            this.$confirm('确定删除该图片吗?', '提示').then(() => {
                $.ajax({
                    url: "http://www.fanjunyang.xyz:9675/deleteImg",
                    data: { imgName },
                    type: "POST",
                    dataType: "json",
                    success: data => {
                        if (!data.code) {
                            this.imgList.splice(this.imgList.findIndex(img => img.imgName === imgName), 1)
                            this.$message.success('删除成功')
                        }
                    }
                })
            }).catch((e) => {
                console.log(e);
            })
      },
      importFiles (event) {
          let files = event.target.files
          console.log(files)
      },
      importFile (event) {
          let files = event.target.files

          if (!files.length) {
              return;
          }

          let file = files[0];

          if (!/(.csv|.xlsx|.txt)$/.test(file.name)) {
              this.$message('上传文件格式错误')
              return
          }

          let reader = new FileReader();

          if (/(.csv|.txt)$/.test(file.name)) {
              reader.readAsText (file, 'utf-8')
              reader.onload = () => {
                  // 数据
                  let result = reader.result
                  if (/.txt$/.test(file.name)) {
                      // 最终数据
                      // console.log(result);
                      this.fileData = result
                  }
                  // 处理CSV
                  if (/.csv$/.test(file.name)) {
                      let arr = result.split('\n')
                      let arrHeader = arr[0].split(',').map(item => item.trim())
                      let csvResult = arr.map(item => {
                          let _str = {}
                          item.split(',').forEach((v, i) => {
                              _str[arrHeader[i]] = v.trim()
                          })
                          return _str
                      })
                      csvResult.shift()
                      csvResult.pop()

                      // 最终数据
                      // console.log(csvResult)
                      this.fileData = csvResult
                  }
              };
          }

          if (/.xlsx$/.test(file.name)) {
              reader.readAsBinaryString(file)
              reader.onload = (event) => {
                  try {
                      let data = event.target.result
                      let workBook =  XLSX.read(data, {type: 'binary'}) // 以二进制流方式读取得到整份excel表格对象

                      // console.log(workBook.SheetNames)  // 获取各个sheet表,可拿到自己需要的表

                      let result = {}   // 存储数据
                      workBook.SheetNames.forEach(sheetName => {
                          let workSheet = workBook.Sheets[sheetName]
                          result[sheetName] = XLSX.utils.sheet_to_json(workSheet)
                          // console.log(workBook.Sheets[sheetName]['!ref'])   // 表头
                      })

                      // 最终数据
                      // console.log(JSON.stringify(result, null, 2))
                      this.fileData = result

                  } catch (e) {
                      console.log(e);
                      return
                  }
              };
          }

          reader.onerror = () => {
              this.$message.error('文件读取失败')
              this.fileData = ''
          }
          this.$refs.showFile.innerHTML = `<i class="el-icon-document"></i>${file.name}`
          this.$refs.uploadInput.value = ''
      },
  }
}
</script>

<style scoped>

    .icon {
        position: absolute;
        right: 0px;
        top: -10px;
        color: red;
        font-size: 25px;
    }

    .span {
        display: inline-block;
        position: relative;
    }

    .img {
        width: 200px;
        height: 200px;
        margin-right: 10px;
    }

    .img-span {
        display: inline-block;
        width: 200px;
        height: 200px;
        border-radius: 5px;
        border: 1px dashed #ccc;
        position: relative;
    }

    .img-inside1 {
        width: 50px;
        height: 2px;
        display: inline-block;
        background-color: #ccc;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left: -25px;
        margin-top: -1px;
    }

    .img-inside2 {
        width: 2px;
        height: 50px;
        display: inline-block;
        background-color: #ccc;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left: -1px;
        margin-top: -25px;
    }

    .img-span:hover {
        border: 1px dashed aqua;
    }

    .img-span:hover .inside {
        background-color: aqua;
    }

</style>

后端代码

const Koa = require("koa")
const route = require('koa-route');
const fs = require('fs')
const Path = require('path')
const cors = require('koa-cors')
const bodyparser = require('koa-bodyparser')
const { nanoid } = require('nanoid');
const app = new Koa();

const { PORT, HOST} = require('./config');

app.use(cors())
app.use(bodyparser())

// 测试接口
const test = ctx => {
    ctx.body = "测试接口"
}

// 上传图片
const uploadImg = async ctx => {
    const { base64 } = ctx.request.body

    if (!base64) {
        ctx.body = {
            code: 1,
            msg: '参数错误'
        }
        return
    }
    const base64Data = base64.replace(/^data:image\/\w+;base64,/, "");

    const dataBuffer = Buffer.from(base64Data, 'base64');

    const imgName = `${nanoid()}.${/^data:image\/(\w+);base64,/.exec(base64)[1]}`

    const path = Path.resolve(__dirname, './images')

    try {
        const result = await new Promise((resolve,rejects) => {
            fs.writeFile(`${path}/${imgName}`, dataBuffer, (err) => {
                if(err){
                    rejects({
                        code: 1, 
                        msg: err
                    })
                }else{
                    resolve({
                        code: 0, 
                        data: {
                            url: HOST + imgName,
                            imgName
                        }
                    })
                }
            });
        })
    
        ctx.body = result
    } catch(e) {
        console.log(`upload:${e}`);
    }
}

// 删除图片
const deleteImg = async ctx => {
    const { imgName } = ctx.request.body

    if (!imgName) {
        ctx.body = {
            code: 1,
            msg: '参数错误'
        }
        return
    }

    const path = Path.join(__dirname, `images/${imgName}`)

    try {
        let result = ''
        if (fs.existsSync(path)) {
            result = await new Promise((resolve, rejects) => {
                fs.unlink(path, err => {
                    if (err) {
                        rejects({
                            code: 1,
                            msg: err
                        })
                    } else {
                        resolve({
                            code: 0,
                            msg: '删除成功'
                        })
                    }
                })
            })
        } else {
            result = {
                code: 1,
                msg: '找不到指定的文件'
            }
        }
    
        ctx.body = result
    } catch(e) {
        console.log(`delete:${e}`);
    } 
}

// 注册路由
app.use(route.get('/test', test))
app.use(route.post('/uploadImg', uploadImg))
app.use(route.post('/deleteImg', deleteImg))

app.listen(PORT, () => {
    console.log(`端口:${PORT},服务启动成功...`);
})

9_9

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin
  3. PayPal/U

    PayPal https://paypal.me/junyangfan
    BTC
    (Bitcoin)
    USDT
    (TRC20)
广告 广告

评论区