10FileManager_SelectMutableLine_ObjectSerialization_FullyCopy

大纲

一、文件管理器
项目:FileManager0412
NSFileManager:文件管理器(单例类)
作用:管理文件/文件夹
(一)获取路径
1.获取home文件夹
2.获取Documents文件夹(拼接字符串)
3.获取指定文件路径(拼接字符串)
(二)文件文件夹的 创建/拷贝/移动/删除/属性
1.获取文件管理器
2.处理路径
3.管理器调用方法(创建/拷贝/移动/删除/属性)
二、多行选择
项目:SelectMutableLine0412
程序再次运行时读取数据:
1.创建基本表
2.处理单元格的 选中/取消选中
2.1 判断点击的Cell索引是否在_selectedRowArr中:
①在,取消选中
换图片 取消选中
移除 索引
②不在,选中
换图片 选中
添加 索引
3.数据存储(通知)
程序将要终止运行时,发出通知,存储数据
4.数据读取
程序再次运行时,从沙盒中取出数据
三、对象序列化
项目:ObjectSerialization0412
NSUserDefaults/writeToFile不能直接存储自定义类
结论:
数组/字典/字符串/NSData可以直接使用NSUserDefaults/writeToFile的方式将数据写入沙盒,因为这些类都实现了NSCoding协议
将自定义类对象写入沙盒的条件:
1.实现NSCoding协议
2.对象序列化
(一)序列化 方法1
序列化:
NSKeyedArchiver:编码器
作用:将一个实现NSCoding协议的对象转换为二进制数据(NSData)
1.编码
2.写入沙盒
反序列化:
NSKeyedUnarchiver:解码器
1.读取数据
2.解码
(二)方法2
序列化:
1.创建容器NSMutableData,保存要编码的对象
2.创建序列化器,指定要编码的对象容器
3.编码
4.结束编码
5.写入文件
反序列化:
1.读取数据
2.创建编码器
3.解码
4.结束解码
四、对容器类的拷贝
项目:FullyCopy0412
完全拷贝
方法1:
initWithArray:copyItems:对数组中的每一个元素调用 copy方法
条件:
1.元素实现 NSCoping 协议
2.元素是可变对象
方法2:序列化
条件:数组/元素 必须实现 NSCoding 协议

正文

一、文件管理器
项目:FileManager0412
NSFileManager:文件管理器(单例类)
作用:管理文件/文件夹
(一)获取路径
1.获取home文件夹

     NSString *homeDirectoryPath = NSHomeDirectory();

2.获取Documents文件夹(拼接字符串)

     NSString *docPath = [homeDirectoryPath stringByAppendingPathComponent:@"Documents"];

3.获取指定文件路径(拼接字符串)

     NSString *filePath = [docPath stringByAppendingPathComponent:fileName];

(二)文件文件夹的 创建/拷贝/移动/删除/属性
1.获取文件管理器
2.处理路径
3.管理器调用方法(创建/拷贝/移动/删除/属性)
创建

