欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

node文件資源管理器的解壓縮從零實現

 更新時間:2023年12月21日 15:19:03   作者:寒露  
這篇文章主要為大家介紹了node文件資源管理器的解壓縮從零實現示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

解壓縮

這里使用較為常用的 7z 來處理壓縮包,它可以解開常見的壓縮包格式

Unpacking only: APFS, AR, ARJ, CAB, CHM, CPIO, CramFS, DMG, EXT, FAT, GPT, HFS, IHEX, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, QCOW2, RAR, RPM, SquashFS, UDF, UEFI, VDI, VHD, VHDX, VMDK, XAR and Z.

開發(fā)

預下載 mac 與 linux 版本的 7z 二進制文件,放置于 explorer-manage/src/7zip/linux 與 /mac 目錄內。可前往 7z 官方進行下載,下載鏈接

也可以使用 7zip-bin 這個依賴,內部包含所有環(huán)境可運行的二進制文件。由于項目是由鏡像進行運行,使用全環(huán)境的包會加大鏡像的體積。

所以這里單獨下載特定環(huán)境的下二進制文件,可能版本會比較舊,最近更新為 2022/5/16 。目前最新的 2023/06/20@23.01 版本。

使用 node-7z 這個依賴處理 7z 的輸入輸出

安裝依賴

pnpm i node-7z

運行文件

// https://laysent.com/til/2019-12-02_7zip-bin-in-alpine-docker
// https://www.npmjs.com/package/node-7z
// https://www.7-zip.org/download.html
// import sevenBin from '7zip-bin'
import node7z from 'node-7z'
import { parseFilePath } from './parse-path.mjs'
import path from 'path'
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { formatPath } from '../../lib/format-path.mjs'
const __dirname = dirname(fileURLToPath(import.meta.url))
/**
 * @type {import('node-7z').SevenZipOptions}
 */
const base_option = {
  $bin: process.platform === 'darwin' ? path.join(__dirname, './mac/7zz') : path.join(__dirname, './linux/7zzs'),
  recursive: true,
  exclude: ['!__MACOSX/*', '!.DS_store'],
  latestTimeStamp: false,
}
/**
 * @param path {string}
 * @param out_path {string|undefined}
 * @param pwd {string | number | undefined}
 * @returns {import('node-7z').ZipStream}
 */
export const node7zaUnpackAction = (path, out_path = '', pwd = 'pwd') => {
  const join_path = formatPath(path)
  const { file_dir_path } = parseFilePath(join_path)
  return node7z.extractFull(join_path, formatPath(out_path) || `${file_dir_path}/`, {
    ...base_option,
    password: pwd,
  })
}
/**
 * @param path {string}
 * @param pwd {string | number | undefined}
 * @returns {import('node-7z').ZipStream}
 */
export const node7zListAction = (path, pwd = 'pwd') => {
  const join_path = formatPath(path)
  return node7z.list(join_path, { ...base_option, password: pwd })
}

簡單封裝下 node7zaUnpackAction 與 node7zListAction 方法

  • node7zaUnpackAction:解壓縮方法
  • node7zListAction:查看當前壓縮包內容

explorer 客戶端展示

大致設計為彈窗模式,提供一個解壓縮位置,默認當前壓縮包位置。再提供一個密碼輸入欄,用于帶密碼的壓縮包解壓。

解壓縮一個超大包時,可能會超過 http 的請求超時時間,瀏覽器會主動關閉這次請求。導致壓縮包沒有解壓縮完畢,請求就已經關閉了。雖然 node 還在后臺進行解壓縮。但是客戶端無法知道是否解壓縮完畢。

可通過延長 http 的請求超時時間。也可使用 stream 逐步輸出內容的方式避免超時,客戶端部分可以實時看到當前解壓縮的進度。類似像 AI 機器人提問時,文字逐字出現的效果。

查看壓縮包內容

直接使用 server action 調用 node7zListAction 方法即可

解壓縮

使用 node-7z 的輸出流逐步輸出到瀏覽器

封裝一個 post api 接口。

  • 監(jiān)聽 node-7z 返回的數據流 .on('data') 事件。
  • 對數據流做 encoder.encode(JSON.stringify(value) + ‘, ’) 格式化操作。方便客戶端讀取數據流。
  • 每秒往客戶端輸出一個時間戳避免請求超時 stream.push({ loading: Date.now() })
  • 10 分鐘后關閉 2 的定時輸出,讓其自然超時。
  • 客戶端通過 fetch 獲取數據流,具體可以看 unpack 方法

接口 api

