Android获取可存储文件所有路径-阿里云开发者社区

开发者社区> ansen_666> 正文

Android获取可存储文件所有路径

简介:
+关注继续查看

引言:大家在做app开发的时候,基本都会保存文件到手机,android存储文件的地方有很多,不像ios一样,只能把文件存储到当前app目录下,并且android手机由于厂家定制了rom,sdcard的路径在不同手机上都会不一样.我这边封装了获取路径的几个方法,放在一个工具类里面.

1.获取扩展存储设备
2.获取sdcard2外部存储空间
3.获取可用的 EMMC 内部存储空间
4.获取其他外部存储可用空间
5.获取内部存储目录


Activity  程序的入口,在oncreate方法里面通过工具类获取文件保存路径,并且打印出来.(还写了一个创建指定大小空文件的方法,有需要的可以调用)

  1. /** 
  2.  * 获取存储路径,并且打印出来 
  3.  * @author ansen 
  4.  * @create time 2015-09-07 
  5.  */  
  6. public class MainActivity extends Activity {  
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.           
  12.         String str=FileUtil.getCachePath();  
  13. //      writeFileSize(str+"/ansen.mp3",50);  //在当前目录下创建ansen.mp3文件  文件长度50兆  
  14.         System.out.println(str);  
  15.     }  
  16.       
  17.     /** 
  18.      * 创建指定大小的文件.写入空数据 
  19.      * @param filePath  文件路径 
  20.      * @param size  文件长度  单位是兆 
  21.      */  
  22.     private void writeFileSize(String filePath,int size){  
  23.         try {  
  24.             RandomAccessFile raf = new RandomAccessFile(filePath,"rw");  
  25.             raf.seek(raf.length());//每次从文件末尾写入  
  26.             for (int i = 0; i < size; i++) {//一共写入260兆,想写多大的文件改变这个值就行  
  27.                 byte[] buffer = new byte[1024*1024]; //1次1M,这样内存开的大一些,又不是特别大。  
  28.                 raf.write(buffer);  
  29.                 System.out.println("写入1兆..."+i);  
  30.             }  
  31.             raf.close();  
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.     }  
  36. }  


文件工具类  封装了一个公共方法,获取文件保存路径,一共可以获取5个路径,依次判断5个路径预留空间是否大于50兆.大于就直接返回路径

  1. /** 
  2.  * 文件工具类 
  3.  * @author ansen 
  4.  * @create time 2015-09-07 
  5.  */  
  6. public final class FileUtil {  
  7.     private static final String FOLDER_NAME = "ansen";//这里可以换成你的app名称  
  8.     private static final long MIN_STORAGE=52428800;//50*1024*1024最低50m  
  9.       
  10.     //缓存路径  
  11.     public static String getCachePath(){  
  12.         String path = getSavePath(MIN_STORAGE);  
  13.         if(TextUtils.isEmpty(path)){  
  14.             return null;  
  15.         }  
  16.         path= path + FOLDER_NAME + "/cache";  
  17.         makeDir(path);  
  18.         return path;  
  19.     }  
  20.       
  21.     /** 
  22.      * 获取保存文件路径   
  23.      * @param saveSize  预留空间 
  24.      * @return 文件路径 
  25.      */  
  26.     private static String getSavePath(long saveSize) {  
  27.         String savePath = null;  
  28.         if (StorageUtil.getExternaltStorageAvailableSpace() > saveSize) {//扩展存储设备>预留空间  
  29.             savePath = StorageUtil.getExternalStorageDirectory();  
  30.             File saveFile = new File(savePath);  
  31.             if (!saveFile.exists()) {  
  32.                 saveFile.mkdirs();  
  33.             } else if (!saveFile.isDirectory()) {  
  34.                 saveFile.delete();  
  35.                 saveFile.mkdirs();  
  36.             }  
  37.         } else if (StorageUtil.getSdcard2StorageAvailableSpace() > saveSize) {//sdcard2外部存储空间>预留空间  
  38.             savePath = StorageUtil.getSdcard2StorageDirectory();  
  39.             File saveFile = new File(savePath);  
  40.             if (!saveFile.exists()) {  
  41.                 saveFile.mkdirs();  
  42.             } else if (!saveFile.isDirectory()) {  
  43.                 saveFile.delete();  
  44.                 saveFile.mkdirs();  
  45.             }  
  46.         } else if (StorageUtil.getEmmcStorageAvailableSpace() > saveSize) {//可用的 EMMC 内部存储空间>预留空间  
  47.             savePath = StorageUtil.getEmmcStorageDirectory();  
  48.             File saveFile = new File(savePath);  
  49.             if (!saveFile.exists()) {  
  50.                 saveFile.mkdirs();  
  51.             } else if (!saveFile.isDirectory()) {  
  52.                 saveFile.delete();  
  53.                 saveFile.mkdirs();  
  54.             }  
  55.         } else if (StorageUtil.getOtherExternaltStorageAvailableSpace()>saveSize) {//其他外部存储可用空间>预留空间  
  56.             savePath = StorageUtil.getOtherExternalStorageDirectory();  
  57.             File saveFile = new File(savePath);  
  58.             if (!saveFile.exists()) {  
  59.                 saveFile.mkdirs();  
  60.             } else if (!saveFile.isDirectory()) {  
  61.                 saveFile.delete();  
  62.                 saveFile.mkdirs();  
  63.             }  
  64.         }else if (StorageUtil.getInternalStorageAvailableSpace() > saveSize) {//内部存储目录>预留空间  
  65.             savePath = StorageUtil.getInternalStorageDirectory() + File.separator;  
  66.         }  
  67.         return savePath;  
  68.     }  
  69.       
  70.     /** 
  71.      * 创建文件夹 
  72.      * @param path 
  73.      */  
  74.     private static void makeDir(String path){  
  75.         File file = new File(path);  
  76.         if(!file.exists()){  
  77.             file.mkdirs();  
  78.         }  
  79.         file = null;  
  80.     }  
  81. }  



