更新时间:2025-11-18 GMT+08:00

MoXing功能介绍

场景描述

在使用ModelArts服务时,您可能会遇到需要访问对象存储服务(OBS)的情况。OBS是一个基于对象的海量存储服务,与传统的本地文件系统不同,无法直接通过文件路径访问OBS上的文件。

直接访问OBS文件时会遇到以下问题:

  • 无法像访问本地文件那样使用open()方法。
  • 需要通过网络请求进行文件读写操作。
  • 使用OBS Python SDK接口可能较为复杂。

如何在ModelArts服务中更便捷地访问和操作OBS文件?

ModelArts提供了mox.file接口,为OBS操作提供了更简便的解决方案。以下是使用mox.file接口访问OBS文件的示例:

# 访问OBS文件示例
import moxing as mox

# 打开OBS文件
with mox.file.File('obs://bucket_name/a.txt', 'r') as f:
    print(f.read())

# 列举OBS目录
mox.file.list_directory('obs://bucket_name/my_dir/')

使用mox.file接口注意事项

  1. mox.file接口主要适用于提升从OBS读取和下载数据的易用性。
  2. 对于OBS并行文件系统部分接口可能存在兼容性问题,建议直接使用OBS Python SDK进行生产业务开发。
  3. 详细接口说明请参见《对象存储服务 OBS》的Python SDK接口概览

通过mox.file接口,您可以像操作本地文件一样便捷地访问和管理OBS资源,从而提高开发效率。

约束限制

  • 需要访问的OBS桶需要满足当前训练作业,可以正常访问。
  • 当前账户有读写OBS桶权限。
  • 使用ModelArts标准镜像或基于自定义镜像安装moxing库。

文件复制

  • 复制一个文件。mox.file.copy仅支持对文件操作,如果要对文件夹进行操作,请使用mox.file.copy_parallel
    • 从OBS复制到OBS,例如将“obs://bucket_name/obs_file.txt”复制到“obs://bucket_name/obs_file_2.txt”
      1
      2
      import moxing as mox
      mox.file.copy('obs://bucket_name/obs_file.txt', 'obs://bucket_name/obs_file_2.txt')
      
    • 将OBS文件复制到本地,也就是下载一个OBS文件。例如下载“obs://bucket_name/obs_file.txt”到本地“/tmp/obs_file.txt”
      1
      2
      import moxing as mox
      mox.file.copy('obs://bucket_name/obs_file.txt', '/tmp/obs_file.txt')
      
    • 将本地文件复制到OBS,也就是上传一个OBS文件,例如上传“/tmp/obs_file.txt”“obs://bucket_name/obs_file.txt”
      1
      2
      import moxing as mox
      mox.file.copy('/tmp/obs_file.txt', 'obs://bucket_name/obs_file.txt')
      
    • 将本地文件复制到本地,操作等价于shutil.copyfile,例如将“/tmp/obs_file.txt”复制到“/tmp/obs_file_2.txt”
      1
      2
      import moxing as mox
      mox.file.copy('/tmp/obs_file.txt', '/tmp/obs_file_2.txt')
      
  • 对于体积较大的文件,mox.file.copy会默认使用分片并发下载方式进行加速,相关参数可以通过环境变量控制。

    1. 判断文件是否为大文件,超过该阈值会启用分片并发下载。
      MOX_FILE_PARTIAL_MAXIMUM_SIZE

      默认大小为5GB,设置单位为Byte,例如设置5GB需要写为5368709120。

    2. 管理文件分片大小。
      MOX_FILE_LARGE_FILE_PART_SIZE

      默认大小为10MB,设置单位为Byte。由于OBS限制分片数量最多为10000片,当文件大小超过100G时需要上调分片大小。

    3. 管理下载并发多进程数量。下载并发多进程数,表示大文件下载时会启动几个线程进行下载,新版本中默认值为8,节点较少或者大文件数量较少时,可以适当扩大并发数,提升下载性能。
      MOX_FILE_LARGE_FILE_TASK_NUM

      默认大小为32,当并发数过高导致OBS桶流控时需要调小。

  • 复制一个文件夹。mox.file.copy_parallel仅支持对文件夹操作,如果要对文件进行操作,请使用mox.file.copy
    • 从OBS复制到OBS,例如将obs://bucket_name/sub_dir_0复制到obs://bucket_name/sub_dir_1
      1
      2
      import moxing as mox
      mox.file.copy_parallel('obs://bucket_name/sub_dir_0', 'obs://bucket_name/sub_dir_1')
      
    • 将OBS文件夹复制到本地,也就是下载一个OBS文件夹。例如下载“obs://bucket_name/sub_dir_0”到本地“/tmp/sub_dir_0”
      1
      2
      import moxing as mox
      mox.file.copy_parallel('obs://bucket_name/sub_dir_0', '/tmp/sub_dir_0')
      
    • 将本地文件夹复制到OBS,也就是上传一个OBS文件夹,例如上传“/tmp/sub_dir_0”“obs://bucket_name/sub_dir_0”
      1
      2
      import moxing as mox
      mox.file.copy_parallel('/tmp/sub_dir_0', 'obs://bucket_name/sub_dir_0')
      
    • 将本地文件夹复制到本地,操作等价于shutil.copytree,例如将“/tmp/sub_dir_0”复制到“/tmp/sub_dir_1”
      1
      2
      import moxing as mox
      mox.file.copy_parallel('/tmp/sub_dir_0', '/tmp/sub_dir_1')
      

