day31 python ftp练习
一.网络基础
租服务器:虚拟机(公有云/私有云:公司内部用/docker:可以事先配置好环境)
端口范围:
0<- well-known ->254<- 保留unix ->1024<- 自定义 ->65536
二.ftp作业
1.进度条
'\r' : 主要实现技术: 不换行输出
import time
print('\r80%',end='')
time.sleep(1)
print('\r90%',end='')
100%
import time
def func(size,total_size):
time.sleep(0.1)
print('\r%s%%' % (int(size/total_size*100),),end='')
for i in range(101):
func(i,100)
100%|------------------->|
import time
def func(size,total_size):
time.sleep(0.1)
num = int(size/total_size*100)
print('\r%s%%|%s>|' % (num,'-'*num,),end='')
for i in range(101):
func(i,100)
sys模块的stdout
sys.stdout.wtrite() #往输出设备上写
sys.stdout.flush() #把写的内容刷新到输出设备上, print()内部就是这个
2.计算文件大小
import os
方法一:
size_d = os.stat(r'C:\Users\THINKPAD\PycharmProjects\s15\day05').st_size
size_f = os.stat(r'C:\Users\THINKPAD\PycharmProjects\s15\day05\ae9516e7-4fb1-41da-98a7-04c013778867.jpg').st_size
print(size_d) #目录本身的大小: 字节
print(size_f) #文件的大小: 字节
方法二:
size = os.path.getsize(r'C:\Users\THINKPAD\PycharmProjects\s15\day05\ae9516e7-4fb1-41da-98a7-04c013778867.jpg')
print(size)
3.ftp的断点续传
3.1.1.服务端
import socketserver
import json
import os
ip_port = ('127.0.0.1',65535)
code = {
'1001':'上传文件,从头开始上传',
'1002':'断点续传'
}
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
#接收client自定义的协议,获取文件的各种信息
cmd_json = self.request.recv(8192) #recv() 最大8k
cmd_dict = json.loads(cmd_json.decode('utf-8'))
file_name = cmd_dict.get('file_name')
file_md5 = cmd_dict.get('file_md5')
file_path = os.path.join('home', 'bajie', file_name)
file_md5_path = os.path.join('home','bajie',file_md5)
file_size = cmd_dict.get('file_size')
if not os.path.exists(file_md5_path): #简单代码往上放
#直接传,要告诉对方直接传
response = {'code': '1001'}
self.request.sendall(json.dumps(response).encode('utf-8'))
with open(file_md5_path,mode='wb') as f:
recv_size = 0
while recv_size < file_size: #条件的边界不能是等于, 要是等于条件就会一直成立, 一直收
data = self.request.recv(1024)
recv_size += len(data)
f.write(data) #实际是写到了内存
f.flush() #把内存的内容刷到文件
os.rename(file_md5_path,file_path) #py2里windows里可能报错,可以使用另外一个模块: import shutil; shutil.move()
else:
#断点续传
exist_size = os.stat(file_md5_path).st_size
print(exist_size)
response = {'code':'1002','exist_size':exist_size}
self.request.sendall(json.dumps(response).encode('utf-8'))
with open(file_md5_path,mode='ab') as f:
recv_size = exist_size
while recv_size < file_size: #条件的边界不能是等于, 要是等于条件就会一直成立, 一直收
data = self.request.recv(1024)
recv_size += len(data)
f.write(data) #实际是写到了内存
f.flush()
os.rename(file_md5_path, file_path) # py2里windows里可能报错,可以使用另外一个模块: import shutil; shutil.move()
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(ip_port, MyServer)
server.serve_forever()
3.1.2.客户端
import socket
import json
import hashlib
import os
ip_port = ('127.0.0.1',65535)
def mymd5(filename):
md5 = hashlib.md5(b'bajieaishuishui')
with open(filename, mode='rb') as f:
for line in f:
md5.update(line)
else:
return md5.hexdigest()
client = socket.socket()
client.connect(ip_port)
while 1:
cmd = input('please input command: ') #定义你自己的协议
#准备文件各种信息, 自定义协议
file_path = 'range.py'
file_name = os.path.basename(file_path)
file_size = os.stat(file_path).st_size
file_md5 = mymd5(file_path)
cmd_dict = {
'cmd':'upload',
'file_name':file_name,
'file_size':file_size,
'file_md5':file_md5
}
cmd_json = json.dumps(cmd_dict)
client.sendall(cmd_json.encode('utf-8')) #send 和 sendall 一样, sendall一直发, 如果没发完就接着发,推荐有这个
#等待服务端响应
response = json.loads(client.recv(8192).decode('utf-8'))
if response.get('code') == '1001':
print('从头开始')
with open(file_path, mode='rb') as f:
send_size = 0
while send_size < file_size: #文件大小的边界,不应等于, 要是等于, 那等于时条件一直成立, 死循环
data = f.read(1024) #用for每次发一行也行,但是用while这个可以控制发多少
#data = f.read(66)
send_size += len(data)
client.sendall(data)
#break
else:
print('断点续传')
exist_size = response.get('exist_size')
send_size = exist_size
with open(file_path, mode='rb') as f:
f.seek(exist_size)
data = f.read(1024)
send_size += len(data)
client.sendall(data)
3.2.1.服务端简化代码:(功能放入函数)
import socketserver
import json
import os
ip_port = ('127.0.0.1',65535)
code = {
'1001':'上传文件,从头开始上传',
'1002':'断点续传'
}
def recv_file(file_md5_path,exist_size,file_size,conn,file_path):
with open(file_md5_path, mode='ab') as f:
recv_size = exist_size
while recv_size < file_size: #条件的边界不能是等于, 要是等于条件就会一直成立, 一直收
data = conn.recv(1024)
recv_size += len(data)
f.write(data) # 实际是写到了内存
f.flush()
if os.path.exists(file_path):
i = 1
while True:
new_file_path = file_path + '.' + str(i)
print(new_file_path)
if os.path.exists(new_file_path):
i += 1
else:
os.rename(file_md5_path, new_file_path) # py2里windows里可能报错,可以使用另外一个模块: import shutil; shutil.move()
break
else:
os.rename(file_md5_path, file_path)
def upload(cmd_dict,conn,username):
file_name = cmd_dict.get('file_name')
file_md5 = cmd_dict.get('file_md5')
file_path = os.path.join('home', username, file_name)
file_md5_path = os.path.join('home', username, file_md5)
file_size = cmd_dict.get('file_size')
if not os.path.exists(file_md5_path): # 简单代码往上放
# 直接传,要告诉对方直接传
exist_size = 0
response = {'code': '1001'}
else:
# 断点续传
exist_size = os.stat(file_md5_path).st_size
response = {'code': '1002', 'exist_size': exist_size}
conn.sendall(json.dumps(response).encode('utf-8'))
recv_file(file_md5_path, exist_size, file_size, conn, file_path)
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
#接收client自定义的协议,获取文件的各种信息
cmd_json = self.request.recv(8192) #recv() 最大8k
cmd_dict = json.loads(cmd_json.decode('utf-8'))
file_cmd = cmd_dict.get('cmd')
if file_cmd == 'upload':
upload(cmd_dict,self.request,'bajie')
elif file_cmd == 'download':
pass
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(ip_port, MyServer)
server.serve_forever()
3.2.2.客户端代码简化(把功能放入函数中)
import socket
import json
import hashlib
import os
ip_port = ('127.0.0.1',65535)
def func(size,total_size):
num = int(size/total_size*100)
print('\r%s%%|%s>|' % (num,'-'*num,),end='')
def mymd5(filename):
md5 = hashlib.md5(b'bajieaishuishui')
with open(filename, mode='rb') as f:
for line in f:
md5.update(line)
else:
return md5.hexdigest()
def send_file(exist_size,file_size):
with open(file_path, mode='rb') as f:
f.seek(exist_size)
send_size = exist_size
while send_size < file_size:
data = f.read(1024)
send_size += len(data)
client.sendall(data)
func(send_size,file_size)
print()
def upload(file_path):
# 准备文件各种信息, 自定义协议
file_name = os.path.basename(file_path)
file_size = os.stat(file_path).st_size
file_md5 = mymd5(file_path)
cmd_dict = {
'cmd': 'upload',
'file_name': file_name,
'file_size': file_size,
'file_md5': file_md5
}
cmd_json = json.dumps(cmd_dict)
client.sendall(cmd_json.encode('utf-8')) # send 和 sendall 一样, sendall一直发, 如果没发完就接着发,推荐用这个
# 等待服务端响应
response = json.loads(client.recv(8192).decode('utf-8'))
print(response)
if response.get('code') == '1001':
# 从头开始
print('从头开始')
exist_size = 0
else:
# 断点续传
print('断点续传')
exist_size = response.get('exist_size')
send_file(exist_size,file_size)
client = socket.socket()
client.connect(ip_port)
while 1:
user_input = input('please input command: ') #upload range.py
cmd,file_path = user_input.split()
if cmd == 'upload':
upload(file_path)
elif cmd == 'download':
pass
4.搭建框架(上面写的叫做脚本, 不叫程序)
应该创建两个project
4.1.一个ftp_server
bin
start.py
from core.handler import run
if __name__ == '__main__':
run()
setting(config)
config.py
ip_port = ('127.0.0.1',65535)
code = {
'1001':'上传文件,从头开始上传',
'1002':'断点续传'
}
core(src:java习惯用这个,都可以)
handler.py(文件名也不要大写)
import socketserver
import json
import os
import logging
class Action:
def __init__(self):
self.username = None
def login(self,cmd_dict,conn):
pass
self.username = 'bajie'
def recv_file(self,file_md5_path,exist_size,file_size,conn,file_path):
with open(file_md5_path, mode='ab') as f:
recv_size = exist_size
while recv_size < file_size: # 条件的边界不能是等于, 要是等于条件就会一直成立, 一直收
data = conn.recv(1024)
recv_size += len(data)
f.write(data) # 实际是写到了内存
f.flush()
if os.path.exists(file_path):
i = 1
while True:
new_file_path = file_path + '.' + str(i)
print(new_file_path)
if os.path.exists(new_file_path):
i += 1
else:
os.rename(file_md5_path, new_file_path) # py2里windows里可能报错,可以使用另外一个模块: import shutil; shutil.move()
break
else:
os.rename(file_md5_path, file_path)
def upload(self,cmd_dict,conn,username):
file_name = cmd_dict.get('file_name')
file_md5 = cmd_dict.get('file_md5')
file_path = os.path.join('home', username, file_name)
file_md5_path = os.path.join('home', username, file_md5)
file_size = cmd_dict.get('file_size')
if not os.path.exists(file_md5_path): # 简单代码往上放
# 直接传,要告诉对方直接传
exist_size = 0
response = {'code': '1001'}
else:
# 断点续传
exist_size = os.stat(file_md5_path).st_size
response = {'code': '1002', 'exist_size': exist_size}
conn.sendall(json.dumps(response).encode('utf-8'))
self.recv_file(file_md5_path, exist_size, file_size, conn, file_path)
def download(self):
pass
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
#接收client自定义的协议,获取文件的各种信息
cmd_json = self.request.recv(8192) #recv() 最大8k
cmd_dict = json.loads(cmd_json.decode('utf-8'))
file_cmd = cmd_dict.get('cmd')
action = Action()
if action.username: #已登录
action_name = cmd_dict.get('file_cmd')
if hasattr(action, action_name):
getattr(action, action_name)(cmd_dict,self.request)
else:
print('cmd is not support')
else:
action.login(cmd_dict,self.request)
def run():
server = socketserver.ThreadingTCPServer(ip_port, MyServer)
server.serve_forever()
db(数据库一定不能和代码放到一起:现在是因为还没学数据库)
log
readme:如何使用你的程序
4.2.一个ftp_client (python中:文件夹和文件名推荐用小写, 如果小写不能满足你, 那么可以用下划线分隔)
课外题:
让python读取excel文件