【问题标题】:How can I calculate the size of a folder?如何计算文件夹的大小?
【发布时间】:2011-01-12 09:46:40
【问题描述】:

我正在使用我的 iPhone 应用程序创建一个文件夹来缓存 Documents 中的图像。我希望能够将此文件夹的大小保持在 1MB,因此我需要检查文件夹的大小(以字节为单位)。

我有计算size of file 的代码,但我需要文件夹的大小。

最好的方法是什么?

【问题讨论】:

  • 使用 NSDirectoryEnumerator 和 fileAttributes 方法应该可以做到。
  • 不确定您的意思,但我尝试在答案below 中充分探索这一点。 TL;DR 版本是它看起来没有转义枚举文件。

标签: ios iphone nsfilemanager


【解决方案1】:

tl;博士

所有其他答案都关闭:)

问题

我想在这个老问题上加两分钱,因为似乎有很多答案都非常相似,但在某些情况下产生的结果非常不精确。

要了解为什么我们首先必须定义文件夹的大小。在我的理解(可能是 OP 之一)中,它是包含其所有内容的目录在卷上使用的字节数。或者,换一种说法:

如果目录将被完全删除,这是可用的空间。

我知道这个定义并不是解释问题的唯一有效方式,但我确实认为这是大多数用例归结为的原因。

错误

现有的答案都采用非常简单的方法:遍历目录内容,将(常规)文件的大小相加。这没有考虑到一些微妙之处。

  • 卷上使用的空间以而不是字节为单位递增。即使是一个字节的文件也至少使用一个块。
  • 文件携带元数据(与任何数量的扩展属性一样)。这些数据必须保存在某个地方。
  • HFS 部署文件系统压缩,以使用比实际长度更少的字节实际存储文件。

解决方案

所有这些原因使现有答案产生不精确的结果。所以我建议在NSFileManager 上进行这个扩展(由于长度原因,github 上的代码:Swift 4Objective C)来解决这个问题。它也快了很多,尤其是对于包含大量文件的目录。

解决方案的核心是使用NSURLNSURLTotalFileAllocatedSizeKeyNSURLFileAllocatedSizeKey 属性来检索文件大小。

测试

我还设置了a simple iOS test project,展示了解决方案之间的差异。它表明在某些情况下结果可能是完全错误的。

在测试中,我创建了一个包含 100 个小文件(范围从 0 到 800 字节)的目录。从其他答案复制的 folderSize: 方法计算出总共 21 kB,而我的 allocatedSize 方法产生 401 kB。

证明

我通过计算删除测试目录前后卷上可用字节的差异,确保allocatedSize 的结果更接近正确值。在我的测试中,差异总是完全等于allocatedSize 的结果。

请参阅 Rob Napier 的评论以了解仍有改进的空间。

性能

但还有另一个优势:在计算包含 1000 个文件的目录的大小时,在我的 iPhone 6 上,folderSize: 方法大约需要 250 毫秒,而allocatedSize 在 35 毫秒内遍历相同的层次结构。

这可能是由于使用NSFileManager 的新(ish)enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: API 来遍历层次结构。该方法让您可以为要迭代的项目指定预取属性,从而减少 io。

结果

Test `folderSize` (100 test files)
    size: 21 KB (21.368 bytes)
    time: 0.055 s
    actual bytes: 401 KB (401.408 bytes)

Test `allocatedSize` (100 test files)
    size: 401 KB (401.408 bytes)
    time: 0.048 s
    actual bytes: 401 KB (401.408 bytes)

Test `folderSize` (1000 test files)
    size: 2 MB (2.013.068 bytes)
    time: 0.263 s
    actual bytes: 4,1 MB (4.087.808 bytes)

Test `allocatedSize` (1000 test files)
    size: 4,1 MB (4.087.808 bytes)
    time: 0.034 s
    actual bytes: 4,1 MB (4.087.808 bytes)

【讨论】:

  • 非常有用的信息。有一个(非常)小的皱纹可能将此与“如果目录将被完全删除,空间变得可用”区分开来。如果树外的 inode 有任何硬链接,则删除这些硬链接实际上不会释放文件。硬链接不是特别常见,跨目录不太常见,甚至在 iOS 上更不常见,所以这是一个非常少的数量,并不会削弱这种技术的实用性。
  • 嗨@NikolaiRuhe,我正在尝试在Swift 项目中使用您的课程。我通过 Objective-C 标头添加了它,我可以像 NSFileManager.defaultManager().nr_getAllocatedSize(UnsafeMutablePointer<UInt64>, ofDirectoryAtURL: NSURL!) 这样调用方法。但是我不确定应该将什么传递给size 参数。我浏览了你的演示项目,但我还是有点困惑。
  • @Isuru size 参数是方法的实际结果,通过引用返回(在 Swift 中使用有点别扭)。如果您不想简单地将方法移植到更快捷的版本,您可以通过引用传递一个变量,如下所示:var size = UInt64(0); nr_getAllocatedSize(&size​, ofDirectoryAtURL: someURL)
  • @NikolaiRuhe 哇,这超出了我的预期!非常感谢。
  • @Keiwan 我特此在 MIT 许可下发布它。
