# 17|不同操作系统下,如何通过网络同步文件? 你好,我是尹会生。 你有没有过这种经历:慌慌张张地去会议室开会,突然发现自己需要的文件却在工位的台式电脑中。因为文件比较大大,通过互联网下载需要很长时间。如果用网盘来中转放在两个电脑上的文件,传输速度又很慢。 我猜这个时候你就会想:如果能用一台电脑实现文件的上传和下载,那文件传输是不是就非常方便快速了。 这当然是可以实现的。所以今天,我就教你怎样用Python基于HTTP协议,来实现跨操作系统的文件上传和下载功能。 今天要学习的代码都不长,比较精简,又和文字相得益彰,所以学起来也不会太累。那接下来就跟着我的思路走,我们先来了解一下使用Python来实现文件上传和下载的优势。 ## 为什么要使用Python? 实现文件下载的软件,相信你也用过很多,比如微信、QQ。用这些软件来传输文件,不仅要连接互联网,而且还有文件大小的限制。那如果用商业软件呢?传输虽然方便,但是就不能跨操作系统,而且还有可能需要付费。 所以综合下来,既要免费,又要传输快、没有大小限制的实现方式有没有呢?聪慧如你,一定知道接下来我会开始讲怎么用Python来实现文件的上传和下载功能了。别着急,我还要再唠叨几句关于用Python来实现的优势,这样你会学得更有劲儿。 首先,用法简单。**只要一行代码,就能实现文件的浏览和下载功能。** 其次,跨操作系统,适用范围广。只要安装了Python默认支持的文件下载需要的模块,那么在Windows、macOS、Linux上就都能用。 最后,传输速度快。和网盘、微信不同,Python的文件下载功能,是基于局域网通信的,不需要通过互联网中转,所以也就没有了传输速度和文件大小的限制。 知道了用Python来实现的优势,那接下来我们就进入正题。我会结合代码,来给你讲解用Python怎么实现文件的浏览和下载功能。代码不会很长,所以你学起来也不会很累。 ## 一行代码,实现文件的浏览和下载 使用Python实现文件的浏览和下载,只需要一行代码。如下: ``` python3 -m http.server 8080 ``` 通过在命令行运行这行代码之后,就能通过“[http://你的IP地址:8080](http://xn--IP-0p3ck01akcu41v:8080)”浏览和下载文件了。 这行代码很简单,但你要仔细看的话,会发现这行代码的执行过程和我们之前执行脚本的过程有比较大的差别,而且通过“http.server”模块的加载就直接运行了Python的脚本,这两种功能都是我们之前没有接触过的。 虽然没有接触过,但是学起来不会很难,那么接下来我就从怎么通过命令行运行模块,以及怎么**使用模块提供一个HTTP服务这两方面来**讲解这行代码。 #### 如何通过命令行运行模块 要通过命令行运行一个模块,我们需要先通过Python命令找到“http.server”模块的第一条命令,然后再来执行。而找到“http.server”模块,非常关键的就是"-m"参数。我来重点讲解一下。 从执行方式上,这行代码和我们以往执行的代码不同。我在Python命令和模块之间使用了“-m”参数,而且**“-m”参数后面会跟着要执行的Python的模块“http.server”。** **“http.server”在你电脑中保存的路径是“/模块所在目录/http/server.py”,它也是一个“.py”结尾的文件,会被保存在你电脑上Python文件夹中的“lib”文件夹下**。 如果不使用“-m”参数,那就像我们之前执行的代码一样,Python会执行当前目录下的.py 文件。所以在这里你要特别注意一下,增加了“-m”参数前后,执行的.py文件位置是不同的。 如果要查看这个模块是怎样通过Python实现的,那么我们需要先找到这个模块的所在目录。核心实现代码我写了出来,供你参考。 ``` $ python3 >>> import http >>> http.__file__ '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/http/__init__.py' ``` 在这段代码中,我使用了我们之前学习过的内置变量“**file**”,得到了该模块所在的位置。在以后的工作中,你可以使用这种方式查找任意一个你想要了解的模块位置。 不过你也要知道,由于你在安装Python时,会根据自己的习惯选择自定义的目录,或者你使用的是Windows操作系统,所以你得到的目录可能会和我不同,但这并不影响你阅读查找该模块的实现代码。 如果你还想查看Python其他模块保存在哪个目录,可以在没有加载模块的前提下,获得所有模块的位置,代码如下: ``` import sys sys.path # 执行结果 ['', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7', '/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages'] ``` 你会发现,在执行“sys.path”得到的列表中,还会出现一个“site-packages”目录,这个目录是你使用pip3安装的第三方模块默认的位置。当你需要学习Python库的代码时,可以使用这个方法找到所有安装的包的目录。 “-m”参数不但能让Python从“sys.path”中找到要执行的模块,还能够自动执行这个模块。以“http.server”为例,Python会首先找到“lib/python3.7/http/server.py”, 然后运行“server.py”文件。 由于该文件中使用了“if **name** == '**main**':”这样一条语句,所以Python会从这一行开始执行“server.py”文件。此外,我还为“http.server”指定了参数“8080”, “server.py”会通过“argparse”库对“8080”这个参数进行处理。 #### **如何使用“http.server”模块提供HTTP服务** **刚才我们讲了怎么通过命令行来运行“http.server”模块,事实上,这个模块\*\*\*\*是基于HTTP协议实现的文件浏览和下载功能。接下来我们就先了解一下**HTTP协议的主要工作过程。 使用HTTP协议的好处是它能够跨平台,而且还比其他协议简单。那么要想掌握HTTP协议,你得要知道HTTP协议提供了两种角色: * 为其他人提供服务的服务端; * 享受服务的客户端。 我们一般把“http.server”称为HTTP服务端,把浏览器称作HTTP客户端。服务端和客户端通信时,会采用它们的主要协议--HTTP协议。 它们的通信过程就像是在打电话,当你给对方打电话时,首先要输入对方的手机号码。同理,在计算机中,手机号码就是服务端的IP地址和端口,接通电话后,双方要想互相听懂要传递的信息,必须使用一种双方都能理解的语言,这个语言在计算机中就是HTTP协议。所以一句话总结就是,相同的语言就是文件传输的协议。 了解了HTTP协议的主要工作过程,那接下来就是它建立连接的过程了。就像我为你举的例子一样,对方的手机号码在HTTP协议就是IP地址和端口。 比如我为HTTP服务器指定的端口是8090,我的IP地址是“192.168.0.100”,那我就可以通过浏览器使用“[http://192.168.0.100:8090](http://192.168.0.100:8090)”进行访问。可以看到,在访问的时候,我手动指定了协议、IP地址和端口。 所以“http.server“模块不仅可以提供HTTP协议,还是一个灵活指定IP和端口的HTTP服务端。这也就是说,http.server模块运行后,能让浏览器访问到服务端。 由于客户端服务端都采用HTTP协议,那么服务端列出的文件目录会自动被浏览器翻译给客户端的用户,你也就能浏览器查看到服务器上的文件名称,并把服务器的文件下载到客户端的电脑上,这就是“http.server”模块能够实现下载的原理和过程了。 另外,我还要提醒你,在文件下载时,一定要注意共享的安全性。因为那些没有用户认证功能的HTTP文件下载方案,其他人都可以通过IP地址和端口直接获取你电脑中的文件,由此造成信息泄漏。因此在共享完成后,你需要把服务端及时关闭。 不过由于“http.server”默认没有提供文件上传的功能,手动编写也需要比较复杂的代码逻辑,因此,我来通过另一个Flask模块,它能通过简单的代码实现文件上传。 ## 如何实现文件的上传 虽然我们要利用最精简的代码来把文件上传到服务端,但是它也要比下载功能复杂得多,因为基于HTTP协议的上传,我们需要自行编写HTML页面,来提示用户怎么上传,怎么使用POST方法访问服务器,以及怎么指定上传后文件的保存位置。 我根据[Flask模块的官方文档](http://docs.jinkan.org/docs/flask/patterns/fileuploads.html)的上传代码,进行了精简,考虑到你目前对编程的理解还比较基础,所以我把用户验证和文件扩展名验证功能去掉后,得到了如下的代码。通过这段代码,可以实现基于Python的文件上传。 我把代码放在文稿中,供你学习和参考。同时,我也再给你详细讲解上传的过程,以及用到的代码。 ``` import os from flask import Flask, request app = Flask(__name__) app.config['UPLOAD_FOLDER'] = os.getcwd() html = '''