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

使用Python實(shí)現(xiàn)大文件切片上傳及斷點(diǎn)續(xù)傳的方法

 更新時(shí)間:2025年01月09日 08:49:45   作者:ZZZ_Tong  
本文介紹了使用 Python 實(shí)現(xiàn)大文件切片上傳及斷點(diǎn)續(xù)傳的方法,包括功能模塊劃分(獲取上傳文件接口狀態(tài)、臨時(shí)文件夾狀態(tài)信息、切片上傳、切片合并)、整體架構(gòu)流程、技術(shù)細(xì)節(jié)(相關(guān)接口和功能的代碼實(shí)現(xiàn)),最后進(jìn)行了小結(jié),需要的朋友可以參考下

概要

本文使用python實(shí)現(xiàn)大文件切片上傳,并支持?jǐn)帱c(diǎn)續(xù)傳,將功能劃分為:獲取上傳文件接口狀態(tài)、獲取臨時(shí)文件夾狀態(tài)信息、切片上傳、切片合并四個功能模塊。提供了詳細(xì)的思路和功能源碼。

整體架構(gòu)流程

步驟示例: 1.前端收到用戶的上傳的文件后,會執(zhí)行以下操作:

  • 計(jì)算文件哈希值:通過特定算法,算出該文件的hash值。
  • 向后端傳參:將文件路徑(包括文件名)、目標(biāo)機(jī)器id、文件hash值、用戶id,一并傳遞給后端判斷文件狀態(tài)接口get_file_upload_status。

后端收到前端傳來的數(shù)據(jù)后,按如下邏輯進(jìn)行處理: 檢查文件是否已經(jīng)存在:判斷該文件是否存在,如果已存在,則返回前端讓用戶選擇是否覆蓋文件。 檢查Redis中上傳記錄:如果不存在則進(jìn)一步判斷redis中是否有該文件正在上傳的記錄。

  • 無上傳記錄:如果沒有則使用redis String數(shù)據(jù)類型進(jìn)行存儲文件上傳狀態(tài),key為"機(jī)器_id + 文件路徑(例如118/tmp/123.jpg)",value為自制一個
{
'hash_code': 文件hash值,
'person_id': 用戶_id
}
  • 有上傳記錄:如果redis中存在正在上傳的記錄,則比對用戶id是否為同一個人,是則可以斷點(diǎn)續(xù)傳,否則阻止其他人上傳。

2.當(dāng)文件狀態(tài)通過后,前端會調(diào)用get_file_dir_info接口,并傳入主機(jī)_id、用戶_id、文件路徑(包括文件名)。 get_file_dir_info接口主要有三個功能:

  • 檢查臨時(shí)文件夾:判斷用于存放切片的 “臨時(shí)文件夾” 是否存在。臨時(shí)文件夾的完整路徑由 “文件路徑 + : + 用戶 id” 拼接而成,例如 “/tmp/123.jgp:12”。若該文件夾不存在,系統(tǒng)會自動創(chuàng)建它。創(chuàng)建完成后,對臨時(shí)文件夾路徑進(jìn)行哈希計(jì)算,再借助 Redis 存儲相關(guān)信息,以哈希值作為 key,臨時(shí)文件夾的全路徑作為 value,方便后續(xù)執(zhí)行刪除文件夾操作時(shí)快速定位。
  • 檢查切片上傳記錄臨時(shí)文件:查看 “臨時(shí)文件夾” 下的 “切片上傳記錄臨時(shí)文件” 是否已經(jīng)存在。如果文件存在,就讀取其中的內(nèi)容;要是不存在,就對其內(nèi)容進(jìn)行初始化。“臨時(shí)記錄文件”內(nèi)容如下:
class FileObject():
    def __init__(self,name,size,chunk,path=None,num=0):
        self.name = name #文件名
        self.size = size #文件夾已上傳大小
        self.chunk = chunk #塊數(shù)
        self.path = path # 路徑
        self.num = num #文件夾下存在分塊數(shù),設(shè)計(jì)冗余了
  • 放置合并腳本:在臨時(shí)文件夾下放置 merge.py 腳本文件,為后續(xù)的文件處理流程提供支持。

