shutil模塊和幾種文件上傳Demo
阿新 • • 發佈:2019-01-05
har app 3.3 文件信息 quest scrip struct function info
一、shutil模塊
1、介紹
shutil模塊是對os中文件操作的補充。--移動 復制 打包 壓縮 解壓
2、基本使用
1. shutil.copyfileobj(文件1, 文件2, 長度) 將文件1的數據覆蓋copy給文件2,可以copy指定大小的內容 文件1和2都是文件對象,都需要打開後才能進行復制操作 import shutil f1 = open(‘testdir/1.txt‘, ‘r‘, encoding=‘utf8‘) f2 = open(‘testdir/2.txt‘, ‘w‘, encoding=‘utf8‘) shutil.copyfileobj(f1, f2, length=1024) 2. shutil.copyfile(文件1,文件2) 不用打開文件,直接復制,實際上copyfile調用了copyfileobj import shutil # 1.txt必須要有,3.txt沒有就創建,有就覆蓋內容 shutil.copyfile(‘testdir/1.txt‘, ‘testdir/3.txt‘) 3. shutil.copymode(文件1,文件2) 僅copy權限,不更改文件內容,組和用戶 # 先看兩個文件的權限 $ ls -l -rw-r--r-- 1 Administrator 197121 5 1月 5 10:22 1.txt-rwxr-xr-x 1 Administrator 197121 8 1月 5 10:24 2.txt # 運行命令 import shutil shutil.copymode(‘testdir/1.txt‘, ‘testdir/2.txt‘) #查看結果 $ ls -l -rw-r--r-- 1 Administrator 197121 5 1月 5 10:22 1.txt -rw-r--r-- 1 Administrator 197121 8 1月 5 10:24 2.txt 4. shutil.copystat(src,dst) 復制所有的狀態信息,包括權限,組,用戶,時間等import shutil shutil.copystat(‘testdir/1.txt‘, ‘testdir/2.txt‘) #查看結果(時間都變了) $ ls -l -rw-r--r-- 1 Administrator 197121 5 1月 5 10:22 1.txt -rw-r--r-- 1 Administrator 197121 8 1月 5 10:22 2.txt 5. shutil.copy(src,dst) 復制文件的內容以及權限,先copyfile後copymode import shutil shutil.copy(‘testdir/1.txt‘, ‘testdir/2.txt‘) 6. shutil.copy2(src,dst) 復制文件的內容以及文件的所有狀態信息。先copyfile後copystat import shutil shutil.copy2(‘testdir/1.txt‘, ‘testdir/2.txt‘) 7. shutil.copytree(src, dst) 遞歸的復制文件內容及狀態信息(就是拷貝整個目錄) import shutil shutil.copytree(‘testdir‘, ‘testdir2‘) 結果 /testdir $ ls -l total 2 -rw-r--r-- 1 Administrator 197121 5 1月 5 10:22 1.txt -rw-r--r-- 1 Administrator 197121 8 1月 5 10:22 2.txt testdir2 $ ls -l total 2 -rw-r--r-- 1 Administrator 197121 5 1月 5 10:22 1.txt -rw-r--r-- 1 Administrator 197121 8 1月 5 10:22 2.txt 8. shutil.rmtree(path) 遞歸地刪除文件 import shutil shutil.rmtree(‘testdir2‘) 結果 testdir2目錄還在,但是裏面的文件全刪了,也就是testdir2現在是一個空文件夾 9. shutil.move(src, dst) 遞歸的移動文件 import shutil shutil.move(‘3.txt‘, ‘testdir‘) # 把3.txt移動到testdir這個文件夾下 10. make_archive(base_name, format, root_dir=None) 壓縮打包 base_name:壓縮打包後的文件名或者路徑名 format: 壓縮或者打包格式 "zip", "tar", "bztar"or "gztar" root_dir : 將哪個目錄或者文件打包(也就是源文件) import shutil shutil.make_archive(‘E:/MyProjects/test‘, ‘zip‘, root_dir=‘testdir‘) 把testdir這個目錄(文件也行)壓縮到E:/MyProjects目錄下,壓縮後的名字為test,格式為zip, 也就是說壓縮完成後,在E:/MyProjects下會生成一個test.zip包 11. 解壓 shutil 對壓縮包的處理是調用 ZipFile模塊來進行的 11-1、zipfile 壓縮解壓 # 壓縮 # 把testdir文件夾下的1.txt和2.txt壓縮到E:/MyProjects/test1.zip z = zipfile.ZipFile(‘E:/MyProjects/test1.zip‘, ‘w‘) # 可以用 a 模塊,那麽zip包裏面可以追加內容 z.write(‘testdir/1.txt‘) z.write(‘testdir/2.txt‘) z.close() # 解壓 import zipfile z = zipfile.ZipFile(‘E:/MyProjects/test1.zip‘, ‘r‘) z.extractall(‘E:/MyProjects/test111‘)#將E:/MyProjects/test1.zip解壓到E:/MyProjects/test111目錄下 # 高級應用 zipfile.is_zipfile(filename) 判斷一個文件是不是壓縮文件 ZipFile.namelist() 返回文件列表 ZipFile.open(name[, mode[, password]]) 打開壓縮文檔中的某個文件 11-2、使用shutil的內在方法解壓 shutil._unpack_zipfile(file, path) import shutil shutil._unpack_zipfile(‘E:/MyProjects/test1.zip‘, ‘E:/MyProjects/test1‘) # 把E:/MyProjects/test1.zip這個zip包解壓到E:/MyProjects/test1文件夾下
二、上傳Demo
1、socket上傳文件
import json import struct import socketserver import operate_handler class MyFTP(socketserver.BaseRequestHandler): def handle(self): conn = self.request length = conn.recv(4) length = struct.unpack(‘i‘,length)[0] operate = (conn.recv(length)).decode(‘utf-8‘) operate_dic = json.loads(operate) opt = operate_dic[‘operate‘] usr = operate_dic[‘user‘] print(opt,usr) getattr(operate_handler,opt)(conn,usr) socketserver.TCPServer.allow_reuse_address = True server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,9000),MyFTP) server.serve_forever()1. server.py
import os import json import struct base_path = r‘E:\PythonProject\ftp\server\root‘ def upload(conn,usr): fileinfo_len = conn.recv(4) fileinfo_len = struct.unpack(‘i‘,fileinfo_len)[0] fileinfo = (conn.recv(fileinfo_len)).decode(‘utf-8‘) fileinfo = json.loads(fileinfo) file_path = os.path.join(base_path,usr,fileinfo[‘filename‘]) file_path = os.path.abspath(file_path) with open(file_path,‘wb‘) as f: while fileinfo[‘filesize‘]: content = conn.recv(20480) fileinfo[‘filesize‘] -= len(content) f.write(content) print(‘接收完畢‘)2. operate_handler.py
import os import json import struct import socket # 發送信息 def my_send(sk,operate_info): b_optinfo = (json.dumps(operate_info)).encode(‘utf-8‘) num = struct.pack(‘i‘,len(b_optinfo)) sk.send(num) sk.send(b_optinfo) sk = socket.socket() sk.connect((‘127.0.0.1‘,9000)) # [登錄,註冊,退出] # 要進行的操作 operate_info = {‘operate‘:‘upload‘,‘user‘:‘xiaoming‘} my_send(sk,operate_info) # 選擇一個文發送到server端 file_path = r‘F:\電影\電影\荒野生存.mp4‘ # 發送文件信息 file_name = os.path.basename(file_path) file_size = os.path.getsize(file_path) file_info = {‘filename‘:file_name,‘filesize‘:file_size} my_send(sk,file_info) # server端接收寫入 with open(file_path,‘rb‘) as f: while file_size: content = f.read(20480) file_size -= len(content) sk.send(content) print(‘上傳完畢‘) sk.close()3. client.py
2、Django中使用form表單上傳文件
from django.shortcuts import render, HttpResponse, redirect from django import views import os, time from django.conf import settings class UploadView(views.View): def get(self, request): return render(request, ‘upload.html‘) def post(self, request): # 文本類型的數據用request.POST獲取,鍵對應的值是字符串類型 print(request.POST) # 文件類型的數據用request.FILES獲取,鍵對應的值是類的對象 print(request.FILES) # 獲取文件對象(是一大串bytes類型的字節碼) file_obj = request.FILES.get(‘file‘) # 文件對象有個內置的屬性name,用於獲取接收到的文件名 filename = file_obj.name # 判斷本地是否有同名的文件存在 if os.path.exists(os.path.join(settings.BASE_DIR, filename)): # 重命名文件 prefix_name = filename.split(‘.‘)[0] # 前綴 suffix_name = filename.split(‘.‘)[1] # 後綴 filename = prefix_name + str(time.time()) + suffix_name # 建一個同名的文件接收上傳的數據 # with open(filename, ‘wb‘) as f: # for i in file_obj: # f.write(i) # 跟上面的方法是一樣的,只不過chunks是一個內置的方法,可以設置每次接收的數據大小 with open(filename, ‘wb‘) as f: for chunk in file_obj.chunks(chunk_size=1024): f.write(chunk) return HttpResponse(‘收到啦!‘)1. views.py
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Upload</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <p><input type="text" name="username"></p> <p><input type="file" name="file"></p> <p><input type="submit"></p> </form> </body> </html>2. HTML代碼
3、ajax文件上傳
<!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Upload</title> </head> <body> {% csrf_token %} <h1>上傳文件</h1> <div> <input type="file" id="f1"> <button id="b1"> 上傳</button> </div> <span style="color: red" id="s1"></span> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script> $(‘#b1‘).click(function () { // 取到要上傳的文件數據,存到一個對象中 var fdObj = new FormData(); fdObj.append(‘xx‘, $(‘#f1‘)[0].files[0]); // 在請求的數據中添加csrftokrn var csrfToken = $(‘[name="csrfmiddlewaretoken"]‘).val(); fdObj.append(‘csrfmiddlewaretoken‘, csrfToken); // 發ajax請求 $.ajax({ url: ‘/upload/‘, type: ‘post‘, data: fdObj, processData: false, // 告訴jQuery不要處理我上傳的數據 contentType: false, // 告訴jQuery不要設置請求的文件類型,這兩個參數相當於enctype="multipart/form-data" success: function (res) { $("#s1").text(res); } }) }) </script> </body> </html>1. HTML代碼
class UploadView(views.View): def get(self, request): return render(request, ‘upload.html‘) def post(self, request): file_obj = request.FILES.get(‘xx‘) file_name = file_obj.name with open(file_name, ‘wb‘) as f: for c in file_obj.chunks(): f.write(c) return HttpResponse(‘上傳成功!‘)2. views.py
4、Flask的文件上傳並統計代碼行數
""" app.config.root_path: 項目的根路徑 os.walk: 遍歷你給的路徑下的所有文件(會遞歸遍歷) 每次循環的根文件夾的路徑,文件夾的名字組成的列表,和文件組成的列表 dirpath, dirnames, filenames zipfile: 壓縮解壓文件的模塊 shutil: 也是壓縮解壓文件的模塊,還能移動啥的 """ from flask import Blueprint, request, render_template from flask import current_app as app import shutil from uploadCode.models import CodeRecord from uploadCode import db import os import time uploadBlue = Blueprint(‘uploadBlue‘, __name__) # zip包上傳 @uploadBlue.route(‘/upload‘, methods=[‘GET‘, ‘POST‘]) def upload(): if request.method == "GET": return render_template("upload.html", error="") # 先獲取前端傳過來的文件 file = request.files.get("zip_file") # 判斷是否是zip包 zip_file_type = file.filename.rsplit(".", 1) if zip_file_type[-1] != "zip": return render_template("upload.html", error="文件必須是zip包") # 解壓路徑 upload_path = os.path.join(app.config.root_path, "files", zip_file_type[0]+str(time.time())) print(upload_path) # 解壓前端傳過來的文件file到upload_path這個路徑 shutil._unpack_zipfile(file, upload_path) # 遍歷保存的文件夾得到所有.py文件 file_list = [] for (dirpath, dirnames, filenames) in os.walk(upload_path): for filename in filenames: file_type = filename.rsplit(".", 1) if file_type[-1] != "py": continue file_path = os.path.join(dirpath, filename) file_list.append(file_path) # 打開每個文件讀取行數 sum_num = 0 for path in file_list: with open(path, mode="rb") as f: for line in f: if line.strip().startswith(b"#"): continue sum_num += 1 # 得到總行數去保存數據庫 return str(sum_num)1. upload.py
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> 請上傳你的代碼: <input type="file" name="zip_file"> <button type="submit">提交</button> {{error}} </form> </body> </html>2. HTML代碼
shutil模塊和幾種文件上傳Demo