服务端功能
上传分片保存
@app.route('/upload_filesliceprocess', methods=['POST'])
def upload_filesliceprocess():
file = request.files['file']
name_index = request.form['name_index']
complete = request.form['complete']
process = request.form['process']
clienthash = request.form['clienthash']
source_name = request.form['filename']
filename = ''.join(source_name.split('.')[0:-1])
file_path = fr'{SLICE_DATA}/{filename}'
p_file_path = pd.Path(file_path)
if not pd.Path.exists(p_file_path):
os.makedirs(p_file_path)
fileindex=fr'{file_path}/{name_index}'
filename=fr'{file_path}/{name_index}'
if(os.path.exists(fileindex)==False):
file.save(filename)
import utils
hashserver=utils.calculate_md5(filename)
if(clienthash==hashserver):
return 'ok'
else:
return 'error'
print(f'process:{round(float(process)*100, 2)}%')
合并分片功能
@app.route('/merge_file', methods=['POST'])
def merge_file():
print('-------------------------------')
filename = request.form['filename']
print(filename)
#splitfile=os.path.splitext(filename)
#filename=splitfile[0]
#ext=splitfile[1]
filename, ext = os.path.splitext(filename)
ext=ext.replace('.','')
file_path= fr'{SLICE_DATA}/{filename}'
combination_fun(file_path,filename,ext)
return 'ok'
合并文件函数
def combination_fun(folder_path, source_name,ext):
com_path = pd.Path(COMBINATION_DATA)
if not pd.Path.exists(com_path):
os.makedirs(com_path)
ready_folder = os.listdir(folder_path)
ready_sort_folder = sorted(ready_folder, key=lambda x: int(x.split('_')[-1]))
with open(f'{COMBINATION_DATA}/{source_name}.{ext}', 'wb') as write_f:
for item in ready_sort_folder:
slice_item = os.path.join(folder_path, item)
print(slice_item)
with open(slice_item, "rb") as read_f:
content = read_f.read()
write_f.write(content)
#删除缓存文件
for item in ready_sort_folder:
slice_item = os.path.join(folder_path, item)
os.remove(slice_item)
前端
引用库 jquery Md5
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
上传简单界面
<input type="file" name="file" id="file">
<button id="upload" onClick="uploadfile()">upload</button>
<button id="mergedata" onClick="uploadcomplete()">mergedata</button>
<div class="rate_div" >
上传进度:<span id="rate_nums">0</span>
<progress id="downloadProgress" value="0" max="100"></progress>
</div>
上传脚本
<script type="text/javascript">
var totalPieces=0;
var nowUploadNums = 0;
const MAX_RETRIES = 5; // 最大重试次数
const CHUNK_SIZE = 100*1024 * 1024; // 1MB 分片大小
let arr = [];
let retries=[];
//发送请求
function displayProgress(percent) {
document.getElementById('downloadProgress').value = percent;
}
function mergedata()
{
var blob = document.getElementById("file").files[0];
var filesize = blob.size;
var filename = blob.name;
}
function setRate(num) {
var rateNums = document.getElementById('rate_nums');
rateNums.innerHTML = num;
}
function uploadcomplete()
{
nowUploadNums ++;
if(nowUploadNums >=totalPieces)
{
console.log('true')
var blob = document.getElementById("file").files[0];
var filename = blob.name;
var formData = new FormData();
formData.append("filename", filename);
$.ajax({
url: '/merge_file',
type: 'POST',
cache: false,
data: formData,
processData: false,
contentType: false,
}).done(function(res){
alert('合并成功');
}).fail(function(res) {
alert('合并失败');
});
}
else{
console.log('false')
}
}
function uploadfile() {
var blob = document.getElementById("file").files[0];
var start = 0;
var end;
var index = 1;
var filesize = blob.size;
var filename = blob.name;
var complete = false;
nowUploadNums =0;
const totalChunks= Math.ceil(filesize / CHUNK_SIZE );
let uploadedChunks = 0;
let chunkRetries = {};
function updateProgress() {
document.getElementById('downloadProgress').value =Math.round((uploadedChunks / totalChunks) * 100);
}
function uploadNextChunk() {
if (uploadedChunks >= totalChunks) {
console.log('文件上传完成!');
updateProgress(); // 确保进度条显示100%
// 通知服务器所有分片都已上传,可以进行合并
return;
}
const start = uploadedChunks * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, blob.size);
const chunk = blob.slice(start, end);
const chunkIndex = uploadedChunks;
if (!chunkRetries[chunkIndex]) {
chunkRetries[chunkIndex] = 0;
}
const wordArray = CryptoJS.lib.WordArray.create(chunk );
const clienthash= CryptoJS.MD5(wordArray).toString()
uploadChunk(chunk, chunkIndex,filename ,clienthash,complete,uploadedChunks , totalChunks).then(() => {
uploadedChunks++;
updateProgress(); // 更新进度条
uploadNextChunk(); // 上传下一个分片
}).catch((error) => {
chunkRetries[chunkIndex]++;
console.error(`上传分片 ${chunkIndex} 失败: ${error.message}, 重试次数: {chunkRetries\[chunkIndex\]}/{MAX_RETRIES}`);
if (chunkRetries[chunkIndex] < MAX_RETRIES) {
// 等待一段时间后重试上传当前分片
setTimeout(uploadNextChunk, 1000); // 延迟1秒重试
} else {
console.error(`分片 ${chunkIndex} 上传失败,已达到最大重试次数`);
// 处理上传失败的情况,比如停止上传或通知用户
}
});
}
uploadNextChunk();
}
function uploadChunk(chunk, sliceIndex,filename,clienthash,complete,index,totalPieces) {
var formData = new FormData();
formData.append("file", chunk);
formData.append("name_index", sliceIndex);
formData.append("filename", filename);
formData.append("clienthash", clienthash);
formData.append("complete",complete);
formData.append("process", index / totalPieces);
return $.ajax({
url: '/upload_filesliceprocess', // 替换为你的上传URL
type: 'POST',
data: formData,
processData: false,
contentType: false,
// 可以设置timeout来处理请求超时的情况
});
}