react文件分片上传

参考文档:

https://blog.csdn.net/weixin_39887846/article/details/113492372

https://juejin.cn/post/6844904046436843527

 

index主文件:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import type { FC } from 'react';
import { useState } from 'react';
import request from './request';
import { Button, Input, Card, Space, message } from 'antd';
import { useModel } from 'umi';
import ProgressBox from './Progress';
import qs from 'qs';
import { checkChunkUploadComplete, uploadPackage } from './service';
import { CloudUploadOutlined } from '@ant-design/icons';
import styles from './index.less';
 
export type UpLoadFileChunkProps = {
  params?: any /** 额外参数 */;
  disabled?: boolean;
  auto?: boolean /**是否需要自动请求接口获取文件信息 */;
  onChange?: (values: any) => void;
};
 
/**
 * 大文件分片上传组件
 *
 * @description 开发中
 */
const UpLoadFileChunk: FC<UpLoadFileChunkProps> = (props) => {
  const { params = {}, disabled = false, onChange, auto = false } = props || {};
  const chunkSize = 50 * 1024 * 1024; // 文件切片大小
  const [sourceFile, setSourceFile] = useState<any>(null);
  const [importLoading, setImportLoading] = useState<boolean>(false);
  const [chunksData, setChunksData] = useState<any[]>([]);
  const [progressStatus, setProgressStatus] = useState<any>('normal');
  const [, setPercentageTotal] = useState<any>(0);
 
  const { initialState } = useModel('@@initialState');
 
  // 获取包体信息
  const getPackageInfo = async (file_url: string) => {
    try {
      const res = await uploadPackage({
        filename: sourceFile.name,
        file_url,
        ...params,
      });
      const { code, result = {} } = res;
      if (code === 0) {
        if (onChange) onChange(result || undefined);
      }
      setImportLoading(false);
    } catch (error) {
      //
    } finally {
      //
    }
  };
 
  // 校验文件请求
  const mergeRequest = async (chunks: number, fileHash: any) => {
    try {
      const res = await checkChunkUploadComplete({
        filename: sourceFile.name,
        file_size: sourceFile.size,
        chunks,
        fileHash,
        user_id: initialState?.currentUser?.id || '',
      });
      const { code, message: resMessage, result } = res;
      if (code === 0) {
        if (auto) {
          getPackageInfo(result.file_url || '');
        } else {
          if (onChange)
            onChange({ file_url: result.file_url || '', filename: sourceFile.name || '' });
        }
        setImportLoading(false);
        setProgressStatus('success');
      } else {
        message.error(resMessage || '文件校验失败');
        setProgressStatus('exception');
        setImportLoading(false);
      }
    } catch (error) {
      //
    } finally {
      //
    }
  };
 
  // 计算文件hash
  const calculateHash = (chunkList: any) => {
    return new Promise((resolve) => {
      const w = new Worker('/hash.js');
      w.postMessage({ chunkList: chunkList });
      w.onmessage = (e) => {
        const { percentage, hash } = e.data;
        setPercentageTotal(percentage);
        if (hash) {
          // 当hash计算完成时,执行resolve
          resolve(hash);
        }
      };
    });
  };
 
  // 拆分文件
  const splitFile = (file: any, size = chunkSize) => {
    const fileChunkList = [];
    let cur = 0;
    while (cur < file.size) {
      fileChunkList.push({ chunk: file.slice(cur, cur + size) });
      cur += size;
    }
    return fileChunkList;
  };
 
  // 选择文件
  const handleFileChange = (e: any) => {
    const { files } = e.target;
    if (files.length === 0) return;
    // 保存源文件
    setSourceFile(files[0]);
    setChunksData([]);
    setProgressStatus('normal');
    // 文件分片
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    splitFile(files[0]);
  };
 
  // 上传分片
  const uploadChunks = async (uploadChunksData: any, fileHash: any) => {
    const formDataList = uploadChunksData.map((item: any, index: number) => {
      const formData = new FormData();
      formData.append('file', item.chunk);
      const allParams = {
        ...params,
        chunk: item.hash,
        chunks: uploadChunksData.length,
        is_chunk: 1,
        filename: sourceFile?.name,
        fileHash: item.fileHash,
        user_id: initialState?.currentUser?.id || '',
      };
      formData.append('data', qs.stringify({ ...allParams })); // 接口需要的其他参数
      return { formData, index };
    });
    const requestList = formDataList.map((item: any, index: number) => {
      return request({
        // url: '/common/chunkUpload',
        url: '/pack/apkChunkUpload',
        data: item.formData,
        onProgress: (e: any) => {
          const list = [...uploadChunksData];
          list[index].progress = parseInt(String((e.loaded / e.total) * 100));
          setChunksData(list);
          setProgressStatus('active');
        },
      });
    });
    // 上传文件
    await Promise.all(requestList).then(
      (resList) => {
        if (resList && resList.length) {
          // 所有请求都回来就发起校验
          if (resList.length === uploadChunksData.length) {
            mergeRequest(resList.length, fileHash);
          }
        }
      },
      (y) => {
        console.log(y);
      },
    );
  };
 
  // 上传文件
  const handleUpload = async () => {
    if (!sourceFile) {
      alert('请先选择文件');
      return;
    }
    setImportLoading(true);
    // 拆分文件
    const chunkList = splitFile(sourceFile);
    // 计算hash
    calculateHash(chunkList);
    // [断点续传+秒传功能]当前文件的hash标识
    const containerHash = await calculateHash(chunkList);
    // 续传&秒传
    // const { shouldUpload, uploadedList } = await verifyUpload(
    //   sourceFile.name, containerHash
    // );
    // if (!shouldUpload) {
    //   message.success('文件上传成功')
    //   return;
    // }
    const chunksDataList = chunkList.map(({ chunk }, index) => ({
      chunk: chunk,
      hash: index,
      progress: 0,
      fileHash: containerHash,
    }));
    // 保存分片数据
    setChunksData(chunksDataList);
    // 开始上传分片
    uploadChunks(chunksDataList, containerHash);
  };
 
  // 暂停
  // const handlePause = () => {
  //   chunksData.forEach((xhr) => xhr?.abort());
  //   setChunksData([]);
  // };
 
  // 续传
  // const handleResume = async () => {
  //   const { uploadedList } = await verifyUpload(sourceFile.name, containerHash);
  //   uploadChunks(uploadedList);
  // };
 
  return (
    <div>
      <div>
        <a
          href="javascript:;"
          className={`${styles['file']}${disabled ? ` ${styles[`file-disabled`]}` : ''}`}
        >
          选择文件
          <Input
            type="file"
            onChange={handleFileChange}
            style={{ display: disabled ? 'none' : 'inline-block' }}
            accept="*.apk"
          />
        </a>
      </div>
      {sourceFile?.name && (
        <Card
          title={sourceFile?.name}
          size="small"
          extra={
            <Space>
              <Button
                disabled={disabled}
                type="primary"
                shape="round"
                onClick={handleUpload}
                size="small"
                loading={importLoading}
                key="uploadButton"
              >
                <CloudUploadOutlined />
                上传
              </Button>
              {/* <Button type="primary" shape="round" onClick={handlePause} size="small" key="uploadPause">
                暂停
              </Button>
              <Button type="primary" shape="round" onClick={handleResume} size="small" key="uploadContinue">
                继续
              </Button> */}
            </Space>
          }
        >
          {/* <Progress
            percent={Number(percentageTotal.toFixed(2))}
            size="small"
            status={progressStatus || 'normal'}
          /> */}
          <ProgressBox
            chunkList={chunksData}
            progressStatus={progressStatus || 'normal'}
            size={sourceFile.size}
          />
        </Card>
      )}
    </div>
  );
};
 