封装了获取各种路径的一些方法,供FileUtil类调用.

  1. /** 
  2.  * 封装了获取文件路径的一些方法 
  3.  * @author ansen 
  4.  * @create time 2015-09-07 
  5.  */  
  6. @SuppressLint("NewApi")  
  7. public final class StorageUtil {  
  8.     private static String otherExternalStorageDirectory = null;  
  9.     private static int kOtherExternalStorageStateUnknow = -1;  
  10.     private static int kOtherExternalStorageStateUnable = 0;  
  11.     private static int kOtherExternalStorageStateIdle = 1;  
  12.     private static int otherExternalStorageState = kOtherExternalStorageStateUnknow;  
  13.     private static String internalStorageDirectory;  
  14.       
  15.     public static Context context;  
  16.   
  17.     public static void init(Context cxt) {  
  18.         context = cxt;  
  19.     }  
  20.       
  21.     /** get external Storage available space */  
  22.     public static long getExternaltStorageAvailableSpace() {  
  23.         if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
  24.             return 0;  
  25.         }  
  26.         File path = Environment.getExternalStorageDirectory();  
  27.         StatFs statfs = new StatFs(path.getPath());  
  28.           
  29.         long blockSize;  
  30.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  31.             blockSize = statfs.getBlockSizeLong();  
  32.         }else {  
  33.             blockSize = statfs.getBlockSize();  
  34.         }  
  35.   
  36.         long availableBlocks;  
  37.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  38.             availableBlocks = statfs.getAvailableBlocksLong();  
  39.         }else {  
  40.             availableBlocks = statfs.getAvailableBlocks();  
  41.         }  
  42.         return blockSize * availableBlocks;  
  43.     }  
  44.       
  45.     public final static String getInternalStorageDirectory() {  
  46.         if (TextUtils.isEmpty(internalStorageDirectory)) {  
  47.             File file = context.getFilesDir();  
  48.             internalStorageDirectory = file.getAbsolutePath();  
  49.             if (!file.exists())  
  50.                 file.mkdirs();  
  51.             String shellScript = "chmod 705 " + internalStorageDirectory;  
  52.             runShellScriptForWait(shellScript);  
  53.         }  
  54.         return internalStorageDirectory;  
  55.     }  
  56.       
  57.     public static long getInternalStorageAvailableSpace() {  
  58.         String path = getInternalStorageDirectory();  
  59.         StatFs stat = new StatFs(path);  
  60. //      long blockSize = stat.getBlockSizeLong();  
  61.         long blockSize;  
  62.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  63.             blockSize = stat.getBlockSizeLong();  
  64.         }else {  
  65.             blockSize = stat.getBlockSize();  
  66.         }  
  67. //      long availableBlocks = stat.getAvailableBlocksLong();  
  68.         long availableBlocks;  
  69.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  70.             availableBlocks = stat.getAvailableBlocksLong();  
  71.         }else {  
  72.             availableBlocks = stat.getAvailableBlocks();  
  73.         }  
  74.           
  75.         return blockSize * availableBlocks;  
  76.     }  
  77.       
  78.       
  79.       
  80.     public final static String getExternalStorageDirectory() {  
  81.         return Environment.getExternalStorageDirectory() + File.separator + "";  
  82.     }  
  83.       
  84.     /** get sdcard2 external Storage available space */  
  85.     public static long getSdcard2StorageAvailableSpace() {  
  86.         if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
  87.             return 0;  
  88.         }  
  89.         String path = getSdcard2StorageDirectory();  
  90.         File file = new File(path);  
  91.         if (!file.exists())  
  92.             return 0;  
  93.         StatFs statfs = new StatFs(path);  
  94. //      long blockSize = statfs.getBlockSizeLong();  
  95.         long blockSize;  
  96.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  97.             blockSize = statfs.getBlockSizeLong();  
  98.         }else {  
  99.             blockSize = statfs.getBlockSize();  
  100.         }  
  101.           
  102. //      long availableBlocks = statfs.getAvailableBlocksLong();  
  103.         long availableBlocks;  
  104.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  105.             availableBlocks = statfs.getAvailableBlocksLong();  
  106.         }else {  
  107.             availableBlocks = statfs.getAvailableBlocks();  
  108.         }  
  109.           
  110.         return blockSize * availableBlocks;  
  111.     }  
  112.       
  113.     public final static String getSdcard2StorageDirectory() {  
  114.         return "/mnt/sdcard2/";  
  115.     }  
  116.       
  117.     public static boolean runShellScriptForWait(final String cmd)throws SecurityException {  
  118.         ShellThread thread = new ShellThread(cmd);  
  119.         thread.setDaemon(true);  
  120.         thread.start();  
  121.         int k = 0;  
  122.         while (!thread.isReturn() && k++ < 20) {  
  123.             try {  
  124.                 Thread.sleep(50);  
  125.             } catch (InterruptedException e) {  
  126.                 // TODO Auto-generated catch block  
  127.                 e.printStackTrace();  
  128.             }  
  129.         }  
  130.         if (k >= 20) {  
  131.             thread.interrupt();  
  132.         }  
  133.         return thread.isSuccess();  
  134.     }  
  135.       
  136.     /** 用于执行shell脚本的线程 */  
  137.     private static class ShellThread extends Thread {  
  138.         private boolean isReturn;  
  139.         private boolean isSuccess;  
  140.         private String cmd;  
  141.   
  142.         public boolean isReturn() {  
  143.             return isReturn;  
  144.         }  
  145.   
  146.         public boolean isSuccess() {  
  147.             return isSuccess;  
  148.         }  
  149.   
  150.         /** 
  151.          * @param cmd shell命令内容 
  152.          * @param isReturn  线程是否已经返回 
  153.          * @param isSuccess Process是否执行成功 
  154.          */  
  155.         public ShellThread(String cmd) {  
  156.             this.cmd = cmd;  
  157.         }  
  158.   
  159.         @Override  
  160.         public void run() {  
  161.             try {  
  162.                 Runtime runtime = Runtime.getRuntime();  
  163.                 Process proc;  
  164.                 try {  
  165.                     proc = runtime.exec(cmd);  
  166.                     isSuccess = (proc.waitFor() == 0);  
  167.                 } catch (IOException e) {  
  168.                     e.printStackTrace();  
  169.                 }  
  170.                 isSuccess = true;  
  171.             } catch (InterruptedException e) {  
  172.             }  
  173.             isReturn = true;  
  174.         }  
  175.     }  
  176.       
  177.     /** get EMMC internal Storage available space */  
  178.     public static long getEmmcStorageAvailableSpace() {  
  179.         String path = getEmmcStorageDirectory();  
  180.         File file = new File(path);  
  181.         if (!file.exists())  
  182.             return 0;  
  183.         StatFs statfs = new StatFs(path);  
  184. //      long blockSize = statfs.getBlockSizeLong();  
  185.         long blockSize;  
  186.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  187.             blockSize = statfs.getBlockSizeLong();  
  188.         }else {  
  189.             blockSize = statfs.getBlockSize();  
  190.         }  
  191.           
  192. //      long availableBlocks = statfs.getAvailableBlocksLong();  
  193.         long availableBlocks;  
  194.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  195.             availableBlocks = statfs.getAvailableBlocksLong();  
  196.         }else {  
  197.             availableBlocks = statfs.getAvailableBlocks();  
  198.         }  
  199.   
  200.         return blockSize * availableBlocks;  
  201.     }  
  202.       
  203.     public final static String getEmmcStorageDirectory() {  
  204.         return "/mnt/emmc/";  
  205.     }  
  206.       
  207.     /** get other external Storage available space */  
  208.     public static long getOtherExternaltStorageAvailableSpace() {  
  209.         if (!Environment.getExternalStorageState().equals(  
  210.                 Environment.MEDIA_MOUNTED)) {  
  211.             return 0;  
  212.         }  
  213.         if (otherExternalStorageState == kOtherExternalStorageStateUnable)  
  214.             return 0;  
  215.         if (otherExternalStorageDirectory == null) {  
  216.             getOtherExternalStorageDirectory();  
  217.         }  
  218.         if (otherExternalStorageDirectory == null)  
  219.             return 0;  
  220.         StatFs statfs = new StatFs(otherExternalStorageDirectory);  
  221. //      long blockSize = statfs.getBlockSizeLong();  
  222.         long blockSize;  
  223.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  224.             blockSize = statfs.getBlockSizeLong();  
  225.         }else {  
  226.             blockSize = statfs.getBlockSize();  
  227.         }  
  228. //      long availableBlocks = statfs.getAvailableBlocksLong();  
  229.         long availableBlocks;  
  230.         if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  231.             availableBlocks = statfs.getAvailableBlocksLong();  
  232.         }else {  
  233.             availableBlocks = statfs.getAvailableBlocks();  
  234.         }  
  235.         return blockSize * availableBlocks;  
  236.     }  
  237.       
  238.       
  239.     public static String getOtherExternalStorageDirectory() {  
  240.         if (otherExternalStorageState == kOtherExternalStorageStateUnable)  
  241.             return null;  
  242.         if (otherExternalStorageState == kOtherExternalStorageStateUnknow) {  
  243.             FstabReader fsReader = new FstabReader();  
  244.             if (fsReader.size() <= 0) {  
  245.                 otherExternalStorageState = kOtherExternalStorageStateUnable;  
  246.                 return null;  
  247.             }  
  248.             List<StorageInfo> storages = fsReader.getStorages();  
  249.             /* 对于可用空间小于100M的挂载节点忽略掉 */  
  250.             long availableSpace = 100 << (20);  
  251.             String path = null;  
  252.             for (int i = 0; i < storages.size(); i++) {  
  253.                 StorageInfo info = storages.get(i);  
  254.                 if (info.getAvailableSpace() > availableSpace) {  
  255.                     availableSpace = info.getAvailableSpace();  
  256.                     path = info.getPath();  
  257.                 }  
  258.             }  
  259.             otherExternalStorageDirectory = path;  
  260.             if (otherExternalStorageDirectory != null) {  
  261.                 otherExternalStorageState = kOtherExternalStorageStateIdle;  
  262.             } else {  
  263.                 otherExternalStorageState = kOtherExternalStorageStateUnable;  
  264.             }  
  265.             if(!TextUtils.isEmpty(otherExternalStorageDirectory)){  
  266.                 if(!otherExternalStorageDirectory.endsWith("/")){  
  267.                     otherExternalStorageDirectory=otherExternalStorageDirectory+"/";  
  268.                 }  
  269.             }  
  270.         }  
  271.         return otherExternalStorageDirectory;  
  272.     }  
  273.       
  274.     public static class FstabReader {  
  275.         public FstabReader() {  
  276.             init();  
  277.         }  
  278.   
  279.         public int size() {  
  280.             return storages == null ? 0 : storages.size();  
  281.         }  
  282.   
  283.         public List<StorageInfo> getStorages() {  
  284.             return storages;  
  285.         }  
  286.   
  287.         final List<StorageInfo> storages = new ArrayList<StorageInfo>();  
  288.   
  289.         public void init() {  
  290.             File file = new File("/system/etc/vold.fstab");  
  291.             if (file.exists()) {  
  292.                 FileReader fr = null;  
  293.                 BufferedReader br = null;  
  294.                 try {  
  295.                     fr = new FileReader(file);  
  296.                     if (fr != null) {  
  297.                         br = new BufferedReader(fr);  
  298.                         String s = br.readLine();  
  299.                         while (s != null) {  
  300.                             if (s.startsWith("dev_mount")) {  
  301.                                 /* "\s"转义符匹配的内容有:半/全角空格 */  
  302.                                 String[] tokens = s.split("\\s");  
  303.                                 String path = tokens[2]; // mount_point  
  304.                                 StatFs stat = new StatFs(path);  
  305.                                   
  306.                                 long blockSize;  
  307.                                 long totalBlocks;  
  308.                                 long availableBlocks;  
  309.                                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  310.                                     blockSize = stat.getBlockSizeLong();  
  311.                                 }else {  
  312.                                     blockSize = stat.getBlockSize();  
  313.                                 }  
  314.                                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  315.                                     totalBlocks = stat.getBlockCountLong();  
  316.                                 }else {  
  317.                                     totalBlocks = stat.getBlockCount();  
  318.                                 }  
  319.                                 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
  320.                                     availableBlocks = stat.getAvailableBlocksLong();  
  321.                                 }else {  
  322.                                     availableBlocks = stat.getAvailableBlocks();  
  323.                                 }  
  324.                                   
  325. //                              if (null != stat&& stat.getAvailableBlocksLong() > 0) {  
  326. //  
  327. //                                  long availableSpace = stat.getAvailableBlocksLong()* stat.getBlockSizeLong();  
  328. //                                  long totalSpace = stat.getBlockCountLong()* stat.getBlockSizeLong();  
  329.                                 if (null != stat&& availableBlocks > 0) {  
  330.   
  331.                                     long availableSpace = availableBlocks* blockSize;  
  332.                                     long totalSpace = totalBlocks* blockSize;  
  333.                                     StorageInfo storage = new StorageInfo(path,  
  334.                                             availableSpace, totalSpace);  
  335.                                     storages.add(storage);  
  336.                                 }  
  337.                             }  
  338.                             s = br.readLine();  
  339.                         }  
  340.                     }  
  341.                 } catch (Exception e) {  
  342.                     e.printStackTrace();  
  343.                 } finally {  
  344.                     if (fr != null)  
  345.                         try {  
  346.                             fr.close();  
  347.                         } catch (IOException e) {  
  348.                             // TODO Auto-generated catch block  
  349.                             e.printStackTrace();  
  350.                         }  
  351.                     if (br != null)  
  352.                         try {  
  353.                             br.close();  
  354.                         } catch (IOException e) {  
  355.                             // TODO Auto-generated catch block  
  356.                             e.printStackTrace();  
  357.                         }  
  358.                 }  
  359.             }  
  360.         }  
  361.     }  
  362.   
  363.     static class StorageInfo implements Comparable<StorageInfo> {  
  364.         private String path;  
  365.         private long availableSpace;  
  366.         private long totalSpace;  
  367.   
  368.         StorageInfo(String path, long availableSpace, long totalSpace) {  
  369.             this.path = path;  
  370.             this.availableSpace = availableSpace;  
  371.             this.totalSpace = totalSpace;  
  372.         }  
  373.   
  374.         @Override  
  375.         public int compareTo(StorageInfo another) {  
  376.             if (null == another)  
  377.                 return 1;  
  378.   
  379.             return this.totalSpace - another.totalSpace > 0 ? 1 : -1;  
  380.         }  
  381.   
  382.         long getAvailableSpace() {  
  383.             return availableSpace;  
  384.         }  
  385.   
  386.         long getTotalSpace() {  
  387.             return totalSpace;  
  388.         }  
  389.   
  390.         String getPath() {  
  391.             return path;  
  392.         }  
  393.     }  
  394.       
  395. }  