mox.file.copy_parallel可以通过threads参数控制复制操作的并发数,该并发数默认为16。

file_list参数可以选择需要拷贝的文件。例如上传“/tmp/sub_dir_0”中的“/tmp/sub_dir_0/train/1.jpg”“/tmp/sub_dir_0/eval/2.jpg”“obs://bucket_name/sub_dir_0”

1
2
import moxing as mox
mox.file.copy_parallel('/tmp/sub_dir_0', 'obs://bucket_name/sub_dir_0', file_list=['train/1.jpg', 'eval/2.jpg'])

读写操作

  • 读取一个OBS文件。
    例如读取“obs://bucket_name/obs_file.txt”文件内容,返回string(字符串类型)。
    1
    2
    import moxing as mox
    file_str = mox.file.read('obs://bucket_name/obs_file.txt')
    
    也可以使用打开文件对象并读取的方式来实现,两者是等价的。
    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.txt', 'r') as f:
      file_str = f.read()
    
  • 从文件中读取一行,返回string,以换行符结尾。同样可以打开OBS的文件对象。
    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.txt', 'r') as f:
      file_line = f.readline()
    
  • 从文件中读取所有行,返回一个list,每个元素是一行,以换行符结尾。
    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.txt', 'r') as f:
      file_line_list = f.readlines()
    
  • 以二进制模式读取一个OBS文件。
    例如读取“obs://bucket_name/obs_file.bin”文件内容,返回bytes(字节类型)。
    1
    2
    import moxing as mox
    file_bytes = mox.file.read('obs://bucket_name/obs_file.bin',binary=True)
    

    也可以使用打开文件对象并读取的方式来实现,两者是等价的。

    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.bin', 'rb') as f:
      file_bytes = f.read()
    

    以二进制模式打开的文件也支持读取一行或者读取所有行,用法不变。

  • 将字符串写入一个文件。
    例如将字符串“Hello World!”写入OBS文件“obs://bucket_name/obs_file.txt”中。
    1
    2
    import moxing as mox
    mox.file.write('obs://bucket_name/obs_file.txt', 'Hello World!')
    

    也可以使用打开文件对象并写入的方式来实现,两者是等价的。

    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.txt', 'w') as f:
      f.write('Hello World!')
    

    用写入模式打开文件或者调用mox.file.write时,如果被写入文件不存在,则会创建,如果已经存在,则会覆盖。

  • 追加一个OBS文件。

    例如将字符串“Hello World!”追加到“obs://bucket_name/obs_file.txt”文件中。

    1
    2
    import moxing as mox
    mox.file.append('obs://bucket_name/obs_file.txt', 'Hello World!')
    

    也可以使用打开文件对象并追加的方式来实现,两者是等价的。

    1
    2
    3
    import moxing as mox
    with mox.file.File('obs://bucket_name/obs_file.txt', 'a') as f:
      f.write('Hello World!')
    

    用追加模式打开文件或者调用mox.file.append时,如果被写入文件不存在,则会创建,如果已经存在,则直接追加。

    当被追加的源文件比较大时,例如“obs://bucket_name/obs_file.txt”文件大小超过5MB时,追加一个OBS文件的性能比较低。

    如果以写入模式或追加模式打开文件,当调用write方法时,待写入内容只是暂时的被存在的缓冲区,直到关闭文件对象(退出with语句时会自动关闭文件对象)或者主动调用文件对象的close()方法或flush()方法时,文件内容才会被写入。

列举操作

  • 列举一个OBS目录,只返回顶层结果(相对路径),不做递归列举。

    例如列举“obs://bucket_name/object_dir”,返回该目录下所有的文件和文件夹,不会递归查询。

    假设“obs://bucket_name/object_dir”中有如下结构

    1
    2
    3
    4
    5
    bucket_name
          |- object_dir
            |- dir0
              |- file00
            |- file1
    

    调用如下代码:

    1
    2
    import moxing as mox
    mox.file.list_directory('obs://bucket_name/object_dir')
    

    返回一个list:

    ['dir0', 'file1']
  • 递归列举一个OBS目录,返回目录中所有的文件和文件夹(相对路径),并且会做递归查询。

    假设obs://bucket_name/object_dir中有如下结构。

    1
    2
    3
    4
    5
    bucket_name
          |- object_dir
            |- dir0
              |- file00
            |- file1
    

    调用如下代码:

    1
    2
    import moxing as mox
    mox.file.list_directory('obs://bucket_name/object_dir', recursive=True)
    

    返回一个list:

    ['dir0', 'dir0/file00', 'file1']

创建文件夹

创建一个OBS目录(即OBS文件夹)。支持递归创建,即如果“sub_dir_0”文件夹不存在,也会自动被创建,如果已经存在,则不起任何作用。