[fileManager createFileAtPath:path contents:[@"123" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];

拷贝/移动

[fileManager copyItemAtPath:path1 toPath:path2 error:&error];
[fileManager moveItemAtPath:path1 toPath:path2 error:&error];

删除

[fileManager removeItemAtPath:path error:&error];

属性

NSDictionary *dic = [fileManager attributesOfItemAtPath:path error:&error];

源码:

@implementation ViewController
#pragma mark - **************** 获取文件路径
- (NSString *)getFilePath:(NSString *)fileName
{
    NSString *homeDirectoryPath = NSHomeDirectory();
    NSLog(@"%@",homeDirectoryPath);
    NSString *docPath = [homeDirectoryPath stringByAppendingPathComponent:@"Documents"];
    NSString *filePath = [docPath stringByAppendingPathComponent:fileName];
    return filePath;
}
#pragma mark - **************** 创建文件
- (IBAction)createFile:(UIButton *)sender
{
    //NSFileManager:文件管理器(单例类)
    //用于管理文件/文件夹
    //1.获取文件管理器
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //2.获取路径
    NSString *filePath = [self getFilePath:@"a.plist"];
    BOOL isExists = [fileManager fileExistsAtPath:filePath];
    if (isExists)
    {
        NSLog(@"该路径下存在该文件。");
    }
    else
    {
        NSLog(@"不存在,创建");
        //3.创建文件
        //AtPath:在哪个路径下创建
        //contents:添加文件内容
        //attributes:文件属性,nil表示默认属性
        [fileManager createFileAtPath:filePath contents:[@"123" dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];
    }
}
#pragma mark - **************** 创建文件夹
- (IBAction)createDirectory:(UIButton *)sender
{
    //1.获取文件管理器
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //2.获取路径
    NSString *directoryPath = [self getFilePath:@"class/student"];
    BOOL isExists = [fileManager fileExistsAtPath:directoryPath];
    if (isExists)
    {
        NSLog(@"该路径下存在该文件。");
    }
    else
    {
        NSLog(@"不存在,创建");
        //1.AtPath:在哪个路径下创建文件夹
        //2.withIntermediateDirectories:是否创建中间级文件夹
        //3.attributes:文件夹属性
        //4.error:若创建失败,返回错误原因
        NSError *error = nil;
        BOOL isSuccess = [fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
        //判断文件夹是否创建成功
        if (isSuccess == NO)
        {
            NSLog(@"创建失败,原因:%@",error);
        }
    }
}
#pragma mark - **************** 拷贝
- (IBAction)copyClick:(UIButton *)sender
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    //1.源路径
    NSString *filePath = [self getFilePath:@"a.plist"];
    //2.目标路径
    NSString *tmpPath = NSTemporaryDirectory();
    NSString *filePath2 = [tmpPath stringByAppendingPathComponent:@"b.plist"];
    //3.拷贝
    NSError *error = nil;
    [fileManager copyItemAtPath:filePath toPath:filePath2 error:&error];
}
#pragma mark - **************** 移动
- (IBAction)moveClick:(UIButton *)sender
{
    NSFileManager *manager = [NSFileManager defaultManager];
    //1.源路径
    NSString *path1 = [self getFilePath:@"class"];
    //2.目标路径
    NSString *path2 = [NSTemporaryDirectory() stringByAppendingPathComponent:@"class2"];
    //3.移动
    NSError *error = nil;
    [manager moveItemAtPath:path1 toPath:path2 error:&error];
}
#pragma mark - **************** 删除
- (IBAction)deleteClick:(UIButton *)sender
{
    NSFileManager *manager = [NSFileManager defaultManager];
    //1.路径
    NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"class2/student"];
    //2.删除
    NSError *error = nil;
    [manager removeItemAtPath:path error:&error];
}
#pragma mark - **************** 获取文件属性
- (IBAction)attributeClick:(UIButton *)sender
{
    NSFileManager *manager = [NSFileManager defaultManager];
    //1.路径
    NSString *path = [self getFilePath:@"a.plist"];
    NSError *error = nil;
    NSDictionary *dic = [manager attributesOfItemAtPath:path error:&error];
    NSDate *date = [dic fileCreationDate];
    NSLog(@"date = %@",date);
}
@end

二、多行选择
项目:SelectMutableLine0412
程序再次运行时读取数据:
1.创建基本表
2.处理单元格的 选中/取消选中
2.1 判断点击的Cell索引是否在_selectedRowArr中:
①在,取消选中
换图片 取消选中
移除 索引
②不在,选中
换图片 选中
添加 索引
3.数据存储(通知)
程序将要终止运行时,发出通知,存储数据
①获取filePath②writeToFile。
4.数据读取
程序再次运行时,从沙盒中取出数据
①获取fileManager②获取filePath③读取

源码:

static NSString *cellId = @"cell";
@implementation ViewController
/** 
 1.创建基本表
 2.处理单元格的选中
 3.处理取消单元格选中
 4.数据存储(通知)
 5.数据读取
 */
- (void)viewDidLoad
{
    [super viewDidLoad];
    //当程序退出时,系统会发出通知
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(saveData) name:UIApplicationWillTerminateNotification object:nil];
    
    //1.数据源
    _movieArr = [[NSMutableArray alloc]initWithObjects:@"火锅英雄",@"奇幻森林",@"X特遣队",@"寻龙诀",@"疯狂动物城",@"伦敦陷落",@"蜘蛛侠",@"1",@"落",@"侠", nil];
    //每次启动程序,先从沙盒中读取数据_selectedRowArr
    //判断沙盒某路径下是否存在数据文件
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *filePath = [self getFilePath:@"movie.plist"];
    BOOL isExists = [fileManager fileExistsAtPath:filePath];
    
    if (isExists)
    {
        //文件存在,读取
        _selectedRowArr = [[NSMutableArray alloc]initWithContentsOfFile:filePath];
    }
    else
    {
        //文件不存在,初始化
        _selectedRowArr = [[NSMutableArray alloc]init];
    }
    //2.创建表
    UITableView *tableView = [[UITableView alloc]initWithFrame:self.view.frame style:UITableViewStylePlain];
    tableView.delegate = self;
    tableView.dataSource = self;
    tableView.rowHeight = 80;
    [self.view addSubview:tableView];
    
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellId];
    [tableView release];
}
#pragma mark - **************** 获取路径
- (NSString *)getFilePath:(NSString *)name
{
    NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSLog(@"%@",doc);
    return [doc stringByAppendingString:name];
}

