• 封装一个帮助类来写文件到android外置存储器上


    项目地址:点击打开

    项目简介:写文件到android外置存储器的一个帮助类,和它的demo程序

    它是如何工作的呢?

    1.创建 AppExternalFileWriter 对象并传递context(上下文);

    2.按照你的要求使用 writeDataToFile 或者 writeDataToTimeStampedFile 不同的方法;

    3.如果你想写入的文件需要有时间标注的数据,那么使用writeDataToTimeStampedFile类型

    4.如果你想创建一个下级目录,那么可以使用灵活的 createSubDirectory类型

    5.如果外置存储设比有任何的问题,比如设备没有挂载,作为大容量存储设备,空间容量不足,或者甚至是创建一个已经存在的库文件,该类运行的时候会抛出一个ExternalFileWriterException异常信息。

    6.如果你想在外部缓存中写入数据,那么做如下操作:

    *检查所有方法的变体(variants),它需要一个boolean类型的参数,如果你传进一个true值,文件操作在cpu缓存中已经完成了,否则将在标准外部存储器中完成。

    *如果你在cpu缓存中已经通过createDirectory方法创建了一个目录,把这个目录传递给任何父类需要的方法。这些方法不管父类是在外置存储器或者cpu缓存中工作是一样的。

    7.检查某些目录或者文件是否存在某些位置或者不借助isFileExists、isDirectoryExists方法。

    8.用deleteDirectory方法删除整个目录。(注意:该方法之关心删除整个目录与它相关的上级目录,如果检查目录是否为空使用一些错误消息推荐使用 File.delete() 方法。

    关于Variants的描述

    1.writeDataToFile--没有父级目录

    writeDataToFile(String fileName, byte[] data,boolean inCache);
    writeDataToFile(String fileName, String data,boolean inCache);

    在程序的目录将数据写入自定义的文件

    a.writeDataToFile---在父级路径

    writeDataToFile(File parent, String fileName, byte[] data);
    writeDataToFile(File parent, String fileName, String data);

    b.在其他的路径写入数据到自定义文件名称

    b1 writeDataToTimeStampedFile方法---没有父级路径

    writeDataToTimeStampedFile(String extension, byte[] data,boolean inCache)
    writeDataToTimeStampedFile(String extension, String data,boolean inCache)

    b2 writeDataToTimeStampedFile方法----带有父级路径

    writeDataToTimeStampedFile(String extension, byte[] data)
    writeDataToTimeStampedFile(String extension, String data)

    在其他目录下写入数据到指定文件,并伴有时间标识扩展

    c1 createSubDirectory方法

    createSubDirectory(File parent, String directoryName)

    在其他目录下创建上级目录

    createSubDirectory(String directoryName,boolean inCache)

    在应用程序目录创建上级目录

        isDirectoryExists方法

    isDirectoryExists(String directoryName, boolean checkInCache)

        检查赋予的目录名称是否存在在程序目录下或者缓存目录

    isDirectoryExists(String directoryName, File parentDirectory)

    检查给予名称的目录是否存在与父路径

    a isFileExists 方法

    isFileExists(String fileName, boolean checkInCache)

    检查给予的文件名称是否存在在程序目录下(parentDirectory )

    isFileExists(String fileName, File parentDirectory)

    删除目录

    deleteDirectory(File directory)

    删除指定指定的目录和它上级的所有文件(翻译的还是很别扭)

    一些好的建议(some goodies)

    1.getAppDirectory() : 创建app目录的文件对象
    
    2.getExternalStorageDirectory() : 获取外置存储目录文件对象
    
    3.getExternalCacheDirectory() : 获取外置缓存目录对象

    完整类的AppExternalFileWriter.java

      1 package com.example.filewrite;
      2 
      3 import java.io.File;
      4 import java.io.FileOutputStream;
      5 import java.io.IOException;
      6 
      7 import android.content.Context;
      8 import android.os.Environment;
      9 import android.os.StatFs;
     10 import android.text.TextUtils;
     11 
     12 /**
     13  * @author Prasham Trivedi
     14  * @version 2.5
     15  *          <p>
     16  *          This class will create a directory having same name as your
     17  *          application. With all the states handled and reported back to
     18  *          developer.
     19  *          </p>
     20  */
     21 public class AppExternalFileWriter {
     22 
     23     private static final String canNotWriteFile = "Can not write file: ";
     24     private static final String canNotCreateDirectory = "Can not create directory: ";
     25     private final File externalStorageDirectory;
     26     private final File externalCacheDirectory;
     27     private Context context;
     28     private File appDirectory;
     29     private File appCacheDirectory;
     30 
     31     /**
     32      * Creates external file writer
     33      *
     34      * @param context
     35      *            : Context
     36      */
     37     public AppExternalFileWriter(Context context) {
     38         this.context = context;
     39         externalStorageDirectory = Environment.getExternalStorageDirectory();
     40         externalCacheDirectory = context.getExternalCacheDir();
     41 
     42     }
     43 
     44     private File createFile(String fileName, boolean inCache)
     45             throws ExternalFileWriterException {
     46         return createFile(fileName, getAppDirectory(inCache));
     47     }
     48 
     49     /**
     50      * Create a file in the app directory with given file name.
     51      *
     52      * @param fileName
     53      *            : Desired name of the file
     54      * @param parent
     55      *            parent of the file
     56      *
     57      * @return : File with desired name
     58      */
     59     private File createFile(String fileName, File parent)
     60             throws ExternalFileWriterException {
     61         if (isExternalStorageAvailable(true)) {
     62             try {
     63 
     64                 if (parent.isDirectory()) {
     65 
     66                     File detailFile = new File(parent, fileName);
     67                     if (!detailFile.exists())
     68                         detailFile.createNewFile();
     69                     else {
     70                         String messege = "File already there ";
     71                         throwException(messege);
     72                     }
     73                     return detailFile;
     74                 } else {
     75                     throwException(parent + " should be a directory");
     76                 }
     77             } catch (IOException e) {
     78                 e.printStackTrace();
     79                 String errorMessege = "IOException " + e;
     80                 throwException(errorMessege);
     81             } catch (Exception e) {
     82                 e.printStackTrace();
     83                 String errorMessege = "Exception " + e;
     84                 throwException(errorMessege);
     85             }
     86         }
     87         return null;
     88     }
     89 
     90     /** Creates app directory */
     91     private void createAppDirectory() throws ExternalFileWriterException {
     92         String directoryName = context
     93                 .getString(context.getApplicationInfo().labelRes);
     94 
     95         if (isExternalStorageAvailable(false)) {
     96 
     97             appDirectory = new File(Environment.getExternalStorageDirectory()
     98                     .toString(), directoryName);
     99             createDirectory(appDirectory);
    100 
    101             appCacheDirectory = new File(externalCacheDirectory, directoryName);
    102             createDirectory(appCacheDirectory);
    103 
    104         }
    105 
    106     }
    107 
    108     private double getAvailableSpace() {
    109         StatFs stat = new StatFs(Environment.getExternalStorageDirectory()
    110                 .getPath());
    111         double sdAvailSize = (double) stat.getAvailableBlocks()
    112                 * (double) stat.getBlockSize();
    113         return sdAvailSize;
    114     }
    115 
    116     private boolean isExternalStorageAvailable(boolean isForFile)
    117             throws ExternalFileWriterException {
    118         String errorStarter = (isForFile) ? canNotWriteFile
    119                 : canNotCreateDirectory;
    120 
    121         String storageState = Environment.getExternalStorageState();
    122 
    123         if (storageState.equals(Environment.MEDIA_MOUNTED)) {
    124             return true;
    125         } else if (storageState.equals(Environment.MEDIA_BAD_REMOVAL)) {
    126             throwException(errorStarter
    127                     + "Media was removed before it was unmounted.");
    128         } else if (storageState.equals(Environment.MEDIA_CHECKING)) {
    129             throwException(errorStarter
    130                     + "Media is present and being disk-checked, "
    131                     + "Please wait and try after some time");
    132         } else if (storageState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
    133             throwException(errorStarter + "Presented Media is read only");
    134         } else if (storageState.equals(Environment.MEDIA_NOFS)) {
    135             throwException(errorStarter + "Blank or unsupported file media");
    136         } else if (storageState.equals(Environment.MEDIA_SHARED)) {
    137             throwException(errorStarter
    138                     + "Media is shared with USB mass storage");
    139         } else if (storageState.equals(Environment.MEDIA_REMOVED)) {
    140             throwException(errorStarter + "Media is not present");
    141         } else if (storageState.equals(Environment.MEDIA_UNMOUNTABLE)) {
    142             throwException(errorStarter
    143                     + "Media is present but cannot be mounted");
    144         } else if (storageState.equals(Environment.MEDIA_UNMOUNTED)) {
    145             throwException(errorStarter + "Media is present but not mounted");
    146         }
    147 
    148         return false;
    149     }
    150 
    151     private void throwException(String errorMessege)
    152             throws ExternalFileWriterException {
    153         throw new ExternalFileWriterException(errorMessege);
    154     }
    155 
    156     private File createDirectory(File directory)
    157             throws ExternalFileWriterException {
    158         if (!directory.exists() || !directory.isDirectory()) {
    159             if (directory.mkdirs()) {
    160                 String messege = "directory " + directory + " created : Path "
    161                         + directory.getPath();
    162                 System.out.println(messege);
    163 
    164             } else {
    165                 if (directory.exists()) {
    166                     if (directory.isDirectory()) {
    167                         String messege = "directory " + directory
    168                                 + " Already exists : Path "
    169                                 + directory.getPath();
    170                         System.out.println(messege);
    171                     } else {
    172                         String messege = directory
    173                                 + "should be a directory but found a file : Path "
    174                                 + directory.getPath();
    175                         throwException(messege);
    176                         System.out.println(messege);
    177                     }
    178 
    179                 }
    180             }
    181         }
    182         return directory;
    183     }
    184 
    185     /**
    186      * Write byte array to file. Will show error if given file is a directory.
    187      *
    188      * @param file
    189      *            : File where data is to be written.
    190      * @param data
    191      *            String which you want to write a file. If size of this is
    192      *            greater than size available, it will show error.
    193      */
    194     private void writeDataToFile(File file, String data)
    195             throws ExternalFileWriterException {
    196         byte[] stringBuffer = data.getBytes();
    197         writeDataToFile(file, stringBuffer);
    198     }
    199 
    200     /**
    201      * Write byte array to file. Will show error if given file is a directory.
    202      *
    203      * @param file
    204      *            : File where data is to be written.
    205      * @param data
    206      *            byte array which you want to write a file. If size of this is
    207      *            greater than size available, it will show error.
    208      */
    209     private void writeDataToFile(File file, byte[] data)
    210             throws ExternalFileWriterException {
    211         if (isExternalStorageAvailable(true)) {
    212             if (file.isDirectory()) {
    213                 throwException(file
    214                         + " is not a file, can not write data in it");
    215             } else {
    216                 if (file != null && data != null) {
    217                     double dataSize = data.length;
    218                     double remainingSize = getAvailableSpace();
    219                     if (dataSize >= remainingSize) {
    220                         throwException("Not enough size available");
    221 
    222                     } else {
    223                         try {
    224                             FileOutputStream out = new FileOutputStream(file);
    225                             out.write(data);
    226                             out.close();
    227                         } catch (IOException e) {
    228                             e.printStackTrace();
    229                         } catch (Exception e) {
    230                             e.printStackTrace();
    231                         }
    232                     }
    233                 }
    234 
    235             }
    236         }
    237     }
    238 
    239     private File getAppDirectory(boolean inCache) {
    240         return (inCache) ? this.appCacheDirectory : this.appDirectory;
    241     }
    242 
    243     /**
    244      * Creates subdirectory in application directory
    245      *
    246      * @param directoryName
    247      *            name of subdirectory
    248      *
    249      * @return File object of created subdirectory
    250      *
    251      * @throws ExternalFileWriterException
    252      *             if external storage is not available
    253      */
    254     public File createSubDirectory(String directoryName, boolean inCache)
    255             throws ExternalFileWriterException {
    256         if (isExternalStorageAvailable(false)) {
    257 
    258             getAppDirectory();
    259 
    260             File subDirectory = new File(getAppDirectory(inCache),
    261                     directoryName);
    262 
    263             return createDirectory(subDirectory);
    264         } else
    265             return null;
    266     }
    267 
    268     /**
    269      * Checks whether directory with given name exists in AppDirectory
    270      *
    271      * @param directoryName
    272      *            : Name of the directory to check.
    273      *
    274      * @return true if a directory with "directoryName" exists, false otherwise
    275      */
    276     public boolean isDirectoryExists(String directoryName, boolean checkInCache) {
    277         File parentDirectory = (checkInCache) ? appCacheDirectory
    278                 : appDirectory;
    279         return isDirectoryExists(directoryName, parentDirectory);
    280     }
    281 
    282     /**
    283      * Check whether file with given name exists in parentDirectory or not.
    284      *
    285      * @param fileName
    286      *            : Name of the file to check.
    287      * @param parentDirectory
    288      *            : Parent directory where directory with "fileName" should be
    289      *            present
    290      *
    291      * @return true if a file with "fileName" exists, false otherwise
    292      */
    293     public boolean isFileExists(String fileName, File parentDirectory) {
    294         File directoryToCheck = new File(parentDirectory, fileName);
    295         return directoryToCheck.exists() && directoryToCheck.isFile();
    296     }
    297 
    298     /**
    299      * Checks whether file with given name exists in AppDirectory
    300      *
    301      * @param fileName
    302      *            : Name of the file to check.
    303      *
    304      * @return true if a file with "directoryName" exists, false otherwise
    305      */
    306     public boolean isFileExists(String fileName, boolean checkInCache) {
    307         File parentDirectory = (checkInCache) ? appCacheDirectory
    308                 : appDirectory;
    309         return isFileExists(fileName, parentDirectory);
    310     }
    311 
    312     /**
    313      * Check whether directory with given name exists in parentDirectory or not.
    314      *
    315      * @param directoryName
    316      *            : Name of the directory to check.
    317      * @param parentDirectory
    318      *            : Parent directory where directory with "directoryName" should
    319      *            be present
    320      *
    321      * @return true if a directory with "directoryName" exists, false otherwise
    322      */
    323     public boolean isDirectoryExists(String directoryName, File parentDirectory) {
    324         File directoryToCheck = new File(parentDirectory, directoryName);
    325         return directoryToCheck.exists() && directoryToCheck.isDirectory();
    326     }
    327 
    328     /**
    329      * Creates subdirectory in parent directory
    330      *
    331      * @param parent
    332      *            : Parent directory where directory with "directoryName" should
    333      *            be created
    334      * @param directoryName
    335      *            name of subdirectory
    336      *
    337      * @return File object of created subdirectory
    338      *
    339      * @throws ExternalFileWriterException
    340      *             if external storage is not available
    341      */
    342     public File createSubDirectory(File parent, String directoryName)
    343             throws ExternalFileWriterException {
    344         if (isExternalStorageAvailable(false)) {
    345 
    346             getAppDirectory();
    347 
    348             if (!parent.isDirectory())
    349                 throwException(parent.getName() + " Must be a directory ");
    350 
    351             File subDirectory = new File(parent, directoryName);
    352 
    353             return createDirectory(subDirectory);
    354         } else
    355             return null;
    356     }
    357 
    358     /**
    359      * Deletes given directory with all its subdirectories and its files.
    360      *
    361      * @param directory
    362      *            : Directory to delete
    363      */
    364     public void deleteDirectory(File directory) {
    365         if (directory != null) {
    366             if (directory.isDirectory())
    367                 for (File child : directory.listFiles()) {
    368 
    369                     if (child != null) {
    370                         if (child.isDirectory())
    371                             deleteDirectory(child);
    372                         else
    373                             child.delete();
    374                     }
    375                 }
    376 
    377             directory.delete();
    378         }
    379         // return false;
    380     }
    381 
    382     /**
    383      * Get created app directory
    384      *
    385      * @return File object of created AppDirectory
    386      */
    387     public File getAppDirectory() throws ExternalFileWriterException {
    388         if (appDirectory == null) {
    389             createAppDirectory();
    390         }
    391         return appDirectory;
    392     }
    393 
    394     /**
    395      * get External Cache directory
    396      *
    397      * @return File object of External Cache directory
    398      */
    399     public File getExternalCacheDirectory() {
    400         return externalCacheDirectory;
    401     }
    402 
    403     /**
    404      * Get external storage directory
    405      *
    406      * @return File object of external storage directory
    407      */
    408     public File getExternalStorageDirectory() {
    409         return externalStorageDirectory;
    410     }
    411 
    412     /**
    413      * Write data in file of a parent directory
    414      *
    415      * @param parent
    416      *            parent directory
    417      * @param fileName
    418      *            desired filename
    419      * @param data
    420      *            data
    421      *
    422      * @throws ExternalFileWriterException
    423      *             if external storage is not available or free space is less
    424      *             than size of the data
    425      */
    426     public void writeDataToFile(File parent, String fileName, byte[] data)
    427             throws ExternalFileWriterException {
    428         if (isExternalStorageAvailable(true)) {
    429             getAppDirectory();
    430 
    431             File file = createFile(fileName, parent);
    432 
    433             writeDataToFile(file, data);
    434         }
    435     }
    436 
    437     /**
    438      * Writes data to the file. The file will be created in the directory name
    439      * same as app.
    440      *
    441      * @param fileName
    442      *            name of the file
    443      * @param data
    444      *            data to write
    445      *
    446      * @throws ExternalFileWriterException
    447      *             if external storage is not available or free space is less
    448      *             than size of the data
    449      */
    450     public void writeDataToFile(String fileName, String data, boolean inCache)
    451             throws ExternalFileWriterException {
    452         if (isExternalStorageAvailable(true)) {
    453             getAppDirectory();
    454 
    455             File file = createFile(fileName, inCache);
    456 
    457             writeDataToFile(file, data);
    458         }
    459     }
    460 
    461     /**
    462      * Writes data to the file. The file will be created in the directory name
    463      * same as app.
    464      *
    465      * @param fileName
    466      *            name of the file
    467      * @param data
    468      *            data to write
    469      *
    470      * @throws ExternalFileWriterException
    471      *             if external storage is not available or free space is less
    472      *             than size of the data
    473      */
    474     public void writeDataToFile(String fileName, byte[] data, boolean inCache)
    475             throws ExternalFileWriterException {
    476         if (isExternalStorageAvailable(true)) {
    477             getAppDirectory();
    478 
    479             File file = createFile(fileName, inCache);
    480 
    481             writeDataToFile(file, data);
    482         }
    483     }
    484 
    485     /**
    486      * Write data in file of a parent directory
    487      *
    488      * @param parent
    489      *            parent directory
    490      * @param fileName
    491      *            desired filename
    492      * @param data
    493      *            data
    494      *
    495      * @throws ExternalFileWriterException
    496      *             if external storage is not available or free space is less
    497      *             than size of the data
    498      */
    499     public void writeDataToFile(File parent, String fileName, String data)
    500             throws ExternalFileWriterException {
    501         if (isExternalStorageAvailable(true)) {
    502             getAppDirectory();
    503 
    504             File file = createFile(fileName, parent);
    505 
    506             writeDataToFile(file, data);
    507         }
    508     }
    509 
    510     /**
    511      * Writes data to the file. The file will be created in the directory name
    512      * same as app.
    513      * <p>
    514      * Name of the file will be the timestamp.extension
    515      * </p>
    516      *
    517      * @param extension
    518      *            extension of the file, pass null if you don't want to have
    519      *            extension.
    520      * @param data
    521      *            data to write
    522      * @param inCache
    523      *            Pass true if you want to write data in External Cache. false
    524      *            if you want to write data in external directory.
    525      *
    526      * @throws ExternalFileWriterException
    527      *             if external storage is not available or free space is less
    528      *             than size of the data
    529      */
    530     public void writeDataToTimeStampedFile(String extension, String data,
    531             boolean inCache) throws ExternalFileWriterException {
    532         if (isExternalStorageAvailable(true)) {
    533             getAppDirectory();
    534 
    535             String fileExtension = (TextUtils.isEmpty(extension)) ? "" : "."
    536                     + extension;
    537             String fileName = System.currentTimeMillis() + fileExtension;
    538 
    539             File file = createFile(fileName, getAppDirectory(inCache));
    540 
    541             writeDataToFile(file, data);
    542         }
    543     }
    544 
    545     /**
    546      * Writes data to the file. The file will be created in the directory name
    547      * same as app.
    548      * <p>
    549      * Name of the file will be the timestamp.extension
    550      * </p>
    551      *
    552      * @param parent
    553      *            parent directory path
    554      * @param extension
    555      *            extension of the file, pass null if you don't want to have
    556      *            extension.
    557      * @param data
    558      *            data to write
    559      *
    560      * @throws ExternalFileWriterException
    561      *             if external storage is not available or free space is less
    562      *             than size of the data
    563      */
    564     public void writeDataToTimeStampedFile(File parent, String extension,
    565             String data) throws ExternalFileWriterException {
    566         if (isExternalStorageAvailable(true)) {
    567             getAppDirectory();
    568 
    569             String fileExtension = (TextUtils.isEmpty(extension)) ? "" : "."
    570                     + extension;
    571             String fileName = System.currentTimeMillis() + fileExtension;
    572 
    573             File file = createFile(fileName, parent);
    574 
    575             writeDataToFile(file, data);
    576         }
    577     }
    578 
    579     /**
    580      * Writes data to the file. The file will be created in the directory name
    581      * same as app.
    582      * <p>
    583      * Name of the file will be the timestamp.extension
    584      * </p>
    585      *
    586      * @param extension
    587      *            extension of the file, pass null if you don't want to have
    588      *            extension.
    589      * @param data
    590      *            data to write
    591      *
    592      * @throws ExternalFileWriterException
    593      *             if external storage is not available or free space is less
    594      *             than size of the data
    595      */
    596     public void writeDataToTimeStampedFile(String extension, byte[] data,
    597             boolean inCache) throws ExternalFileWriterException {
    598         if (isExternalStorageAvailable(true)) {
    599             getAppDirectory();
    600 
    601             String fileExtension = (TextUtils.isEmpty(extension)) ? "" : "."
    602                     + extension;
    603             String fileName = System.currentTimeMillis() + fileExtension;
    604 
    605             File file = createFile(fileName, getAppDirectory(inCache));
    606 
    607             writeDataToFile(file, data);
    608         }
    609     }
    610 
    611     /**
    612      * Writes data to the file. The file will be created in the directory name
    613      * same as app.
    614      * <p>
    615      * Name of the file will be the timestamp.extension
    616      * </p>
    617      *
    618      * @param parent
    619      *            parent directory path
    620      * @param extension
    621      *            extension of the file, pass null if you don't want to have
    622      *            extension.
    623      * @param data
    624      *            data to write
    625      *
    626      * @throws ExternalFileWriterException
    627      *             if external storage is not available or free space is less
    628      *             than size of the data
    629      */
    630     public void writeDataToTimeStampedFile(File parent, String extension,
    631             byte[] data) throws ExternalFileWriterException {
    632         if (isExternalStorageAvailable(true)) {
    633             getAppDirectory();
    634 
    635             String fileExtension = (TextUtils.isEmpty(extension)) ? "" : "."
    636                     + extension;
    637             String fileName = System.currentTimeMillis() + fileExtension;
    638 
    639             File file = createFile(fileName, parent);
    640 
    641             writeDataToFile(file, data);
    642         }
    643     }
    644 
    645     /**
    646      * Exception to report back developer about media state or storage state if
    647      * writing is not possible
    648      */
    649     public class ExternalFileWriterException extends Exception {
    650 
    651         public ExternalFileWriterException(String messege) {
    652             super(messege);
    653         }
    654 
    655     }
    656 }
    View Code

    在MainActivity.java中使用的方法如下:

    String test = "writer File class test";
    if (testFolder == null) {
        testFolder = writer.getExternalStorageDirectory();// 获取sd卡的根目录,testFolder和writer分别为File和AppExternalFileWriter(this)的实例
    }
    try {
       writer.writeDataToFile(testFolder, "fileName.txt",
                                test.getBytes());// 注意对应的惨胡分别为存储目录,写入的文件名称,byte[]
       } catch (ExternalFileWriterException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
      }

    注意添加写入的权限:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • 相关阅读:
    IO以及file的一些基本方法
    异常处理和Throwable中的几个方法
    Map的嵌套
    Collections
    Map接口
    Set接口
    React生命周期执行顺序详解
    当面试官问你GET和POST区别的时候,请这么回答.......
    webpack.config.js配置遇到Error: Cannot find module '@babel/core'&&Cannot find module '@babel/plugin-transform-react-jsx' 问题
    前端简单实现校招笔试'作弊监听'功能
  • 原文地址:https://www.cnblogs.com/sowhat4999/p/4461645.html
Copyright © 2020-2023  润新知