最后遍歷整個臨時(shí)文件夾,獲得一個文件已上傳塊數(shù)的列表(為了支持?jǐn)帱c(diǎn)續(xù)傳),返回給前端臨時(shí)記錄文件信息、臨時(shí)文件夾的hash值、已上傳的文件塊列表。

3.前端將文件按照10M進(jìn)行切片,并按照上述接口得到的信息(文件名、已上傳的文件塊列表),進(jìn)行續(xù)傳或直接傳輸file_chunk_upload,通過列表中的信息可跳過已上傳的文件塊,并可補(bǔ)上中間因?yàn)槠渌騺G失的塊。 4.上傳完成后前端會再次調(diào)用get_file_dir_info接口,獲得當(dāng)前文件夾下已存在的文件塊數(shù)量與列表,與自己分塊進(jìn)行對比。如果成功則調(diào)用合并文件接口。 5.前端發(fā)起合并請求時(shí),會調(diào)用 bigfile_merge 接口,同時(shí)傳入用戶 id、文件塊數(shù)、文件路徑以及臨時(shí)文件夾路徑這些關(guān)鍵參數(shù)。 后端在接收到前端傳來的數(shù)據(jù)后,展開一系列校驗(yàn)與操作:

  • 參數(shù)校驗(yàn):對傳入的路徑與文件塊數(shù)進(jìn)行準(zhǔn)確性核查,如果正確則開始合并。
  • 合并方式選擇:合并功能主要分兩種執(zhí)行路徑。一是檢測目標(biāo)機(jī)器是否支持運(yùn)行 merge.py 腳本,若支持,便直接執(zhí)行已傳入的腳本完成合并;若不支持,則執(zhí)行目標(biāo)機(jī)器文件的操作方法來執(zhí)行合并。
  • 斷點(diǎn)續(xù)合判斷:開始合并前,要先確認(rèn)需要合并的文件是否已經(jīng)存在。若文件已存在,意味著這是一個斷點(diǎn)文件,此時(shí)需讀取臨時(shí)記錄文件中的 size 和 chunk 值,從而判斷文件的實(shí)際大小以及已合并的塊位置。一旦發(fā)現(xiàn)實(shí)際文件大小超過記錄文件中的數(shù)值,就表明合并過程曾出現(xiàn)中斷,此時(shí)要把文件指針調(diào)整到記錄值對應(yīng)的位置,接著從該記錄值對應(yīng)的塊開啟后續(xù)合并。
  • 記錄更新 :每成功完成一塊文件的合并,就把新的 size 與 chunk 值寫入臨時(shí)記錄文件。
  • 收尾清理:合并完成后清除臨時(shí)文件夾,并刪除redis中該文件上傳記錄狀態(tài)信息。

到此完成一次文件上傳操作

技術(shù)細(xì)節(jié)

  • API

獲取上傳文件狀態(tài)接口

get_file_upload_status 查看需要上傳的文件是否存在或斷點(diǎn)續(xù)