#pragma mark - **************** 收到通知,保存数据
- (void)saveData
{
    NSString *filePath = [self getFilePath:@"movie.plist"];
    [_selectedRowArr writeToFile:filePath atomically:YES];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath];
    cell.imageView.image = [UIImage imageNamed:@"star_half"];
    
    for (NSNumber *number in _selectedRowArr)
    {
        if (indexPath.row == [number integerValue])
        {
            cell.imageView.image = [UIImage imageNamed:@"star_full"];
        }
    }
    cell.textLabel.text = [_movieArr objectAtIndex:indexPath.row];
    return cell;
}
#pragma mark - **************** 点击单元格
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //4.判断当前点击的Cell索引是否在_selectedRowArr中
    //两种情况:
    //1.在
    //2.不在
    BOOL isSelect = NO;
    for (NSNumber *number in _selectedRowArr)
    {
        NSInteger selectedRow = [number integerValue];
        if (selectedRow == indexPath.row)
        {
            //已经被选中
            isSelect = YES;
        }
    }
    //1.找到当前点击的单元格
    UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
    NSNumber *number = [NSNumber numberWithInteger:indexPath.row];
    //被选中,取消选中
    if (isSelect)
    {
        //2.改变单元格上的图片
        selectedCell.imageView.image = [UIImage imageNamed:@"star_half"];
        //3.索引从数组中移除
        [_selectedRowArr removeObject:number];
    }
    //未被选中
    else
    {
        //2.改变单元格上的图片
        selectedCell.imageView.image = [UIImage imageNamed:@"star_full"];
        //3.将选中的单元格索引存进数组中
        [_selectedRowArr addObject:number];
    }
}
@end

三、对象序列化
项目:ObjectSerialization0412
NSUserDefaults/writeToFile不能直接存储自定义类
结论:
数组/字典/字符串/NSData可以直接使用NSUserDefaults/writeToFile的方式将数据写入沙盒,因为这些类都实现了NSCoding协议
将自定义类对象写入沙盒的条件:
1.实现NSCoding协议
2.对象序列化

(一)序列化 方法1
序列化:
NSKeyedArchiver:编码器
作用:将一个实现NSCoding协议的对象转换为二进制数据(NSData)
1.编码

 NSData *data = [NSKeyedArchiver archivedDataWithRootObject:people];

2.写入沙盒

 [data writeToFile:[self getFilePath] atomically:YES];

反序列化:
NSKeyedUnarchiver:解码器
1.读取数据

 NSData *data = [NSData dataWithContentsOfFile:[self getFilePath]];

2.解码

 People *people = [NSKeyedUnarchiver unarchiveObjectWithData:data];

(二)方法2
序列化:
1.创建容器NSMutableData,保存要编码的对象

 NSMutableData *mData = [[NSMutableData alloc]init];

2.创建序列化器,指定要编码的对象容器

 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:mData];

3.编码

 [archiver encodeObject:people forKey:@"p"];

4.结束编码

 [archiver finishEncoding];

5.写入文件

 [mData writeToFile:[self getFilePath] atomically:YES];

反序列化:
1.读取数据

 NSMutableData *mData = [[NSMutableData alloc]initWithContentsOfFile:[self getFilePath]];

2.创建编码器

 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:mData];

3.解码

 People *people = [unarchiver decodeObjectForKey:@"p"];

4.结束解码

 [unarchiver finishDecoding];

源码:

@implementation People
#pragma mark - **************** 编码(对People类对象内的每一个属性进行编码)
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeInteger:_age forKey:@"age"];
}
#pragma mark - **************** 解码
- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self)
    {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}
#pragma mark - **************** 重写description方法,用于自定义对象的输入内容(NSLog输出的内容)
- (NSString *)description
{
    return [NSString stringWithFormat:@"%@--%d",self.name,self.age];
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"%@",NSHomeDirectory());
    
    People *people = [People new];
    people.name = @"张三";
    people.age = 30;
    NSArray *array = @[people];
    //不能直接存储自定义类
    //1.NSUserDefaults不行
//    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    //①
//    [defaults setObject:people forKey:@"p"];
    //②
//    [defaults setObject:array forKey:@"p"];
    //2.writeToFile也不可以
