NSFile​Manager

本文介绍了 NSFileManager 的基本用法,包括文件和目录的基本操作、文件属性的获取与设置、使用 NSFileManagerDelegate 进行业务逻辑控制及 iCloud 文件管理。

NSFileManager 是处理文件系统的 Foundation 框架的高级API。它抽象了 Unix 和 Finder 的内部构成,和 iCloud ubiquitous containers 一样, 提供了创建,读取,移动,拷贝以及删除本地或者网络驱动器上的文件或者目录的方法。

文件系统是一个复杂的主题,它有数十年的历史,一些遗留下的复杂性和一些特别的地方,已经不是一篇文章就可以描述的了。现在大多数的应用除了简单的文件操作之外不会经常与文件系统交互,所以有时候简单了解它的基础就行了。

你可以复制粘贴下面的代码试试看,用他们作为你的代码基础,修改这些参数来达到你期望的效果。

常用操作

纵观苹果提供的样例代码,尽是这样的黑魔法:NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) , 它或许绑定了KVO,也是Cocoa最糟糕的API之一。你只需要知道它返回了一个包含用户文档目录作为第一个元素的数组就行了。真要感谢 NSArray -firstObject

确定文件是否存在

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"file.txt"];
BOOL fileExists = [fileManager fileExistsAtPath:filePath];

列出文件里面的所有目录

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
NSArray *contents = [fileManager contentsOfDirectoryAtURL:bundleURL
                               includingPropertiesForKeys:@[]
                                                  options:NSDirectoryEnumerationSkipsHiddenFiles
                                                    error:nil];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"pathExtension == 'png'"];
for (NSURL *fileURL in [contents filteredArrayUsingPredicate:predicate]) {
    // 在目录中枚举 .png 文件
}

在目录中递归地遍历文件

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtURL:bundleURL
                                      includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey]
                                                         options:NSDirectoryEnumerationSkipsHiddenFiles
                                                    errorHandler:^BOOL(NSURL *url, NSError *error)
{
    if (error) {
        NSLog(@"[Error] %@ (%@)", error, url);
        return NO;
    }

    return YES;
}];

NSMutableArray *mutableFileURLs = [NSMutableArray array];
for (NSURL *fileURL in enumerator) {
    NSString *filename;
    [fileURL getResourceValue:&filename forKey:NSURLNameKey error:nil];

    NSNumber *isDirectory;
    [fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil];

    // Skip directories with '_' prefix, for example
    if ([filename hasPrefix:@"_"] && [isDirectory boolValue]) {
        [enumerator skipDescendants];
        continue;
    }

    if (![isDirectory boolValue]) {
        [mutableFileURLs addObject:fileURL];
    }
}

创建一个目录

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *imagesPath = [documentsPath stringByAppendingPathComponent:@"images"];
if (![fileManager fileExistsAtPath:imagesPath]) {
    [fileManager createDirectoryAtPath:imagesPath withIntermediateDirectories:NO attributes:nil error:nil];
}

删除一个目录

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"image.png"];
NSError *error = nil;

if (![fileManager removeItemAtPath:filePath error:&error]) {
    NSLog(@"[Error] %@ (%@)", error, filePath);
}

删除文件的创建日期

Objective-C
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *filePath = [documentsPath stringByAppendingPathComponent:@"Document.pages"];

NSDate *creationDate = nil;
if ([fileManager fileExistsAtPath:filePath]) {
    NSDictionary *attributes = [fileManager attributesOfItemAtPath:filePath error:nil];
    creationDate = attributes[NSFileCreationDate];
}

通过NSFileManager的 -attributesOfItemAtPath:error: 和其它方法可以访问很多文件的属性

文件属性的键
  • NSFileAppendOnly: 文件是否只读
  • NSFileBusy: 文件是否繁忙
  • NSFileCreationDate: 文件创建日期
  • NSFileOwnerAccountName: 文件所有者的名字
  • NSFileGroupOwnerAccountName: 文件所有组的名字
  • NSFileDeviceIdentifier: 文件所在驱动器的标示符
  • NSFileExtensionHidden: 文件后缀是否隐藏
  • NSFileGroupOwnerAccountID: 文件所有组的group ID
  • NSFileHFSCreatorCode: 文件的HFS创建者的代码
  • NSFileHFSTypeCode: 文件的HFS类型代码
  • NSFileImmutable: 文件是否可以改变
  • NSFileModificationDate: 文件修改日期
  • NSFileOwnerAccountID: 文件所有者的ID
  • NSFilePosixPermissions: 文件的Posix权限
  • NSFileReferenceCount: 文件的链接数量
  • NSFileSize: 文件的字节
  • NSFileSystemFileNumber: 文件在文件系统的文件数量
  • NSFileType: 文件类型
  • NSDirectoryEnumerationSkipsSubdirectoryDescendants: 浅层的枚举,不会枚举子目录
  • NSDirectoryEnumerationSkipsPackageDescendants: 不会扫描pakages的内容
  • NSDirectoryEnumerationSkipsHiddenFile: 不会扫描隐藏文件

