vue实现文件分割与合并

上传文件到蓝奏云,但文件大于100兆,又不想充钱,另辟蹊径。
想着把文件按指定大小进行分割,这里用vue实现。

一、文件分割页面

分割.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件分割器</title>
    <script src="../vue.js"></script>
</head>
<body>
    <div id="app">
        <h3>文件分割器</h1>
        选择文件&nbsp;&nbsp;<input ref="fileInput" type="file" id="file-input" @change="handleSelectFile"><br>
        分割大小&nbsp;&nbsp;<input v-model="BLOCK_SIZE" type="number" placeholder="块大小(MB)">(MB)<br>
        文件类型&nbsp;&nbsp;<input v-model="extension" type="text" placeholder="文件类型">
        <br>
        <br>
        <button @click="downloadFiles">下载分割文件</button>
        <span>蓝奏云上传 .bin 类型的文件会失败</span>

    </div>
    <script>

        let app = new Vue({
            el:"#app",
            data:{
                BLOCK_SIZE : 90 , // 90MB
                fileName:"",
                extension:""
            },
            methods:{
                handleSelectFile(){
                    const file = this.$refs["fileInput"].files[0];
                    this.fileName = file.name;
                    this.extension = (file.name+"").split(".").pop();
                },
                downloadFiles() {
                    if(this.$refs["fileInput"].files.length==0){
                        alert("请选择文件")
                        return;
                    }
                    const file = this.$refs["fileInput"].files[0];
                    if (!file) return;

                    const chunkSize = this.BLOCK_SIZE * 1024 * 1024;
                    const chunks = this.splitFile(file, chunkSize);
                    this.downloadChunks(chunks);
                },
                splitFile(file, chunkSize) {
                    const chunks = [];
                    let start = 0;

                    while (start < file.size) {
                        const chunk = file.slice(start, start + chunkSize);
                        chunks.push(chunk);
                        start += chunkSize;
                    }

                    return chunks;
                },
                downloadChunks(chunks) {
                    chunks.forEach((chunk, index) => {
                        const url = URL.createObjectURL(chunk);
                        const a = document.createElement('a');
                        a.href = url;
                        a.download = `${this.fileName}.part_${index}.`+this.extension;
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);
                        URL.revokeObjectURL(url);
                    });
                }
            }
        })
    </script>
</body>

</html>

二、文件合并页面

合并.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件合并器</title>
    <script src="../vue.js"></script>