1
2
import moxing as mox
mox.file.make_dirs('obs://bucket_name/sub_dir_0/sub_dir_1')

查询操作

  • 判断一个OBS文件是否存在,如果存在则返回True,如果不存在则返回False
    1
    2
    import moxing as mox
    mox.file.exists('obs://bucket_name/sub_dir_0/file.txt')
    
  • 判断一个OBS文件夹是否存在,如果存在则返回True,如果不存在则返回False
    1
    2
    import moxing as mox
    mox.file.exists('obs://bucket_name/sub_dir_0/sub_dir_1')
    

    由于OBS允许同名的文件和文件夹(Unix操作系统不允许),如果存在同名的文件和文件夹,例如“obs://bucket_name/sub_dir_0/abc”,当调用mox.file.exists时,不论abc是文件还是文件夹,都会返回True。

  • 判断一个OBS路径是否为文件夹,如果是则返回True,否则返回False
    1
    2
    import moxing as mox
    mox.file.is_directory('obs://bucket_name/sub_dir_0/sub_dir_1')
    

    由于OBS允许同名的文件和文件夹(Unix操作系统不允许),如果存在同名的文件和文件夹,例如obs://bucket_name/sub_dir_0/abc,当调用mox.file.is_directory时,会返回True。

  • 获取一个OBS文件的大小,单位为bytes。
    例如获取“obs://bucket_name/obs_file.txt”的文件大小。
    1
    2
    import moxing as mox
    mox.file.get_size('obs://bucket_name/obs_file.txt')
    
  • 递归获取一个OBS文件夹下所有文件的大小,单位为bytes。
    例如获取“obs://bucket_name/object_dir”目录下所有文件大小的总和。
    1
    2
    import moxing as mox
    mox.file.get_size('obs://bucket_name/object_dir', recursive=True)
    
  • 获取一个OBS文件或文件夹的stat信息,stat信息中包含如下信息。
    • length:文件大小。
    • mtime_nsec:创建时间戳。
    • is_directory:是否为目录。
    例如查询一个OBS文件“obs://bucket_name/obs_file.txt”,此文件地址也可以替换成一个文件夹地址。
    1
    2
    3
    4
    5
    import moxing as mox
    stat = mox.file.stat('obs://bucket_name/obs_file.txt')
    print(stat.length)
    print(stat.mtime_nsec)
    print(stat.is_directory)
    

删除操作

  • 删除一个OBS文件。
    例如删除“obs://bucket_name/obs_file.txt”
    1
    2
    import moxing as mox
    mox.file.remove('obs://bucket_name/obs_file.txt')
    
  • 删除一个OBS目录,并且递归的删除这个目录下的所有内容。如果这个目录不存在,则会报错。
    例如删除“obs://bucket_name/sub_dir_0”下的所有内容。
    1
    2
    import moxing as mox
    mox.file.remove('obs://bucket_name/sub_dir_0', recursive=True)
    

设置参数

  • 使用mox.file.set_auth函数设置所有可配置的参数。
    #配置moxing读取的参数,具体如下,对于不需要修改配置项不用显示指定即可,该API全局执行一次,不能多次执行 
    #ak - Access Key , 字符串类型,在ModelArts使用时使用时,系统默认配置,其他环境参考统一身份认证
    #sk - Secret Access Key,字符串类型,在ModelArts使用时使用时,系统默认配置,其他环境参考统一身份认证
    #server - OBS 服务端, 在ModelArts使用时,系统默认配置,其他环境配置参考https://support.huaweicloud.com/productdesc-obs/obs_03_0152.html
    #port - OBS服务器端口, 在ModelArts使用时,系统默认配置,其他环境配置参考server,一般不会给定特殊端口号,不需要配置
    #is_secure - 是否使用https, 布尔类型,默认值为True
    #ssl_verify - 是否使用ssl验证,布尔类型,默认值为False
    #long_conn_mode - 是否使用长连接模式,布尔类型,默认配置为True
    #path_style - 是否使用路径风格. 布尔类型,HEC则默认设置为True,当为公有云则默认设置为False,默认不建议修改
    #retry - 总共尝试的次数,类型为整型,默认值为10,单位为次
    #retry_wait - 在每次尝试时所等待的时间,类型为浮点型,默认值为0.1,单位秒,若不配置,则第一次等待0.1秒,第二次失败等待0.2秒,第三次为0.4秒,指数递增#client_timeout - obs客户端超时时间, 类型为整型,默认值为30, 单位秒#list_max_keys - 每页列出的最大对象数,用于list_directory api,类型为整型,默认值为1000, 单位为个 
    import moxing as mox 
    mox.file.set_auth(ak='xxx', sk='xxx')
  • 删除一个OBS目录,并且递归的删除这个目录下的所有内容。如果这个目录不存在,则会报错。
    例如删除“obs://bucket_name/sub_dir_0”下的所有内容。
    1
    2
    import moxing as mox
    mox.file.remove('obs://bucket_name/sub_dir_0', recursive=True)