NSFileManagerDelegate

NSFileManager 可以设置一个 <NSFileManagerDelegate> protocol 来确认是否要进行特定的文件操作。它允许进行一些业务逻辑,比如保护一些文件删除,在 Controller 中删除一些元素

NSFileManagerDelegate里面有四个方法,每个按照path变化

  • -fileManager:shouldMoveItemAtURL:toURL:
  • -fileManager:shouldCopyItemAtURL:toURL:
  • -fileManager:shouldRemoveItemAtURL:
  • -fileManager:shouldLinkItemAtURL:toURL:

如果你想用 alloc init 初始化你自己的 NSFileManager 来取代shared实例,那就要用它了,就像文档说的

如果你使用一个delegate 来接受移动,拷贝,涉案出,以及链接的操作,你需要创建一个独一无二的实例,将delegate绑定到你的实例中,用这个fielmanager开始你的操作

Objective-C
NSFileManager *fileManager = [[NSFileManager alloc] init];
fileManager.delegate = delegate;

NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
NSArray *contents = [fileManager contentsOfDirectoryAtURL:bundleURL
                               includingPropertiesForKeys:@[]
                                                  options:NSDirectoryEnumerationSkipsHiddenFiles
                                                    error:nil];

for (NSString *filePath in contents) {
    [fileManager removeItemAtPath:filePath error:nil];
}
CustomFileManagerDelegate.m
Objective-C
#pragma mark - NSFileManagerDelegate

- (BOOL)fileManager:(NSFileManager *)fileManager
shouldRemoveItemAtURL:(NSURL *)URL
{
    return ![[[URL lastPathComponent] pathExtension] isEqualToString:@"pdf"];
}

Ubiquitous Storage

文档也可与放到iCloud里面。如果你猜可以直截了当的进行操作,恭喜你猜对了。

这里有一个其它用到 alloc init 的地方,因为 URLForUbiquityContainerIdentifier: and setUbiquitous:itemAtURL:destinationURL:error: 是代码块调用,所以整个操作需要在后台队列分发

将文件放到iCloud里面

Objective-C
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSURL *fileURL = [NSURL fileURLWithPath:[documentsPath stringByAppendingPathComponent:@"Document.pages"]];

    //这里的 identifier 应该设置为 entitlements 的第一个元素;当你使用这段代码的时候需要把 identifier 设置为你自己的真实 identifier
    NSString *identifier = nil;

    NSURL *ubiquitousContainerURL = [fileManager URLForUbiquityContainerIdentifier:identifier];
    NSURL *ubiquitousFileURL = [ubiquitousContainerURL URLByAppendingPathComponent:@"Document.pages"];

    NSError *error = nil;
    BOOL success = [fileManager setUbiquitous:YES
                                    itemAtURL:fileURL
                               destinationURL:ubiquitousFileURL
                                        error:&error];
    if (!success) {
        NSLog(@"[Error] %@ (%@) (%@)", error, fileURL, ubiquitousFileURL);
    }
});

你可以在苹果的 iCloud File Management 文档里面找到更多信息


关于文件系统需要知道很多东西,但大多数是理论测验层面的。别误会,这些理论测验并没有错!但理论并不能教你代码该怎么写。NSFileManager可以让你不用学习它们大多数的内容就能完成工作。