import { NextRequest, NextResponse } from 'next/server'
import { node7zaUnpackAction } from '@/explorer-manager/src/7zip/7zip.mjs'
import { nodeStreamToIterator } from '@/explorer-manager/src/main.mjs'
const encoder = new TextEncoder()
const iteratorToStream = (iterator: AsyncGenerator) => {
  return new ReadableStream({
    async pull(controller) {
      const { value, done } = await iterator.next()
      if (done) {
        controller.close()
      } else {
        controller.enqueue(encoder.encode(JSON.stringify(value) + ', '))
      }
    },
  })
}
export const POST = async (req: NextRequest) => {
  const { path, out_path, pwd } = await req.json()
  try {
    const stream = node7zaUnpackAction(path, out_path, pwd)
    stream.on('data', (item) => {
      console.log('data', item.file)
    })
    const interval = setInterval(() => {
      console.log('interval', stream.info)
      stream.push({ loading: Date.now() })
    }, 1000)
    const timeout = setTimeout(
      () => {
        clearInterval(interval)
      },
      60 * 10 * 1000,
    )
    stream.on('end', () => {
      console.log('end', stream.info)
      stream.push({
        done: JSON.stringify(Object.fromEntries(stream.info), null, 2),
      })
      clearTimeout(timeout)
      clearInterval(interval)
      stream.push(null)
    })
    return new NextResponse(iteratorToStream(nodeStreamToIterator(stream)), {
      headers: {
        'Content-Type': 'application/octet-stream',
      },
    })
  } catch (e) {
    return NextResponse.json({ ret: -1, err_msg: e })
  }
}

客戶端彈窗組件

'use client'
import React, { useState } from 'react'
import { Card, Modal, Space, Table } from 'antd'
import UnpackForm from '@/components/unpack-modal/unpack-form'
import { isEmpty } from 'lodash'
import { useRequest } from 'ahooks'
import Bit from '@/components/bit'
import DateFormat from '@/components/date-format'
import { UnpackItemType } from '@/explorer-manager/src/7zip/types'
import { useUnpackPathDispatch, useUnpackPathStore } from '@/components/unpack-modal/unpack-path-context'
import { useUpdateReaddirList } from '@/app/path/readdir-context'
import { unpackListAction } from '@/components/unpack-modal/action'
let pack_list_path = ''
const UnpackModal: React.FC = () => {
  const unpack_path = useUnpackPathStore()
  const changeUnpackPath = useUnpackPathDispatch()
  const [unpack_list, changeUnpackList] = useState<UnpackItemType['list']>([])
  const { update } = useUpdateReaddirList()
  const packList = useRequest(
    async (form_val) => {
      pack_list_path = unpack_path
      const { pwd } = await form_val
      return unpackListAction(unpack_path, pwd)
    },
    {
      manual: true,
    },
  )
  const unpack = useRequest(
    async (form_val) => {
      pack_list_path = unpack_path
      unpack_list.length = 0
      const { out_path, pwd } = await form_val
      const res = await fetch('/path/api/unpack', {
        method: 'post',
        body: JSON.stringify({ path: unpack_path, out_path, pwd: pwd }),
      })
      if (res.body) {
        const reader = res.body.getReader()
        const decode = new TextDecoder()
        while (1) {
          const { done, value } = await reader.read()
          const decode_value = decode
            .decode(value)
            .split(', ')
            .filter((text) => Boolean(String(text).trim()))
            .map((value) => {
              try {
                return value ? JSON.parse(value) : { value }
              } catch (e) {
                return { value }
              }
            })
            .filter((item) => !item.loading)
            .reverse()
          !isEmpty(decode_value) && changeUnpackList((unpack_list) => decode_value.concat(unpack_list))
          if (done) {
            break
          }
        }
      }
      return Promise.resolve().then(update)
    },
    {
      manual: true,
    },
  )
  return (
    <Modal
      title="解壓縮"
      open={!isEmpty(unpack_path)}
      width={1000}
      onCancel={() => changeUnpackPath('')}
      footer={false}
      destroyOnClose={true}
    >
      <UnpackForm packList={packList} unpack={unpack} />
      <Space direction="vertical" style={{ width: '100%' }}>
        {pack_list_path === unpack_path && !isEmpty(unpack_list) && (
          <Card
            title="unpack"
            bodyStyle={{
              maxHeight: '300px',
              overflowY: 'scroll',
              paddingTop: 20,
              overscrollBehavior: 'contain',
            }}
          >
            {unpack_list.map(({ file, done }) => (
              <pre key={file || done}>{file || done}</pre>
            ))}
          </Card>
        )}
        {pack_list_path === unpack_path && !isEmpty(packList.data) && (
          <Card title="壓縮包內容">
            {!isEmpty(packList.data?.data) && (
              <Table
                scroll={{ x: true }}
                rowKey={({ file }) => file}
                columns={[
                  { key: 'file', dataIndex: 'file', title: 'file' },
                  {
                    key: 'size',
                    dataIndex: 'size',
                    title: 'size',
                    width: 100,
                    render: (size) => {
                      return <Bit>{size}</Bit>
                    },
                  },
                  {
                    key: 'sizeCompressed',
                    dataIndex: 'sizeCompressed',
                    title: 'sizeCompressed',
                    width: 150,
                    render: (size) => {
                      return <Bit>{size}</Bit>
                    },
                  },
                  {
                    key: 'datetime',
                    dataIndex: 'datetime',
                    title: 'datetime',
                    width: 180,
                    render: (date) => <DateFormat>{new Date(date).getTime()}</DateFormat>,
                  },
                ]}
                dataSource={packList.data?.data}
              />
            )}
            {packList.data?.message && <p>{packList.data?.message}</p>}
          </Card>
        )}
      </Space>
    </Modal>
  )
}
export default UnpackModal