//    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/array.plist"];
//    [array writeToFile:path atomically:YES];
    
    //结论:
    //数组/字典/字符串/NSData可以直接使用NSUserDefaults/writeToFile的方式将数据写入沙盒,因为这些类都实现了NSCoding协议
    //将自定义类对象写入沙盒的条件:
    //1.实现NSCoding协议
    //2.对象序列化:
}
//对象序列化
- (IBAction)archiverClick:(UIButton *)sender
{
    People *people = [People new];
    people.name = @"张三";
    people.age = 30;
    //对象序列化:
    //NSKeyedArchiver:编码器
    //作用:将一个实现NSCoding协议的对象转换为二进制数据(NSData)
    //1.编码
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:people];
    //2.写入沙盒
    [data writeToFile:[self getFilePath] atomically:YES];
}
//对象反序列化
- (IBAction)unarchiverClick:(UIButton *)sender
{
    //反序列化
    //NSKeyedUnarchiver
    //1.读取
    NSData *data = [NSData dataWithContentsOfFile:[self getFilePath]];
    //2.对数据进行解码
    People *people = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"%@",people);
}
@end

项目:ObjectSerialization_Tow0412

#pragma mark - **************** 序列化
- (IBAction)archiverClick:(UIButton *)sender
{
    People *people = [People new];
    people.name = @"李四";
    people.phoneNum = @"1234325423";
    //1.创建一个NSMutableData,作为一个容器,保存要编码的对象
    NSMutableData *mData = [[NSMutableData alloc]init];
    //2.创建序列化器,并且指定要编码的对象保存的位置
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:mData];
    //3.编码
    [archiver encodeObject:people forKey:@"p"];
    //4.结束编码
    [archiver finishEncoding];
    //5.写入文件
    BOOL is = [mData writeToFile:[self getFilePath] atomically:YES];
    if (is)
    {
        NSLog(@"成功");
    }
}
#pragma mark - **************** 反编码
- (IBAction)unarchiverClick:(UIButton *)sender
{
    //1.从沙盒中读取数据
    NSMutableData *mData = [[NSMutableData alloc]initWithContentsOfFile:[self getFilePath]];
    //2.创建编码器
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:mData];
    //3.解码
    People *people = [unarchiver decodeObjectForKey:@"p"];
    //4.结束解码
    [unarchiver finishDecoding];
    NSLog(@"%@",people);
}

四、对容器类的拷贝
项目:FullyCopy0412
完全拷贝
方法1:

initWithArray:copyItems:对数组中的每一个元素调用 copy方法

条件:
1.元素实现 NSCoping 协议
2.元素是可变对象
方法2:序列化
条件:数组/元素 必须实现 NSCoding 协议

 NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];

反序列化

 NSArray *array4 = [NSKeyedUnarchiver unarchiveObjectWithData:data];

源码:

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    //可变
    NSString *text = @"12345";
//    //不可变
//    NSMutableString *text = [NSMutableString stringWithFormat:@"12345"];
    NSArray *array = @[text];
//    NSArray *array = @[mText];
    NSArray *array1 = [array copy];//浅拷贝,拷贝指针
    NSArray *array2 = [array mutableCopy];//深拷贝,拷贝对象
    
    //完全拷贝:
    //方法1:
    //initWithArray: copyItems:对数组中的每一个元素调用 copy方法
    //条件:
    //1.元素实现 NSCoping 协议
    //2.元素是可变对象
    NSArray *array3 = [[NSArray alloc]initWithArray:array copyItems:YES];
    //方法2:序列化
    //条件:数组/元素 必须实现 NSCoding 协议
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
    //反序列化
    NSArray *array4 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    
    //输出
    NSLog(@"---%p---%p---%p---%p---%p",array,array1,array2,array3,array4);
    //对于系统容器类来说,copy/mutableCopy,容器内部的元素都是浅拷贝,
    NSLog(@"===%p===%p===%p===%p===%p",array[0],array1[0],array2[0],array3[0],array4[0]);
}
@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • 27、ViewController的didReceiveMemoryWarning是在什么时候调用的?默认的操作是...
    烟雨平生花飞舞阅读 552评论 0 1
  • iOS开发系列--网络开发 概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博、微信等,这些应用本身可...
    lichengjin阅读 3,629评论 2 7
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666阅读 1,357评论 0 6
  • 一、iOS中的沙盒机制 iOS应用程序只能对自己创建的文件系统读取文件,这个独立、封闭、安全的空间,叫做沙盒。它一...
    1d5cb7cff98d阅读 1,760评论 0 0
  • iOS开发-文件管理(一) 一、iOS中的沙盒机制 iOS应用程序只能对自己创建的文件系统读取文件,这个独立、封闭...
    MacShare阅读 1,784评论 0 6