export default UpLoadFileChunk;

  

不太重要的样式文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@import '~antd/es/style/themes/default.less';
 
.file {
  position: relative;
  display: inline-block;
  height: 32px;
  padding: 0 12px;
  overflow: hidden;
  color: rgba(0, 0, 0, 0.85);
  font-size: 14px;
  line-height: 32px;
  background: #fff;
  border: 1px solid #d9d9d9;
 
  input {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 0;
    opacity: 0;
  }
 
  &:hover {
    color: #40a9ff;
    border-color: #40a9ff;
  }
 
  &-disabled {
    color: rgba(0, 0, 0, 0.25);
    background: #f5f5f5;
    border-color: #d9d9d9;
 
    input {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      z-index: 0;
      opacity: 0;
    }
  }
}

  

进度条文件:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import type { FC } from 'react';
import { useMemo } from 'react';
import { Progress } from 'antd';
 
export type ProgressBoxProps = {
  chunkList?: any[];
  progressStatus?: 'success' | 'exception' | 'active' | 'normal';
  size?: number;
};
 
const ProgressChunk: FC<ProgressBoxProps> = ({
  chunkList = [],
  progressStatus = 'normal',
  size = 0,
}) => {
  const sumProgress = useMemo(() => {
    if (chunkList.length === 0) return 0;
    return (chunkList.reduce((pre, cur) => pre + cur.progress / 100, 0) * 100) / chunkList.length;
    // const loaded = chunkList
    //   .map((item) => item.size * item.percentage)
    //   .reduce((acc, cur) => acc + cur);
    // return parseInt((loaded / size).toFixed(2));
 
    // return (
    //   (chunkList.reduce((pre, cur: { progress: number }) => pre + cur.progress / 100, 0) * 100) /
    //   chunkList.length
    // );
  }, [chunkList, size]);
 
  return (
    <Progress
      percent={Number(sumProgress.toFixed(2))}
      size="small"
      status={progressStatus || 'normal'}
    />
  );
};
 