【解决方案2】:

为 Alex 干杯,你帮了很多忙,现在已经编写了以下函数来解决问题...

- (unsigned long long int)folderSize:(NSString *)folderPath {
    NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
    NSString *fileName;
    unsigned long long int fileSize = 0;

    while (fileName = [filesEnumerator nextObject]) {
        NSDictionary *fileDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
        fileSize += [fileDictionary fileSize];
    }

    return fileSize;
}

它会像 Finder 一样提供确切的字节数。

顺便说一句,Finder 返回两个数字。一个是磁盘上的大小,另一个是实际的字节数。

例如,当我在我的一个文件夹上运行此代码时,它以 130398 的“fileSize”返回代码。当我签入 Finder 时,它显示磁盘上的大小为 201KB(130,398 字节)。

我有点不确定这里的实际大小(201KB 或 130,398 字节)。现在,为了安全起见,我将把限制减半,直到我弄清楚这到底意味着什么……

如果有人可以为这些不同的数字添加更多信息,我将不胜感激。

干杯,

【讨论】:

  • 我可以想到两个复杂性来解释这种差异:1024 字节相当于 1 KB(或 KiB?取决于你问谁)和“块大小”,文件的字节可以在哪里占用大块磁盘空间的倍数——这是文件系统级别的优化,取决于磁盘格式化和磁盘容量。例如,一个 1024 字节的文件实际上可能占用整个 16 KB 块,因此尽管它只使用 1024 字节,但它被列为 16 KB 文件。
  • @AlexReynolds - 正确。 “磁盘大小”表示实际用于存储文件的磁盘空间。第二个数字是文件本身的大小。这是两个不同的东西,磁盘上的大小几乎总是会更大。
  • @iphone_developer - 值得一提的是,这种方法非常昂贵。如果在主线程上完成,在包含数百或数千个小文件的大文件夹上调用它会使您的应用程序停止运行。如果你需要它没有错,只是值得指出。
  • 有没有办法以编程方式查找磁盘大小?
  • Nikolai Ruhe 的回答对于大量文件来说要快得多。
【解决方案3】:

这是在MBKBGB中获取文件夹和文件size的方法 -- -

1.文件夹大小 -

-(NSString *)sizeOfFolder:(NSString *)folderPath
{
    NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *contentsEnumurator = [contents objectEnumerator];

    NSString *file;
    unsigned long long int folderSize = 0;

    while (file = [contentsEnumurator nextObject]) {
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:file] error:nil];
        folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
    }

    //This line will give you formatted size from bytes ....
    NSString *folderSizeStr = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleFile];
    return folderSizeStr;
}

注意:如果是子文件夹,请使用subpathsOfDirectoryAtPath:而不是contentsOfDirectoryAtPath:

2。文件大小 -

-(NSString *)sizeOfFile:(NSString *)filePath
{
    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
    NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] integerValue];
    NSString *fileSizeStr = [NSByteCountFormatter stringFromByteCount:fileSize countStyle:NSByteCountFormatterCountStyleFile];
    return fileSizeStr;
}

--------- Swift 4.0 ----------

1.文件夹大小 -

func sizeOfFolder(_ folderPath: String) -> String? {
    do {
        let contents = try FileManager.default.contentsOfDirectory(atPath: folderPath)
        var folderSize: Int64 = 0
        for content in contents {
            do {
                let fullContentPath = folderPath + "/" + content
                let fileAttributes = try FileManager.default.attributesOfItem(atPath: fullContentPath)
                folderSize += fileAttributes[FileAttributeKey.size] as? Int64 ?? 0
            } catch _ {
                continue
            }
        }

        /// This line will give you formatted size from bytes ....
        let fileSizeStr = ByteCountFormatter.string(fromByteCount: folderSize, countStyle: ByteCountFormatter.CountStyle.file)
        return fileSizeStr

    } catch let error {
        print(error.localizedDescription)
        return nil
    }
}

2。文件大小 -