測試用逐字輸出

每秒往客戶端輸出當前時間。持續(xù) 10 分鐘。

import { iteratorToStream, nodeStreamToIterator } from '@/explorer-manager/src/main.mjs'

function sleep(time: number) {
  return new Promise((resolve) =&gt; {
    setTimeout(resolve, time)
  })
}

const encoder = new TextEncoder()

async function* makeIterator() {
  let length = 0
  while (length &gt; 60 * 10) {
    await sleep(1000)
    yield encoder.encode(`&lt;p&gt;${length} ${new Date().toLocaleString()}&lt;/p&gt;`)

    length += 1
  }
}

export async function POST() {
  return new Response(iteratorToStream(nodeStreamToIterator(makeIterator())), {
    headers: { 'Content-Type': 'application/octet-stream' },
  })
}

export async function GET() {
  return new Response(iteratorToStream(nodeStreamToIterator(makeIterator())), {
    headers: { 'Content-Type': 'html' },
  })
}

效果

git-repo

yangWs29/share-explorer

以上就是node文件資源管理器的解壓縮從零實現的詳細內容,更多關于node文件資源解壓縮的資料請關注腳本之家其它相關文章!

相關文章

  • 從零開始學習Node.js系列教程之SQLite3和MongoDB用法分析

    從零開始學習Node.js系列教程之SQLite3和MongoDB用法分析

    這篇文章主要介紹了Node.js SQLite3和MongoDB用法,結合實例形式分析了SQLite3和MongoDB數據庫的初始化、連接、查詢等操作的實現技巧與相關注意事項,需要的朋友可以參考下
    2017-04-04
  • 配置nodejs環(huán)境的方法

    配置nodejs環(huán)境的方法

    本篇文章主要介紹了配置nodejs環(huán)境變量的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Node工程的依賴包管理方式

    Node工程的依賴包管理方式

    在前端工程化中,JavaScript 依賴包管理是非常重要的一環(huán)。依賴包通常是項目所依賴的第三方庫、工具和框架等資源,它們能夠幫助我們減少重復開發(fā)、提高效率并且確保項目可以正確的運行。本文詳細介紹了Node工程的依賴包管理方式,感興趣的同學可以參考一下
    2023-04-04
  • 詳解nodejs微信jssdk后端接口

    詳解nodejs微信jssdk后端接口

    本篇文章主要介紹了詳解nodejs微信jssdk后端接口,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • node.js中的fs.fchmodSync方法使用說明

    node.js中的fs.fchmodSync方法使用說明

    這篇文章主要介紹了node.js中的fs.fchmodSync方法使用說明,本文介紹了fs.fchmodSync的方法說明、語法、接收參數、使用實例和實現源碼,需要的朋友可以參考下
    2014-12-12
  • HTTP JSON接口模擬工具Interfake快速入門教程

    HTTP JSON接口模擬工具Interfake快速入門教程

    這篇文章主要為大家介紹了HTTP JSON接口模擬工具Interfake快速入門教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • nodeJs內存泄漏問題詳解

    nodeJs內存泄漏問題詳解

    由于內存泄漏在Node.js中非常的常見,可能在瀏覽器中應用javascript時,對于其內存泄漏不是特別敏感,但作為服務器語言運行時,你就不得不去考慮這些問題。
    2016-09-09
  • nvm介紹、安裝、報錯處理及使用詳細步驟

    nvm介紹、安裝、報錯處理及使用詳細步驟

    所謂nvm就是一個可以讓你在同一臺機器上安裝和切換不同版本node的工具,下面這篇文章主要給大家介紹了關于nvm介紹、安裝、報錯處理及使用的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • Node.js中操作MongoDB的CRUD操作指南

    Node.js中操作MongoDB的CRUD操作指南

    在Node.js中操作MongoDB常見的庫有mongodb原生驅動和mongoose等,本文將使用mongodb官方驅動包來進行示例,在開始之前,請確保已經安裝了MongoDB數據庫并且在本地啟動了MongoDB服務,需要的朋友可以參考下
    2024-01-01
  • npm?i報錯以及解決方案實戰(zhàn)案例

    npm?i報錯以及解決方案實戰(zhàn)案例

    npm在前端開發(fā)流程中提供了非常完善的自動化工具鏈,但是同樣由于其復雜性導致有很多奇奇怪怪的問題,下面這篇文章主要給大家介紹了關于npm?i報錯以及解決方案的相關資料,需要的朋友可以參考下
    2022-07-07

最新評論