export default ProgressChunk;

  

request文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { getToken } from '@/utils/token';
 
export type Props = {
  url?: string;
  method?: string;
  data?: any;
  file?: any;
  onProgress?: any;
  requestList?: any[];
};
 
const request = (props: Props) => {
  const { url, method = 'post', data, onProgress } = props;
  return new Promise((resolve) => {
    const xhr = new XMLHttpRequest();
    const { pathname } = window.location;
    const headers = {
      ...(getToken() ? { Authorization: `Bearer ${getToken()}` } : {}),
      'refer-uri': pathname,
    };
 
    xhr.open(
      method,
      `http://172.16.7.77:8080${url}`,
      // process.env.NODE_ENV === 'production' ? `//xxxxx${url}` : `//xxxxxx:8080${url}`,
    );
    Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key]));
    xhr.upload.onprogress = onProgress;
    xhr.send(data);
    xhr.onload = (e: any) => {
      // 将请求成功的 xhr 从列表中删除
      // if (requestList) {
      //   const xhrIndex = requestList.findIndex(item => item === xhr);
      //   requestList.splice(xhrIndex, 1);
      // }
 
      resolve({
        data: e?.target?.response,
      });
    };
    // 暴露当前 xhr 给外部
    // requestList?.push(xhr);
  });
};
 
export default request;

  

 

public文件夹下的hash文件和md5文件:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 导入脚本
self.importScripts('/spark-md5.min.js');
 
// 生成文件 hash
self.onmessage = e => {
  const {
    chunkList
  } = e.data;
  const spark = new self.SparkMD5.ArrayBuffer();
  let percentage = 0;
  let count = 0;
  const loadNext = (index) => {
    const reader = new FileReader();
    reader.readAsArrayBuffer(chunkList[index].chunk);
    reader.onload = (event) => {
      count++;
      spark.append(event.target.result);
      if (count === chunkList.length) {
        self.postMessage({
          percentage: 100,
          hash: spark.end(),
        });
        self.close();
      } else {
        percentage += 100 / chunkList.length;
        self.postMessage({
          percentage,
        });
        loadNext(count);
      }
    };
  };
  loadNext(count);
};

  

1
(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<<s|a>>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64<n?a.subarray(i-64):new Uint8Array(0);length=a.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i<length;i+=1){tail[i>>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i<x.length;i+=1){x[i]=rhex(x[i])}return x.join("")}if(hex(md51("hello"))!=="5d41402abc4b2a76b9719d911017c592"){add32=function(x,y){var lsw=(x&65535)+(y&65535),msw=(x>>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i<length;i+=1){arr[i]=str.charCodeAt(i)}return returnUInt8Array?arr:buff}function arrayBuffer2Utf8Str(buff){return String.fromCharCode.apply(null,new Uint8Array(buff))}function concatenateArrayBuffers(first,second,returnUInt8Array){var result=new Uint8Array(first.byteLength+second.byteLength);result.set(new Uint8Array(first));result.set(new Uint8Array(second),first.byteLength);return returnUInt8Array?result:result.buffer}function hexToBinaryString(hex){var bytes=[],length=hex.length,x;for(x=0;x<length-1;x+=2){bytes.push(parseInt(hex.substr(x,2),16))}return String.fromCharCode.apply(String,bytes)}function SparkMD5(){this.reset()}SparkMD5.prototype.append=function(str){this.appendBinary(toUtf8(str));return this};SparkMD5.prototype.appendBinary=function(contents){this._buff+=contents;this._length+=contents.length;var length=this._buff.length,i;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk(this._buff.substring(i-64,i)))}this._buff=this._buff.substring(i-64);return this};SparkMD5.prototype.end=function(raw){var buff=this._buff,length=buff.length,i,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash.slice()}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64<length?new Uint8Array(buff.buffer.slice(i-64)):new Uint8Array(0);return this};SparkMD5.ArrayBuffer.prototype.end=function(raw){var buff=this._buff,length=buff.length,tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],i,ret;for(i=0;i<length;i+=1){tail[i>>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5});

  

 

posted @   芝麻小仙女  阅读(927)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2020-07-08 react+andt+Steps 步骤条改造【计划开始时间/计划截止时间/实际开始时间/实际结束时间】
点击右上角即可分享
微信分享提示