func sizeOfFile(_ filePath: String) -> String? {
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
        let folderSize = fileAttributes[FileAttributeKey.size] as? Int64 ?? 0
        let fileSizeStr = ByteCountFormatter.string(fromByteCount: folderSize, countStyle: ByteCountFormatter.CountStyle.file)
        return fileSizeStr
    } catch {
        print(error)
    }
    return nil
}

【讨论】:

    【解决方案4】:

    在 iOS 5 中,-filesAttributesAtPath: 方法已被弃用。这是使用新方法发布的第一个代码的版本:

    - (unsigned long long int)folderSize:(NSString *)folderPath {
        NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
        NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
        NSString *fileName;
        unsigned long long int fileSize = 0;
    
        while (fileName = [filesEnumerator nextObject]) {
            NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:fileName] error:nil];
            fileSize += [fileDictionary fileSize];
        }
    
        return fileSize;
    }
    

    【讨论】:

    • 当然也可以使用快速枚举:for(NSString *fileName in filesArray) { }
    【解决方案5】:

    以下内容应该可以帮助您入门。不过,您需要将 _documentsDirectory 修改为您的特定文件夹:

    - (unsigned long long int) documentsFolderSize {
        NSFileManager *_manager = [NSFileManager defaultManager];
        NSArray *_documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *_documentsDirectory = [_documentPaths objectAtIndex:0];   
        NSArray *_documentsFileList;
        NSEnumerator *_documentsEnumerator;
        NSString *_documentFilePath;
        unsigned long long int _documentsFolderSize = 0;
    
        _documentsFileList = [_manager subpathsAtPath:_documentsDirectory];
        _documentsEnumerator = [_documentsFileList objectEnumerator];
        while (_documentFilePath = [_documentsEnumerator nextObject]) {
            NSDictionary *_documentFileAttributes = [_manager fileAttributesAtPath:[_documentsDirectory stringByAppendingPathComponent:_documentFilePath] traverseLink:YES];
            _documentsFolderSize += [_documentFileAttributes fileSize];
        }
    
        return _documentsFolderSize;
    }
    

    【讨论】:

    • fileAttributesAtPath 已弃用
    【解决方案6】:

    我使用此代码获取 2 个目录的目录大小,如果一个目录不存在,它将显示 0 KB。否则,代码的后半部分将分别显示文件夹大小以及 KB、MB、GB,并且还会以干净的格式显示:10.02 MB

    试试这个:

    - (unsigned long long int)folderSize:(NSString *)folderPath {
        NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
        NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
        NSString *fileName;
        unsigned long long int fileSize = 0;
    
        while (fileName = [filesEnumerator nextObject]) {
            NSDictionary *fileDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
            fileSize += [fileDictionary fileSize];
        } 
    
        return fileSize;
    }
    
    -(NSString *)getMPSize
    {
        NSString*sizeTypeW = @"bytes";
        int app = [self folderSize:@"/PathToTheFolderYouWantTheSizeOf/"];
        NSFileManager *manager = [NSFileManager defaultManager];
        if([manager fileExistsAtPath:@"/AnotherFolder/"] == YES){
    
            int working = [self folderSize:@"/AnotherFolder/"];
            if(working<1){
                return @"Size: Zero KB";
            }else{
                if (working > 1024)
                {
                    //Kilobytes
                    working = working / 1024;
    
                    sizeTypeW = @" KB";
                }
    
                if (working > 1024)
                {
                    //Megabytes
                    working = working / 1024;
    
                    sizeTypeW = @" MB";
                }
    
                if (working > 1024)
                {
                    //Gigabytes
                    working = working / 1024;
    
                    sizeTypeW = @" GB";
                }
    
                return [NSString stringWithFormat:@"App: %i MB, Working: %i %@ ",app/1024/1024, working,sizeTypeW];
            }
    
        }else{
            return [NSString stringWithFormat:@"App: %i MB, Working: Zero KB",app/1024/1024];
        }
        [manager release];
    }
    

    【讨论】:

      【解决方案7】:

      这是一个快速的 2.1/2.2 答案,使用扩展并构建了 Rok 的答案:

      extension NSFileManager {
          func fileSizeAtPath(path: String) -> Int64 {
              do {
                  let fileAttributes = try attributesOfItemAtPath(path)
                  let fileSizeNumber = fileAttributes[NSFileSize]
                  let fileSize = fileSizeNumber?.longLongValue
                  return fileSize!
              } catch {
                  print("error reading filesize, NSFileManager extension fileSizeAtPath")
                  return 0
              }
          }
      
          func folderSizeAtPath(path: String) -> Int64 {
              var size : Int64 = 0
              do {
                  let files = try subpathsOfDirectoryAtPath(path)
                  for i in 0 ..< files.count {
                      size += fileSizeAtPath((path as NSString).stringByAppendingPathComponent(files[i]) as String)
                  }
              } catch {
                  print("error reading directory, NSFileManager extension folderSizeAtPath")
              }
              return size
          }
      
          func format(size: Int64) -> String {
             let folderSizeStr = NSByteCountFormatter.stringFromByteCount(size, countStyle: NSByteCountFormatterCountStyle.File)
             return folderSizeStr
          }
      
      }
      

      使用示例:

      let fileManager = NSFileManager.defaultManager()
      let documentsDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
      let dirSize: String = fileManager.format(fileManager.folderSizeAtPath(documentsDirPath))
      

      【讨论】:

        【解决方案8】:

        使用枚举块更新方法

        仅使用文件计算文件夹大小

        - (NSString *)sizeOfFolder:(NSString *)folderPath {
            NSArray *folderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:nil];
            __block unsigned long long int folderSize = 0;
        
            [folderContents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:obj] error:nil];
                folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
            }];
            NSString *folderSizeStr = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleFile];
            return folderSizeStr;
        }
        

        用文件夹中的其他子目录计算文件夹大小

         NSArray *folderContents = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
        

        获取文件大小

        - (NSString *)sizeOfFile:(NSString *)filePath {
            NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
            NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] integerValue];
            NSString *fileSizeString = [NSByteCountFormatter stringFromByteCount:fileSize countStyle:NSByteCountFormatterCountStyleFile];
            return fileSizeString;
        }
        

        【讨论】:

          【解决方案9】:

          这是基于 @vitalii 扩展的 FileManager 扩展的 Swift 3 等价物:

          extension FileManager {
          
          func fileSizeAtPath(path: String) -> Int64 {
              do {
                  let fileAttributes = try attributesOfItem(atPath: path)
                  let fileSizeNumber = fileAttributes[FileAttributeKey.size] as? NSNumber
                  let fileSize = fileSizeNumber?.int64Value
                  return fileSize!
              } catch {
                  print("error reading filesize, NSFileManager extension fileSizeAtPath")
                  return 0
              }
          }
          
          func folderSizeAtPath(path: String) -> Int64 {
              var size : Int64 = 0
              do {
                  let files = try subpathsOfDirectory(atPath: path)
                  for i in 0 ..< files.count {
                      size += fileSizeAtPath(path:path.appending("/"+files[i]))
                  }
              } catch {
                  print("error reading directory, NSFileManager extension folderSizeAtPath")
              }
              return size
          }
          
          func format(size: Int64) -> String {
              let folderSizeStr = ByteCountFormatter.string(fromByteCount: size, countStyle: ByteCountFormatter.CountStyle.file)
              return folderSizeStr
          }}
          

          【讨论】:

            【解决方案10】:

            我认为使用 Unix C 方法性能更好。

            + (long long) folderSizeAtPath: (const char*)folderPath {
              long long folderSize = 0;
              DIR* dir = opendir(folderPath);
              if (dir == NULL) return 0;
              struct dirent* child;
              while ((child = readdir(dir))!=NULL) {
                if (child->d_type == DT_DIR
                    && child->d_name[0] == '.'
                    && (child->d_name[1] == 0 // ignore .
                        ||
                        (child->d_name[1] == '.' && child->d_name[2] == 0) // ignore dir ..
                       ))
                  continue;
            
                int folderPathLength = strlen(folderPath);
                char childPath[1024]; // child 
                stpcpy(childPath, folderPath);
                if (folderPath[folderPathLength-1] != '/'){
                  childPath[folderPathLength] = '/';
                  folderPathLength++;
                }
                stpcpy(childPath+folderPathLength, child->d_name);
                childPath[folderPathLength + child->d_namlen] = 0;
                if (child->d_type == DT_DIR){ // directory
                  folderSize += [self _folderSizeAtPath:childPath]; // 
                  // add folder size
                  struct stat st;
                  if (lstat(childPath, &st) == 0)
                    folderSize += st.st_size;
                } else if (child->d_type == DT_REG || child->d_type == DT_LNK){ // file or link
                  struct stat st;
                  if (lstat(childPath, &st) == 0)
                    folderSize += st.st_size;
                }
              }
              return folderSize;
            }
            

            【讨论】:

              【解决方案11】:

              如果我们想获取任何文件的大小,那么这里有一个方法,我们只需要传递该文件的路径。

              - (unsigned long long int) fileSizeAt:(NSString *)path {
                  NSFileManager *_manager = [NSFileManager defaultManager];
                  return [[_manager fileAttributesAtPath:path traverseLink:YES] fileSize];
              }
              

              【讨论】:

              • 根据您的建议,您将只处理目录占位符大小。如果您想计算所有内容的目录大小,则必须通过一些循环操作获取目录内的每个文件大小并一一相加。像上面的例子。而且,fileAttributesAtPath 方法很久以前就被弃用了。
              • fileAttributesAtPath 已弃用
              【解决方案12】:

              我在使用前清理了第一个答案的实现,所以它不再抛出不推荐使用的警告 + 使用快速枚举。

              /**
               *  Calculates the size of a folder.
               *
               *  @param  folderPath  The path of the folder
               *
               *  @return folder size in bytes
               */
              - (unsigned long long int)folderSize:(NSString *)folderPath {
                  NSFileManager *fm = [NSFileManager defaultManager];
                  NSArray *filesArray = [fm subpathsOfDirectoryAtPath:folderPath error:nil];
                  unsigned long long int fileSize = 0;
              
                  NSError *error;
                  for(NSString *fileName in filesArray) {
                      error = nil;
                      NSDictionary *fileDictionary = [fm attributesOfItemAtPath:[folderPath     stringByAppendingPathComponent:fileName] error:&error];
                      if (!error) {
                          fileSize += [fileDictionary fileSize];
                      }else{
                          NSLog(@"ERROR: %@", error);
                      }
                  }
              
                  return fileSize;
              }
              

              【讨论】:

                【解决方案13】:

                快速实现

                class func folderSize(folderPath:String) -> UInt{
                
                    // @see http://stackoverflow.com/questions/2188469/calculate-the-size-of-a-folder
                
                    let filesArray:[String] = NSFileManager.defaultManager().subpathsOfDirectoryAtPath(folderPath, error: nil)! as [String]
                    var fileSize:UInt = 0
                
                    for fileName in filesArray{
                        let filePath = folderPath.stringByAppendingPathComponent(fileName)
                        let fileDictionary:NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil)!
                        fileSize += UInt(fileDictionary.fileSize())
                
                    }
                
                    return fileSize
                }
                

                【讨论】:

                  【解决方案14】:

                  不确定这是否对任何人有帮助,但我想把我的一些发现联系起来(一些受@zneak 上面评论的启发)。

                  1. 我找不到任何使用 NSDirectoryEnumerator 的快捷方式来避免枚举文件以获得目录的总包含大小。

                  2. 对于我的测试,使用-[NSFileManager subpathsOfDirectoryAtPath:path error:nil] 比使用-[NSFileManager enumeratorAtPath:path] 更快。在我看来,这可能是一个经典的时间/空间权衡,因为subPaths... 创建了一个 NSArray,然后在其上进行迭代,enumerator... 可能不会。

                  #1 的一些背景知识。假设:

                  NSFileManager *fileMan = [NSFileManager defaultManager];
                  NSString *dirPath = @"/"; // references some directory
                  

                  然后

                  [fileMan enumeratorAtPath:dirPath] fileAttributes]
                  

                  返回nil。正确的属性访问器是directoryAttributes,但是

                  [fileMan enumeratorAtPath:dirPath] directoryAttributes] fileSize]
                  

                  返回目录信息的大小,而不是所有包含文件大小的递归总和(Finder 中的 lá ⌘-I)。

                  【讨论】:

                    【解决方案15】:

                    我创建了一个简单的 NSFileManager 扩展:

                    extension NSFileManager {
                      func fileSizeAtPath(path: String) -> Int {
                        return attributesOfItemAtPath(path, error: nil)?[NSFileSize] as? Int ?? 0
                      }
                    
                      func folderSizeAtPath(path: String) -> Int {
                        var size = 0
                        for file in subpathsOfDirectoryAtPath(path, error: nil) as? [String] ?? [] {
                          size += fileSizeAtPath(path.stringByAppendingPathComponent(file))
                        }
                        return size
                      }
                    }
                    

                    可以获取文件大小:

                    NSFileManager.defaultManager().fileSizeAtPath("file path")
                    

                    和文件夹大小:

                    NSFileManager.defaultManager().folderSizeAtPath("folder path")
                    

                    【讨论】:

                      猜你喜欢
                      • 2011-08-17
                      • 2019-01-06
                      • 1970-01-01
                      • 2018-10-10
                      • 2022-01-07
                      • 1970-01-01
                      • 2018-10-10
                      相关资源
                      最近更新 更多