<body>
    <div id="app">
        <h3>文件合并器</h3>
        <input ref="inputFile" type="file" id="file-input" multiple>
        <button @click="handleDownload">合并文件并下载</button>
    </div>
    <script>
        var app = new Vue({
            el: "#app",
            data: {
                fileName: "",
                extension: ""
            },
            methods: {
                handleSelectFile() {
                    const file = this.$refs["fileInput"].files[0];
                    this.fileName = file.name;
                    this.extension = (file.name + "").split(".").pop();
                },
                mergeFiles(files) {
                    // 读取每个文件为ArrayBuffer  
                    const filePromises = files.map(file => new Promise((resolve, reject) => {
                        const reader = new FileReader();
                        reader.onload = event => resolve(event.target.result);
                        reader.onerror = error => reject(error);
                        reader.readAsArrayBuffer(file);
                    }));

                    // 等待所有文件读取完成  
                    return Promise.all(filePromises).then(arrayBuffers => {
                        // 将所有ArrayBuffer合并为一个  
                        const totalLength = arrayBuffers.reduce((acc, buf) => acc + buf.byteLength, 0);
                        const resultBuffer = new Uint8Array(totalLength);
                        let offset = 0;
                        arrayBuffers.forEach(buf => {
                            resultBuffer.set(new Uint8Array(buf), offset);
                            offset += buf.byteLength;
                        });

                        // 创建Blob对象  
                        const mergedBlob = new Blob([resultBuffer], { type: 'application/octet-stream' });
                        return mergedBlob;
                    });
                },
                downloadMergedFile(mergedBlob) {
                    const url = URL.createObjectURL(mergedBlob);
                    const a = document.createElement('a');
                    a.href = url;
                    a.download = this.fileName; // 假设合并后的文件为二进制格式  
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    URL.revokeObjectURL(url);
                },

                async downloadMergedFile2(buffer) {
                    const options = {
                        suggestedName: this.fileName, // 建议的文件名  
                        types: [
                            {
                                description: '文件描述', // 文件的描述  
                                // accept: {
                                //     'text/plain': ['.txt'], // MIME 类型和对应的文件扩展名  
                                // },
                            },
                            // 可以添加更多类型  
                        ],
                        excludeAcceptAllOption: false, // 是否排除“接受所有文件”选项  
                    };

                    try {
                        const fileHandle = await showSaveFilePicker(options);
                        const writable = await fileHandle.createWritable();
                        await writable.write(buffer)
                        await writable.close()
                    } catch (error) {
                        console.error("保存文件失败", error);
                        downloadMergedFile(buffer);
                    }
                },
                handleDownload() {
                    //文件是否为空
                    if (this.$refs["inputFile"].files.length === 0) { alert('请选择要合并的文件'); return; }
                    let files = [];
                    // FileList转Array
                    for (let i = 0; i < this.$refs["inputFile"].files.length; i++) {
                        files.push(this.$refs["inputFile"].files[i]);
                    };
                    // 按名称排序
                    files.sort((a, b) => a.name.localeCompare(b.name));

                    // 获取文件名称 fileName.apk.part_index.bin  ==> fileName.apk
                    let t = files[0].name.split(".");
                    console.log(t);
                    t.pop();
                    console.log(t);
                    t.pop();
                    console.log(t);
                    let name = t.join(".");
                    this.fileName = name;
                    console.log(this.fileName);

                    //合并文件
                    this.mergeFiles(files).then(mergedBlob => {
                        this.downloadMergedFile2(mergedBlob);
                    }).catch(error => {
                        console.error('合并文件时发生错误:', error);
                        alert('合并文件时发生错误,请检查文件是否正确选择');
                    });
                }
            }
        })
    </script>
</body>
</head>

</html>

三、合并两个页面

放到一个页面内方便测试

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <iframe src="./分割.html" frameborder="0" width="100%" height="200px"></iframe>
    <hr>
    <iframe src="./合并.html" frameborder="0" width="100%" height="200px"></iframe>
</body>

</html>

相关推荐

  1. vue实现文件分割合并

    2024-04-02 23:38:01       39 阅读
  2. 文件分割合并

    2024-04-02 23:38:01       62 阅读
  3. Linux分割合并文件

    2024-04-02 23:38:01       59 阅读
  4. Python 实现Excel 文件合并

    2024-04-02 23:38:01       67 阅读
  5. Git分支合并导致文件异常

    2024-04-02 23:38:01       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-02 23:38:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-02 23:38:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-02 23:38:01       87 阅读
  4. Python语言-面向对象

    2024-04-02 23:38:01       96 阅读

热门阅读

  1. 前端src和href的区别

    2024-04-02 23:38:01       36 阅读
  2. 前端代码规范-命名规范

    2024-04-02 23:38:01       38 阅读
  3. Vuex工作机制

    2024-04-02 23:38:01       35 阅读
  4. Redis面试题10道

    2024-04-02 23:38:01       37 阅读
  5. 【TC3xx芯片】TC3xx芯片ACCEN寄存器保护详解

    2024-04-02 23:38:01       32 阅读
  6. 图像最低三位的可能情况

    2024-04-02 23:38:01       30 阅读
  7. 数据库 之 关系型数据库和非关系数据库

    2024-04-02 23:38:01       34 阅读
  8. 面试宝典:深入分析golang 的 泛型

    2024-04-02 23:38:01       35 阅读