展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Python Django源码运行分析指南

Python Django源码运行分析指南

Django运行顺序WSGI会不断监听客户端发送来的请求先经过中间件进行分析验证处理然后经过url分发与验证视图层进行处理再经过中间件进行分析验证处理返回响应内容1.启动1.1命令行启动(测试服务器)命令行结论:其在第二步utility.execute()函数会根据命令行参数,分发给不同的类进行处理在manange.py里面execute_from_command_line(sys.argv)进入关键代码defmain():os.environ.setdefault('DJANGO_SETTING

Django运行顺序

  • WSGI会不断监听客户端发送来的请求

  • 先经过中间件进行分析验证处理

  • 然后经过url分发与验证

  • 视图层进行处理

  • 再经过中间件进行分析验证处理

  • 返回响应内容

1.启动

1.1 命令行启动(测试服务器)

命令行结论:其在第二步utility.execute()函数会根据命令行参数,分发给不同的类进行处理

在manange.py里面execute_from_command_line(sys.argv)进入关键代码

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testDjango.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
		---
    execute_from_command_line(sys.argv)

2.execute_from_command_line函数里面其实例化 ManagementUtility类然后执行utility.execute()函数 [
2.1. 此函数是专门用来分析参数的,例如python manage.py runserver、python manage.py help
2.2 其会通过分析额外添加的参数选择要使用的类或者函数,类或者函数对应着django\core\management\commands里面的类

def execute_from_command_line(argv=None):
    utility = ManagementUtility(argv)
    utility.execute()

3.从self.fetch_command(subcommand).run_from_argv(self.argv)[约第413行]
3.1 self.fetch_command(subcommand),这个函数返回了runserver.Command对象(可以自行深入查看),之后执行该Command父类里面的run_from_argv函数

 def execute(self):
			---
        if subcommand == 'help':
			---
        elif subcommand == 'version' or self.argv[1:] == ['--version']:
            sys.stdout.write(django.get_version() + '\n')
        elif self.argv[1:] in (['--help'], ['-h']):
            sys.stdout.write(self.main_help_text() + '\n')
        else:
            self.fetch_command(subcommand).run_from_argv(self.argv)

4.从run_from_argv函数self.execute(*args, **cmd_options)进入
4.1 当前类也有这个execute函数,但是由于继承关系(此时的self也指向Command类),子类如果已经存在该函数会覆盖执行,execute是在子类 Command类中(之后由于super还会到父类里面)[约第354行]

    def run_from_argv(self, argv):
        self._called_from_command_line = True
        parser = self.create_parser(argv[0], argv[1])
        options = parser.parse_args(argv[2:])
        cmd_options = vars(options)

        args = cmd_options.pop('args', ())
        handle_default_options(options)
        try:
            self.execute(*args, **cmd_options)
        except CommandError as e:
			---

5.execute函数执行output = self.handle(*args, **options)[约第398行]跳进子类runserver.Command类的handle函数
5.1 此时位于Command类的父类里面的execute,因为super().execute(*args, **options) #继承下来父类

    def handle(self, *args, **options):
        if not settings.DEBUG and not settings.ALLOWED_HOSTS:
            raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.')
        self.use_ipv6 = options['use_ipv6']
        if self.use_ipv6 and not socket.has_ipv6:
            raise CommandError('Your Python does not support IPv6.')
        self._raw_ipv6 = False
        if not options['addrport']:
        	---
        else:
           	---
        if not self.addr:
            self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr
            self._raw_ipv6 = self.use_ipv6
        self.run(**options)

6.handle 函数最后一行,从 self.run(**options) 进入

    def run(self, **options):
        use_reloader = options['use_reloader']

        if use_reloader:
            autoreload.run_with_reloader(self.inner_run, **options)
        else:
            self.inner_run(None, **options)

7.从def inner_run(self, *args, \*\*options)再执行run函数

    def inner_run(self, *args, **options):
    		---
        try:
            handler = self.get_handler(*args, **options)
            run(self.addr, int(self.port), handler,
                ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
        except OSError as e:
          	 ---

8.最后启动服务,此时跳到django.core.servers.basehttp.py的run函数
8.1 httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) 这一步特别重要,其涉及到较长的继承关系,2.监听-4.1这一环节会介绍到

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    server_address = (addr, port)
    if threading:
        httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        httpd.daemon_threads = True
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

总结流程:

  • 解析运行 python manage.py 所提供的参数,例如: help

  • 加载所有的app

  • 根据参数找到相对应的命令管理工具

  • 检查端口、ipv4检测、ipv6检测、端口是否占用、线程检查

  • orm对象检查表是否创建

  • 最后启动python Lib库中的WSGIServer

2.监听

解释:WSGI开启后,不间断的监听外界的请求

快速阅读:下面写的比较麻烦,最快了解监听和到中间件前的经过就是去读 1 、12.1 和 13

2.1 runserver(测试服务器)

1.runserver成功开启后,关键的一步是httpd.serve_forever(),其使得进入监听即一个死循环

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
	---
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

2.在serve_forever()函数里面执行,当ready有值时,表示有请求发来,然后进入self._handle_request_noblock()

    def serve_forever(self, poll_interval=0.5):
        self.__is_shut_down.clear()
        try:
            with _ServerSelector() as selector:
                selector.register(self, selectors.EVENT_READ)
                while not self.__shutdown_request:
                    ready = selector.select(poll_interval)
                    if self.__shutdown_request:
                        break
                    if ready:
                        self._handle_request_noblock()

                    self.service_actions()
		---

3.从self._handle_request_noblock()正常请求将进入self.process_request(request, client_address)

    def _handle_request_noblock(self):
        try:
            request, client_address = self.get_request()
        except OSError:
            return
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
                self.shutdown_request(request)
            except:
                self.shutdown_request(request)
                raise
        else:
            self.shutdown_request(request)

4.从self.process_request(request, client_address)进入来到了ThreadingMixIn.process_request
4.1 此时,如果没有搞清楚此时的self是谁,就搞不明白为什么进入到ThreadingMixIn.process_request,而不是其它的process_request,这时候就关联到上面提到的httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
4.2 type的用法是动态的创建类,此时httpd_cls 是一个新类,里面分别继承了ThreadingMixIn和server_cls对应得WSGIServer,这时就不难理解为什么找的是ThreadingMixIn.process_request

    def process_request(self, request, client_address):
        """Start a new thread to process the request."""
        t = threading.Thread(target = self.process_request_thread,
                             args = (request, client_address))
        t.daemon = self.daemon_threads
        if not t.daemon and self.block_on_close:
            if self._threads is None:
                self._threads = []
            self._threads.append(t)
        t.start()

5.在def process_request(self, request, client_address)里面的t = threading.Thread(target = self.process_request_thread,args = (request, client_address))实际调用了self.process_request_thread,但是等t.start()才会真正执行

    def process_request_thread(self, request, client_address):
        """Same as in BaseServer but as a thread.

        In addition, exception handling is done here.

        """
        try:
            self.finish_request(request, client_address)
        except Exception:
            self.handle_error(request, client_address)
        finally:
            self.shutdown_request(request)

6.从def process_request_thread(self, request, client_address)进入,self.finish_request(request, client_address),继续完成请求
6.1 这时候又需要回顾之前的代码,因为self.RequestHandlerClass不是已经有的类,而是初始化的时候赋值,其值变为了某个类
6.2 这个过程就在1.启动-8里面的httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6),此时的httpd_cls是type动态创建的,继承了ThreadingMixIn和server_cls对应得WSGIServer,实例化时会执行def __init__方法,其关键执行了self.RequestHandlerClass = RequestHandlerClass

class BaseServer:
    timeout = None

    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False
    def finish_request(self, request, client_address):
        self.RequestHandlerClass(request, client_address, self)
        # self.RequestHandlerClass等同于self.WSGIRequestHandler

7.从self.RequestHandlerClass(request, client_address, self),即去WSGIRequestHandler类里面初始化,根据一层层继承关系,只要最老类BaseRequestHandler有初始化方法

class BaseRequestHandler:
    def __init__(self, request, client_address, server):
        self.request = request
        self.client_address = client_address
        self.server = server
        self.setup()
        try:
            self.handle()
        finally:
            self.finish()

从def __init__(self, request, client_address, server):进入self.handle()
8.1 此时的self.handle(),根据继承关系,其就在最小子类WSGIRequestHandler里面

    def handle(self):
        self.close_connection = True
        self.handle_one_request()
        while not self.close_connection:
            self.handle_one_request()
        try:
            self.connection.shutdown(socket.SHUT_WR)
        except (AttributeError, OSError):
            pass

9.从def handle(self)进入self.handle_one_request()

    def handle_one_request(self):
        """Copy of WSGIRequestHandler.handle() but with different ServerHandler"""
        self.raw_requestline = self.rfile.readline(65537)
        if len(self.raw_requestline) > 65536:
            self.requestline = ''
            self.request_version = ''
            self.command = ''
            self.send_error(414)
            return

        if not self.parse_request():  # An error code has been sent, just exit
            return

        handler = ServerHandler(
            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
        )
        handler.request_handler = self      # backpointer for logging & connection closing
        handler.run(self.server.get_app())

10.从def handle_one_request(self)进入handler.run(self.server.get_app())
10.1 注意此时handler为ServerHandler实例化对象,run方法存在它的最大父类BaseHandler里面
10.2 此时handler.run(self.server.get_app())执行了self.server.get_app(),其返回django.contrib.staticfiles.handlers.StaticFilesHandler,handler.run把其当参数传递了过去

    def run(self, application):
        try:
            self.setup_environ()
            self.result = application(self.environ, self.start_response)
            self.finish_response()
        except (ConnectionAbortedError, BrokenPipeError, ConnectionResetError):

            return
        except:
			---

11.从def run(self, application)进入self.result = application(self.environ, self.start_response),其中application是django.contrib.staticfiles.handlers.StaticFilesHandler
11.1 其中self.application已经初始化了是WSGIHandler

class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
    def __init__(self, application):
        self.application = application
        self.base_url = urlparse(self.get_base_url())
        super().__init__()

    def __call__(self, environ, start_response):
        if not self._should_handle(get_path_info(environ)):
            return self.application(environ, start_response)
        return super().__call__(environ, start_response)

12.进入后执行def __call__(self, environ, start_response)方法,进入return self.application(environ, start_response),此时self.application已经初始化了是WSGIHandler
12.1 request = self.request_class(environ)获取到用户请求的url后面就开始配置runserver启动时候加载的url; response = self.get_response(request)获取用户url对应的响应准备开始往视图转

    def __call__(self, environ, start_response):
        set_script_prefix(get_script_name(environ))
        signals.request_started.send(sender=self.__class__, environ=environ)
        request = self.request_class(environ)
        response = self.get_response(request)
		---

13.进入response = self.get_response(request),结束,再下一步就要开始中间件的进行

    def get_response(self, request):
        set_urlconf(settings.ROOT_URLCONF)
        response = self._middleware_chain(request)
        response._resource_closers.append(request.close)
        if response.status_code >= 400:
            log_response(
                '%s: %s', response.reason_phrase, request.path,
                response=response,
                request=request,
            )
        return response

3.中间件的执行

解释:中间件的执行需要联系着上面运行过程,这个过程是一个递归的过程,下面介绍的五个函数是中间件命名规则对应得内容

  • process_request():完成请求对象的创建,但用户访问的网址尚未与网站的路由地址匹配。

  • process_view():完成用户访问的网址与路由地址的匹配,但尚未执行视图函数。

  • process_exception():在执行视图函数的期间发生异常,比如代码异常,主动抛出404异常等。

  • process_response():完成视图函数的执行,但尚未将响应内容返回浏览器

  • process_template_response():默认不执行,在视图函数完成操作后调用,除非视图函数返回的response中有render方法(几乎不会用,可以忽略)

1.递归的进入阶段:循环进行下面的代码(此代码位置django\core\handlers\exception.py)

1.1 此处出现process_request()和process_response()

        @wraps(get_response)
        def inner(request):
            try:
                response = get_response(request) # 此进入循环
            except Exception as exc:
                response = response_for_exception(request, exc)
            return response
        return inner
    def __call__(self, request):
        # Exit out to async mode, if needed
        if asyncio.iscoroutinefunction(self.get_response):
            return self.__acall__(request)
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request) # 进行中间件的process_request步骤
        response = response or self.get_response(request) # 此进入循环
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response) # 此是递归后执行的
        return response