class FileUploadStatus(APIView):
    
    def post(self, request, *args, **kwargs):
        
        #先判斷目標(biāo)地址下是否存在該文件
        #如果存在則提示是否需要覆蓋
        try:
            forms = json.loads(request.body)
            host_id = forms['host_id']
            
            full_path = forms['full_path']
            hash_code = forms['hash_code']
            person_id = forms['person_id']
        except Exception as e:
            logger.error("前端參數(shù)解析出錯",repr(e))
        try:
            err, tmp_sftp = RemoteBigFileUploadHandler.get_handle(host_id) #使用paramiko模塊獲取目標(biāo)機(jī)器連接,這里讀者自行用其他方式都可以
            if err:
                return Response({'code': -1, 'data': host_id, 'msg': "連接目標(biāo)主機(jī)出錯"}, status=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            logger.error("連接目標(biāo)機(jī)器失敗",repr(e))
        
        try:
            #判斷機(jī)器上文件是否存在
            tmp_sftp._sftp.stat(full_path)
            return Response({'code': -1, 'data': full_path, 'msg': "文件已存在,通知是否覆蓋"}, status=status.HTTP_400_BAD_REQUEST)
        except IOError:
            #其次判斷是否存在在redis中,防止短時(shí)間內(nèi)有相同的人傳同一份文件,但前一個人并沒有合并完成
            #如果都沒有則創(chuàng)建新key hashcode放入redis,并通知前端可以上傳
            try:
                r = get_redis() #獲得redis連接實(shí)例,讀者自行實(shí)現(xiàn)
            except Exception as e:
                logger.error("redis獲取失敗",repr(e))
            #例如:18115/app/home/202.jpg
            #獲取redis中記錄
            data = r.get(str(host_id)+full_path)
            if not data:
                #將key和hashcode放入redis
                #加上person_id 
                file_dict = {}
                file_dict['hash_code'] = hash_code
                file_dict['person_id'] = person_id
                r.set(str(host_id)+full_path, str(file_dict))
                return Response({'code': 1, 'data': full_path, 'msg': "文件不存在,可以上傳"}, status=status.HTTP_200_OK)
            else:
                #如果redis中有記錄,host_id+路徑能夠攔截在目標(biāo)機(jī)器傳輸同一份文件,但也會把同一個人想斷點(diǎn)傳輸攔截
                #所以在此key的value中保存帶有person_id的臨時(shí)文件夾路徑信息
                #使用person_id將同一個人放行
                retrieved_data = r.get(str(host_id)+full_path)

                # 將獲取到的數(shù)據(jù)轉(zhuǎn)換為字典對象
                try:
                    retrieved_dict = eval(retrieved_data.decode())
                except Exception as e:
                    logger.error("redis獲取目標(biāo)文件hashcode解碼失敗",repr(e))
                if person_id ==retrieved_dict['person_id']:
                    return Response({'code': 1, 'data': full_path, 'msg': "斷點(diǎn)續(xù)傳判斷通過"}, status=status.HTTP_200_OK)
                else:
                    return Response({'code': 2, 'data': full_path, 'msg': "該文件正在上傳,請勿多次操作"}, status=status.HTTP_200_OK)

獲取臨時(shí)文件夾狀態(tài)信息接口

get_file_dir_info 獲取臨時(shí)文件夾狀態(tài)信息接口

class GetFileDirInfo(APIView):
    
    def post(self, request, *args, **kwargs):
        forms = json.loads(request.body)
        host_id = forms['host_id']
        person_id = forms['person_id']
        full_path = forms['full_path']
        err, tmp_sftp = RemoteBigFileUploadHandler.get_handle(host_id)#使用paramiko模塊獲取目標(biāo)機(jī)器連接,這里讀者自行用其他方式都可以
        if err:
            return Response({'code': -1, 'data': host_id, 'msg': "連接目標(biāo)主機(jī)出錯"}, status=status.HTTP_400_BAD_REQUEST)
        #分離路徑名與文件名
        #示例:/home/app  2-2.jpg
        file_path,file_name = os.path.split(full_path)
        if file_path[-1] != "/":
                file_path += "/"
        #分離文件名與文件擴(kuò)展名
        #示例:2-2 .jpg
        short_name,ext = os.path.splitext(file_name)
        #構(gòu)造存放臨時(shí)文件的文件夾名
        #示例:/home/app/2-2.jpg:12/   
        tmp_dir = full_path +":"+ str(person_id)
        #并將臨時(shí)文件夾做hashcode 傳入redis key為hashcode value為路徑,后續(xù)刪除文件夾操作多一層驗(yàn)證
        tmp = hashlib.md5()    
        tmp.update(tmp_dir.encode('utf-8'))
        hash_value = tmp.hexdigest()
        
        if tmp_dir[-1] != "/":
            tmp_dir += "/"
        try:
            #判斷臨時(shí)文件夾是否存在
            tmp_sftp._sftp.stat(tmp_dir)
        except Exception:
            try:
                print('創(chuàng)建臨時(shí)文件夾')
                tmp_sftp._sftp.mkdir(tmp_dir)
                r = get_redis() #獲取redis連接
                r.set(hash_value,tmp_dir)
                
            except Exception as e:
                logger.error("創(chuàng)建臨時(shí)文件夾失敗",e)
                tmp_sftp._sftp.close()
                return Response({'code': -1, 'data': "", 'msg': "創(chuàng)建臨時(shí)文件夾失敗"}, status=status.HTTP_400_BAD_REQUEST)
        #如果臨時(shí)文件夾存在則在此文件夾下獲取文件傳輸txt
        #初始化記錄文件對象
        fobject = FileObject(file_name,0,0,tmp_dir,0)
        #示例:/home/app/2-2.jpg:12/2-2.txt  
        record_file = tmp_dir+short_name+".txt"
        try:
            #判斷記錄文件是否存在
            tmp_sftp._sftp.stat(record_file)
            tmp_load_file = tmp_sftp._sftp.open(record_file,'r')
            #如果記錄文件夾存在則讀取其已保存上傳文件大小和塊數(shù)
            for line in tmp_load_file.readlines():
                title,value = line.replace('\n','').split(':')
                print(title + ":"+ value)
                if title=='name':
                    fobject.name = value
                elif title=='size':
                    fobject.size = int(value)
                elif title =='chunk':
                    fobject.chunk = int(value)
            tmp_load_file.close()
        except IOError:
            print("記錄文件不存在,創(chuàng)建新的記錄文件,并初始化")
            store_f=tmp_sftp._sftp.open(record_file,'w+')
            store_f.writelines(['name:'+fobject.name+'\n','size:'+str(fobject.size)+'\n',
                                'chunk:'+str(fobject.chunk)+'\n'])
            print("創(chuàng)建記錄文件成功")
            store_f.close()
            
            serializer = RecordFileSerializer(fobject)
            data = serializer.data
            data['dir_hashcode'] = hash_value
            
            
            #上傳一個支持異步合并的merge.py文件
            command = 'command -v python'
            stdin, stdout, stderr = tmp_sftp._ssh.exec_command(command)
            output = stdout.read().decode().strip()
            try:
                print('判斷merge在不在')
                tmp_sftp._sftp.stat(tmp_dir + 'merge.py')
            except Exception as e:
                if output:
                    print('目標(biāo)機(jī)器已安裝 Python')
                    current_path = os.path.dirname(os.path.abspath(__file__))
                    if current_path[-1] != "/":
                        current_path += "/"
                    try:
                        print('需要傳輸?shù)牡刂?,current_path+'merge.py')
                        print('目標(biāo)地址',tmp_dir + 'merge.py')
                        tmp_sftp._sftp.put(current_path+'merge.py',tmp_dir + 'merge.py')
                    except Exception as e:
                        logger.error("發(fā)送本地合并文件失敗",e)
                        tmp_sftp._sftp.close()
                        return Response({'code': -1, 'data': "", 'msg': "發(fā)送本地合并文件失敗"}, status=status.HTTP_400_BAD_REQUEST)
                    #將merge文件發(fā)送
                else:
                    tmp_sftp._sftp.close()
                    return Response({'code': -1, 'data': "", 'msg': "目標(biāo)機(jī)器未安裝python"}, status=status.HTTP_400_BAD_REQUEST)
            tmp_sftp._sftp.close()
            return Response({'code': 0, 'data': data, 'msg': "創(chuàng)建新記錄文件"}, status=status.HTTP_200_OK)
        
        file_list = tmp_sftp._sftp.listdir(tmp_dir)
        #文件夾下有一個txt記錄文件,總文件塊數(shù)需要減一
        fobject.num = len(file_list)-2
        chunk_list =[]
        for file in file_list:
            parts = file.rsplit(":", 1)  # 按冒號從右到左分割為最多兩個部分

            if len(parts) == 2:
                last_part = parts[1]  # 獲取最后一個部分
                try:
                    chunk_list.append(int(last_part))
                except Exception as e:
                    continue
                print("最后一個值:", last_part)
            else:
                print("未找到冒號,跳過")
        serializer = RecordFileSerializer(fobject)
        data = serializer.data
        data['dir_hashcode'] = hash_value
        data['chunk_list'] = chunk_list
        return Response({'code': 0, 'data': data, 'msg': "記錄文件已存在"}, status=status.HTTP_200_OK) 

切片上傳功能

file_chunk_upload 切片上傳功能

class FileChunkUploadHandler():
    
    def __init__(self, redis_host,request=None,file_info=None,chunk_num=0,people_id =0):
        self.request = request
        self.file_info = request.FILES.get('file_info')
        # forms = json.loads(request.body)
        #數(shù)據(jù)塊信息
        
        #第幾個數(shù)據(jù)塊
        self.chunk_num = request.data.get('chunk_num')
        self.full_path = request.data.get('full_path')
        self.person_id = request.data.get('person_id')
        self.redis_host = redis_host
    
    
    def upload_file(self):
        print("%s號文件塊開始傳輸",self.chunk_num)
        full_path = urllib.parse.unquote(self.full_path)
        file_path,file_name = os.path.split(full_path)
        host_id = self.request.query_params.get('host_id', None)
        err, tmp_sftp = RemoteBigFileUploadHandler.get_handle(host_id)
        #分離擴(kuò)展名和文件名
        #2-2  .jpg
        short_name,ext = os.path.splitext(file_name)
        if file_path[-1] != "/":
            file_path += "/"
        #存放臨時(shí)文件的文件夾,在上一個獲取臨時(shí)文件夾狀態(tài)接口就已創(chuàng)建,按照相同格式做一次校驗(yàn)。
        #/home/app/2-2.jpg:12
        tmp_dir = file_path+file_name+":"+ str(self.person_id)
        if tmp_dir[-1] != "/":
            tmp_dir += "/"
        #臨時(shí)文件名
        #/home/app/2-2.jpg:12/12-2-2:1
        tmp_file_name = tmp_dir + str(self.person_id) + "-"  + short_name + ":" + str(self.chunk_num)
        
        try:
            tmp_sftp._sftp.stat(tmp_dir)
        except IOError as e:
            logger.error("存儲臨時(shí)文件夾不存在",e)
            return 0,repr(e)
        
        try:
            tmp_sftp._sftp.stat(tmp_file_name)
        except IOError:
            try:
                #文件塊上傳存放
                print('創(chuàng)建臨時(shí)文件塊',tmp_file_name)
                remote_file = tmp_sftp._sftp.open(tmp_file_name, mode="wb")
                my_bytes = self.file_info.read()     
                remote_file.write(my_bytes)
                remote_file.close()
            except Exception as e:
                logger.error("上傳文件塊失敗",e)
                return 0,repr(e)
            print("寫入文件完成:",tmp_file_name)
        record_file = tmp_dir+short_name+".txt"
            
        #更新上傳記錄文件信息
        fobject = FileObject(file_name,0,0)
        tmp_load_file = tmp_sftp._sftp.open(record_file,'r')
        for line in tmp_load_file.readlines():
            title,value = line.replace('\n','').split(':')
            print(title + ":"+ value)
            if title=='name':
                fobject.name = value
            elif title=='size':
                fobject.size = int(value)
            elif title =='chunk':
                fobject.chunk = int(value)
        tmp_load_file.close()
        
        try:
            tmp_sftp._sftp.stat(record_file)
            load_file = tmp_sftp._sftp.open(record_file,'w+')
            load_file.writelines(['name:'+fobject.name+'\n','size:'+str(fobject.size)+'\n',
                            'chunk:'+str(0)+'\n'])
        except Exception as e:
            logger.error(e)
        tmp_sftp.close()
        return 1,None

文件合并功能

bigfile_merge 文件合并與校驗(yàn)功能

class RemoteBigFileUploadHandler():
    
    def __init__(self, redis_host,request=None, chat=False,tmp_path=None,chunk_num=0,person_id=0):
        self.request = request
        forms = json.loads(request.body)
        self.chat = chat
        #數(shù)據(jù)塊大小
        # self.chunk_size = forms['chunk_size']
        self.tmp_path = forms['tmp_path']
        #數(shù)據(jù)塊數(shù)量
        self.chunk_num = forms['chunk_num']
        self.full_path = forms['full_path']
        self.person_id = forms['person_id']
        self.redis_host = redis_host
        
        if self.chat:
            self.current = 0
            self.datetime = datetime.datetime.now()
            #數(shù)據(jù)進(jìn)度聊天室
            self.channel_layer = get_channel_layer()
            self.room = self.request.query_params.get('chat_room', None)
            self.total = self.request.query_params.get('total', None)
            if not self.room or not self.total:
                raise KeyError('params: chat_room and total is needed')
            
    
    def file_isavailable(self):
        
        tmp_path = self.tmp_path
        tmp_sftp = self.get_session()
        file_list = tmp_sftp._sftp.listdir(tmp_path)
        #文件夾下有一個txt記錄文件,總文件塊數(shù)需要減一
        true_num = len(file_list)-2
        if true_num!=self.chunk_num:
            tmp_sftp._sftp.close()
            return False
        else:
            tmp_sftp._sftp.close()
            return True
    
    def merge_file(self):
        #----------------------獲得基礎(chǔ)信息-----------------------------------
        host_id = self.request.query_params.get('host_id', None)
        full_path = urllib.parse.unquote(self.full_path)
        file_path,file_name = os.path.split(full_path)
        if file_path[-1] != "/":
            file_path += "/"
        #分離擴(kuò)展名和文件名
        short_name,ext = os.path.splitext(file_name)
        
        tmp_path = self.tmp_path
        tmp_sftp = self.get_session()
        
        
        file_list = tmp_sftp._sftp.listdir(tmp_path)
        try:
            tmp_sftp._sftp.stat(full_path)
            print("文件已存在")
        except IOError:
            print("文件不存在")
            print("創(chuàng)建新的文件")
            new_f = tmp_sftp._sftp.open(full_path,mode='a')
            new_f.write("")
            new_f.close()
        #判斷merge.py 文件是否存在
        if 'merge.py' in file_list:
            com_path = tmp_path + 'merge.py'
            command = f"nohup python {com_path} {self.person_id} {self.chunk_num} &"
            stdin, stdout, stderr = tmp_sftp._ssh.exec_command(command)
            merging = True
            
            while merging:
                if self.chat:
                    # websocket回顯進(jìn)度,獲得當(dāng)前文件字節(jié)數(shù)
                    self.current = tmp_sftp._sftp.stat(full_path).st_size
                    print('current',self.current)
                    print('total',self.total)
                    self.call_back()
                    if self.current >= int(self.total):
                        merging = False
                    time.sleep(1)
                else :
                    merging = False
        else:
        #創(chuàng)建或打開用戶的存儲文件
            
                
            # ----------------開始合并操作-------------------------------
            # rb+ 追加覆蓋的方式打開用戶需要存儲文件,指針初始位置為文件開頭
            remote_file = tmp_sftp._sftp.open(full_path,mode='rb+')
            
            #默認(rèn)當(dāng)前塊數(shù)從1開始
            i=1
            #創(chuàng)建文件記錄對象
            fobject = FileObject(file_name,0,0)
            print('創(chuàng)建記錄對象成功')
            # 斷點(diǎn)續(xù)傳記錄文件
            record_file = tmp_path+short_name+".txt"
            try :
                #如果記錄文件存在,則存儲文件大概率也存在
                #如果兩個文件打開出錯 則走excpt重新創(chuàng)建
                tmp_sftp._sftp.stat(record_file)
                upload_file = tmp_sftp._sftp.stat(full_path)
                
                #這里也是獲取本地文件的大小
                temp_size = upload_file.st_size
                print("記錄文件已存在")
                print("當(dāng)前文件真實(shí)數(shù)據(jù)大?。?,temp_size)
                # 讀取文件,獲得記錄的已上傳塊數(shù),以及大小總塊數(shù)
                tmp_load_file = tmp_sftp._sftp.open(record_file,'r')
                for line in tmp_load_file.readlines():
                    title,value = line.replace('\n','').split(':')
                    print(title + ":"+ value)
                    if title=='name':
                        fobject.name = value
                    elif title=='size':
                        fobject.size = int(value)
                    elif title =='chunk':
                        fobject.chunk = int(value)
                tmp_load_file.close()
            except IOError:
                print("記錄文件不存在,創(chuàng)建新的記錄文件,并初始化")
                temp_size = 0
                store_f=tmp_sftp._sftp.open(record_file,'w+')
                store_f.writelines(['name:'+fobject.name+'\n','size:'+str(fobject.size)+'\n',
                                    'chunk:'+str(fobject.chunk)+'\n'])
                print("創(chuàng)建記錄文件成功")
                store_f.close()
                    
            #    ----------------------------------開始保存數(shù)據(jù)--------------------------
            print("真實(shí)文件數(shù)據(jù)大小",temp_size)
            print("記錄文件數(shù)據(jù)大小",fobject.size)
            if temp_size>=fobject.size:
                #如果實(shí)際文件大于記錄文件,則表示在合并時(shí)中斷過
                print("調(diào)整指針")
                remote_file.seek(fobject.size)
                i = fobject.chunk+1
            
            tmp_file_name = str(self.person_id) + "-"  + short_name + ":"
            try:
                while i<=self.chunk_num:
                    if  tmp_file_name + str(i) in file_list:
                        print('true')
                        #臨時(shí)文件夾/臨時(shí)文件名
                        file_path = tmp_path+tmp_file_name + str(i)
                        with tmp_sftp._sftp.file(file_path,'rb') as input_file:
                            print(file_path)
                            file_content = input_file.read()
                            remote_file.write(file_content)
                            fobject.size += len(file_content)
                    i = i+1
                    fobject.chunk += 1
                    if self.chat:
                        # websocket回顯進(jìn)度,獲得當(dāng)前文件字節(jié)數(shù)
                        self.current = tmp_sftp._sftp.stat(full_path).st_size
                        print('current',self.current)
                        print('total',self.total)
                        self.call_back()
                    #將已經(jīng)寫入的塊和大小記錄
                    load_file = tmp_sftp._sftp.open(record_file,'w+')
                    load_file.writelines(['name:'+fobject.name+'\n','size:'+str(fobject.size)+'\n',
                                            'chunk:'+str(fobject.chunk)+'\n'])
                    load_file.close()
                    
            except Exception as e:
                logger.error("合并文件異常",e)
                #----------------清除臨時(shí)文件與關(guān)閉資源操作----------
                #刪除臨時(shí)文件夾下的所有文件
            remote_file.close()
        try:
            for name in file_list:
                del_path = tmp_path  + name
                tmp_sftp._sftp.remove(del_path)
                # 刪除空臨時(shí)文件夾
            tmp_sftp._sftp.rmdir(tmp_path)
        except Exception as e:
            logger.error("刪除文件文件異常",e)
        
        #關(guān)閉操作文件資源    
            
        tmp_sftp._sftp.close()
        #刪除redis中該文件臨時(shí)記錄,一個是文件夾hashcode,用于驗(yàn)證與刪除目標(biāo)文件夾
        #一個是host_id+路徑,用于標(biāo)記該路徑下這個文件正在傳輸
        r = self.redis_host
        data = r.get(str(host_id)+full_path)
        if data:
            r.delete(str(host_id)+full_path)
        tmp = hashlib.md5()    
        tmp.update(tmp_path.encode('utf-8'))
        hash_value = tmp.hexdigest()
        r.delete(hash_value)
        print("文件合并結(jié)束")
        return 1,None

小結(jié)

本文提供了一個python大文件上傳功能實(shí)現(xiàn)的思路,希望能夠你帶來一些思路和啟發(fā)。

以上就是使用Python實(shí)現(xiàn)大文件切片上傳及斷點(diǎn)續(xù)傳的方法的詳細(xì)內(nèi)容,更多關(guān)于Python大文件切片上傳及斷點(diǎn)續(xù)傳的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論