此时的run_in_exp_310_with_livox.launch <launch> <!-- size of map, change the size inflate x, y, z according to your application --> <arg name="map_size_x" value="40.0"/> <arg name="map_size_y" value="40.0"/> <arg name="map_size_z" value=" 3.0"/> <!-- topic of your odometry such as VIO or LIO --> <arg name="odom_topic" value="/Odometry" /> <!-- <arg name="odom_topic" value="/camera/odom/sample" /> --> <!-- main algorithm params --> <include file="$(find ego_planner)/launch/advanced_param_droneyee.xml"> <arg name="map_size_x_" value="$(arg map_size_x)"/> <arg name="map_size_y_" value="$(arg map_size_y)"/> <arg name="map_size_z_" value="$(arg map_size_z)"/> <arg name="odometry_topic" value="$(arg odom_topic)"/> <!-- camera pose: transform of camera frame in the world frame --> <!-- depth topic: depth image, 640x480 by default --> <!-- don't set cloud_topic if you already set these ones! --> <arg name="camera_pose_topic" value="/pcl_render_node/camera_pose"/> <arg name="depth_topic" value="/camera/depth/image_rect_raw"/> <!-- topic of point cloud measurement, such as from LIDAR --> <!-- don't set camera pose and depth, if you already set this one! --> <!-- <arg name="cloud_topic" value="/livox/lidar"/> --> <arg name="cloud_topic" value="/cloud_registered"/> <!-- intrinsic params of the depth camera --> <arg name="cx" value="321.04638671875"/> <arg name="cy" value="243.44969177246094"/> <arg name="fx" value="387.229248046875"/> <arg name="fy" value="387.229248046875"/> <!-- maximum velocity and acceleration the drone will reach --> <arg name="max_vel" value="0.3" /> <arg name="max_acc" value="0.5" /> <!--always set to 1.5 times grater than sensing horizen--> <arg name="planning_horizon" value="7.5" /> <!-- 1: use 2D Nav Goal to select goal --> <!-- 2: use global waypoints below --> <arg name="flight_type" value="1" /> <!-- global waypoints --> <!-- It generates a piecewise min-snap traj passing all waypoints --> <arg name="point_num" value="5" /> <arg name="point0_x" value="-15.0" /> <arg name="point0_y" value="0.0" /> <arg name="point0_z" value="1.0" /> <arg name="point1_x" value="0.0" /> <arg name="point1_y" value="15.0" /> <arg name="point1_z" value="1.0" /> <arg name="point2_x" value="15.0" /> <arg name="point2_y" value="0.0" /> <arg name="point2_z" value="1.0" /> <arg name="point3_x" value="0.0" /> <arg name="point3_y" value="-15.0" /> <arg name="point3_z" value="1.0" /> <arg name="point4_x" value="-15.0" /> <arg name="point4_y" value="0.0" /> <arg name="point4_z" value="1.0" /> </include> <!-- trajectory server --> <node pkg="ego_planner" name="traj_server" type="traj_server" output="screen"> <remap from="/position_cmd" to="planning/pos_cmd"/> <remap from="/odom_world" to="$(arg odom_topic)"/> <param name="traj_server/time_forward" value="1.0" type="double"/> </node> <node pkg="waypoint_generator" name="waypoint_generator" type="waypoint_generator" output="screen"> <remap from="~odom" to="$(arg odom_topic)"/> <remap from="~goal" to="/move_base_simple/goal"/> <remap from="~traj_start_trigger" to="/traj_start_trigger" /> <param name="waypoint_type" value="manual-lonely-waypoint"/> </node> </launch> AI写代码 launch文件调用的xml文件内容如下 <launch> <arg name="map_size_x_"/> <arg name="map_size_y_"/> <arg name="map_size_z_"/> <arg name="odometry_topic"/> <arg name="camera_pose_topic"/> <arg name="depth_topic"/> <arg name="cloud_topic"/> <arg name="cx"/> <arg name="cy"/> <arg name="fx"/> <arg name="fy"/> <arg name="max_vel"/> <arg name="max_acc"/> <arg name="planning_horizon"/> <arg name="point_num"/> <arg name="point0_x"/> <arg name="point0_y"/> <arg name="point0_z"/> <arg name="point1_x"/> <arg name="point1_y"/> <arg name="point1_z"/> <arg name="point2_x"/> <arg name="point2_y"/> <arg name="point2_z"/> <arg name="point3_x"/> <arg name="point3_y"/> <arg name="point3_z"/> <arg name="point4_x"/> <arg name="point4_y"/> <arg name="point4_z"/> <arg name="flight_type"/> <!-- main node --> <node pkg="ego_planner" name="ego_planner_node" type="ego_planner_node" output="screen"> <remap from="/odom_world" to="$(arg odometry_topic)"/> <remap from="/grid_map/odom" to="$(arg odometry_topic)"/> <remap from="/grid_map/cloud" to="$(arg cloud_topic)"/> <remap from = "/grid_map/pose" to = "$(arg camera_pose_topic)"/> <remap from = "/grid_map/depth" to = "$(arg depth_topic)"/> <!-- planning fsm --> <param name="fsm/flight_type" value="$(arg flight_type)" type="int"/> <param name="fsm/thresh_replan" value="1.5" type="double"/> <param name="fsm/thresh_no_replan" value="2.0" type="double"/> <param name="fsm/planning_horizon" value="$(arg planning_horizon)" type="double"/> <!--always set to 1.5 times grater than sensing horizen--> <param name="fsm/planning_horizen_time" value="3" type="double"/> <param name="fsm/emergency_time_" value="1.0" type="double"/> <param name="fsm/waypoint_num" value="$(arg point_num)" type="int"/> <param name="fsm/waypoint0_x" value="$(arg point0_x)" type="double"/> <param name="fsm/waypoint0_y" value="$(arg point0_y)" type="double"/> <param name="fsm/waypoint0_z" value="$(arg point0_z)" type="double"/> <param name="fsm/waypoint1_x" value="$(arg point1_x)" type="double"/> <param name="fsm/waypoint1_y" value="$(arg point1_y)" type="double"/> <param name="fsm/waypoint1_z" value="$(arg point1_z)" type="double"/> <param name="fsm/waypoint2_x" value="$(arg point2_x)" type="double"/> <param name="fsm/waypoint2_y" value="$(arg point2_y)" type="double"/> <param name="fsm/waypoint2_z" value="$(arg point2_z)" type="double"/> <param name="fsm/waypoint3_x" value="$(arg point3_x)" type="double"/> <param name="fsm/waypoint3_y" value="$(arg point3_y)" type="double"/> <param name="fsm/waypoint3_z" value="$(arg point3_z)" type="double"/> <param name="fsm/waypoint4_x" value="$(arg point4_x)" type="double"/> <param name="fsm/waypoint4_y" value="$(arg point4_y)" type="double"/> <param name="fsm/waypoint4_z" value="$(arg point4_z)" type="double"/> <param name="grid_map/resolution" value="0.1" /> <param name="grid_map/map_size_x" value="$(arg map_size_x_)" /> <param name="grid_map/map_size_y" value="$(arg map_size_y_)" /> <param name="grid_map/map_size_z" value="$(arg map_size_z_)" /> <param name="grid_map/local_update_range_x" value="5.5" /> <param name="grid_map/local_update_range_y" value="5.5" /> <param name="grid_map/local_update_range_z" value="4.5" /> <param name="grid_map/obstacles_inflation" value="0.099" /> <param name="grid_map/local_map_margin" value="30"/> <param name="grid_map/ground_height" value="-0.01"/> <!-- camera parameter --> <param name="grid_map/cx" value="$(arg cx)"/> <param name="grid_map/cy" value="$(arg cy)"/> <param name="grid_map/fx" value="$(arg fx)"/> <param name="grid_map/fy" value="$(arg fy)"/> <!-- depth filter --> <param name="grid_map/use_depth_filter" value="true"/> <param name="grid_map/depth_filter_tolerance" value="0.15"/> <param name="grid_map/depth_filter_maxdist" value="5.0"/> <param name="grid_map/depth_filter_mindist" value="0.2"/> <param name="grid_map/depth_filter_margin" value="1"/> <param name="grid_map/k_depth_scaling_factor" value="1000.0"/> <param name="grid_map/skip_pixel" value="2"/> <!-- local fusion --> <param name="grid_map/p_hit" value="0.65"/> <param name="grid_map/p_miss" value="0.35"/> <param name="grid_map/p_min" value="0.12"/> <param name="grid_map/p_max" value="0.90"/> <param name="grid_map/p_occ" value="0.80"/> <param name="grid_map/min_ray_length" value="0.1"/> <param name="grid_map/max_ray_length" value="4.5"/> <param name="grid_map/virtual_ceil_height" value="2.5"/> <param name="grid_map/visualization_truncate_height" value="2.4"/> <param name="grid_map/show_occ_time" value="false"/> <param name="grid_map/pose_type" value="2"/> <param name="grid_map/frame_id" value="world"/> <!-- planner manager --> <param name="manager/max_vel" value="$(arg max_vel)" type="double"/> <param name="manager/max_acc" value="$(arg max_acc)" type="double"/> <param name="manager/max_jerk" value="4" type="double"/> <param name="manager/control_points_distance" value="0.4" type="double"/> <param name="manager/feasibility_tolerance" value="0.05" type="double"/> <param name="manager/planning_horizon" value="$(arg planning_horizon)" type="double"/> <!-- trajectory optimization --> <param name="optimization/lambda_smooth" value="1.0" type="double"/> <param name="optimization/lambda_collision" value="0.5" type="double"/> <param name="optimization/lambda_feasibility" value="0.1" type="double"/> <param name="optimization/lambda_fitness" value="1.0" type="double"/> <param name="optimization/dist0" value="0.5" type="double"/> <param name="optimization/max_vel" value="$(arg max_vel)" type="double"/> <param name="optimization/max_acc" value="$(arg max_acc)" type="double"/> <param name="bspline/limit_vel" value="$(arg max_vel)" type="double"/> <param name="bspline/limit_acc" value="$(arg max_acc)" type="double"/> <param name="bspline/limit_ratio" value="1.1" type="double"/> </node> </launch> 这是最近修改的两个文件请检查一下
最新发布
08-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值