2.递归的结束准备回传:进行下面的代码(此代码位置django\core\handlers\base.py)
2.1 此处出现process_view()、process_template_response()和process_exception()

进入视图的关键函数:

  • callback, callback_args, callback_kwargs = self.resolve_request(request) # callback即对于视图函数url匹配到对应的view函数

  • for middleware_method in self._view_middleware_view_middleware里面放着所有的process_view()函数(初始化时加载的), process_view()正是在该代码下面的环节循环执行

  • response = wrapped_callback(request, *callback_args, **callback_kwargs) 回调函数传参,并返回试图函数响应。

  • 沿着这个路径连续进入两次,就到了后面讲到的as_view里面(此内容是专门视图处理的前的关键步骤)

  • response = self.process_exception_by_middleware(e, request)对应process_exception()

  • self._template_response_middleware 循环加载模板中间件

 def _get_response(self, request):
        response = None
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        for middleware_method in self._view_middleware:
            response = middleware_method(request, callback, callback_args, callback_kwargs)
            if response:
                break
        if response is None:
            wrapped_callback = self.make_view_atomic(callback) # 找到视图函数
            # If it is an asynchronous view, run it in a subthread.
            if asyncio.iscoroutinefunction(wrapped_callback):
                wrapped_callback = async_to_sync(wrapped_callback)
            try:
                response = wrapped_callback(request, *callback_args, **callback_kwargs)
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise
        self.check_response(response, callback)
        if hasattr(response, 'render') and callable(response.render):
            for middleware_method in self._template_response_middleware:
                response = middleware_method(request, response)
                self.check_response(
                    response,
                    middleware_method,
                    name='%s.process_template_response' % (
                        middleware_method.__self__.__class__.__name__,
                    )
                )
            try:
                response = response.render()
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise
        return response