最后记得在AndroidManifest.xml中配置读写sdcard权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />


点击下载源码

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Android存储之SQLite数据库
Android存储之SQLite数据库数据库 创建数据库 package ……; import android.
703 0
文件存储管理文件系统的操作有哪些?
本文介绍如何在NAS控制台上管理文件系统,包括创建文件系统、查看文件系统列表、查看文件系统详情、删除文件系统等操作。
770 0
Android存储之SQLite数据库
Android存储之SQLite数据库数据库 创建数据库 package ……; import android.
493 0
Android获取移动设备IP地址
MainActivity如下: package cn.testip; import java.net.InetAddress; import java.
660 0
Android存储访问及目录
原文:Android存储访问及目录   Android存储访问及目录   Android的外部存储   Android支持外部存储(case-insensitive filesystem with immutable POSIX permission classes and modes)。
952 0
文件存储:购买存储包的方法及常见问题
通用型NAS支持绑定存储包,您可以先创建文件系统再绑定存储包,也可以在购买存储包时创建文件系统。
373 0
Android:StatFs类 获取系统/sdcard存储空间信息
在存储文件时,为了保证有充足的存储空间大小,通常需要知道系统内部或者sdcard的剩余存储空间大小,这里就需要用到StatFs类。 1. 判断 SDCard 是否存在,并且是否具有可读写权限  [java] view plaincopyprint? /** * 外部存储是...
1005 0
Android二级缓存之物理存储介质上的缓存DiskLruCache
 Android二级缓存之物理存储介质上的缓存DiskLruCache Android DiskLruCache属于物理性质的缓存,相较于LruCache缓存,则DiskLruCache属于Android二级缓存中的最后一级。
705 0
+关注
ansen_666
有三年android开发经验,开发过加密.短视频.直播app,一直在互联网公司工作,目前就职于上海翼成科技,担任android开发组长。
62
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载