3.递归的结束回传:循环进行下面的代码

        @wraps(get_response)
        def inner(request):
            try:
                response = get_response(request) # 此进入循环
            except Exception as exc:
                response = response_for_exception(request, exc)
            return response
        return inner
    def __call__(self, request):
        # Exit out to async mode, if needed
        if asyncio.iscoroutinefunction(self.get_response):
            return self.__acall__(request)
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request) 
        response = response or self.get_response(request) # 此进入循环
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response) # 进行中间件的process_response步骤
        return response
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发 Python django
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
Shapr3D macOS版
Shapr3D macOS版

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

Adobe After Effects macOS版
Adobe After Effects macOS版

Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

Adobe Audition macOS版
Adobe Audition macOS版

Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

Adobe Bridge macOS版
Adobe Bridge macOS版

Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

Adobe Illustrator macOS版
Adobe Illustrator macOS版

Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

Adobe InDesign macOS版
Adobe InDesign macOS版

Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

Adobe Lightroom Classic macOS版
Adobe Lightroom Classic macOS版

Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

Adobe Media Encoder macOS版
Adobe Media Encoder macOS版

Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

Adobe Photoshop macOS版
Adobe Photoshop macOS版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

Adobe Premiere Pro macOS版
Adobe Premiere Pro macOS版

Adobe Premiere Pro 是面向专业视频制作的非线性剪辑软件,提供多轨时间线、调色、音频处理、字幕、代理工作流和多格式输出能力,并可与 After Effects、Audition、Photoshop 及 Frame.io 协同

WINDOWS 更多
3dmax(3ds max)
3dmax(3ds max)

Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

photoshop
photoshop

Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

Blender
Blender

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365简体中文
Office 365简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。