Objective c NSString唯一的文件路径以避免名称冲突
是否有一种简单的方法来获取给定的文件路径并对其进行修改以避免名称冲突?比如:Objective c NSString唯一的文件路径以避免名称冲突,objective-c,cocoa-touch,nsstring,Objective C,Cocoa Touch,Nsstring,是否有一种简单的方法来获取给定的文件路径并对其进行修改以避免名称冲突?比如: [StringUtils stringToAvoidNameCollisionForPath:path]; 对于类型为:/foo/bar/file.png的给定路径,将返回/foo/bar/file-1.png,稍后它将增加“-1”,类似于Safari对下载文件所做的操作 更新: 我遵循了Ash Furrow的建议,发布了我的实现作为答案:)我有一个类似的问题,并提出了一个稍微宽泛的方法,即尝试以iTunes相同的方
[StringUtils stringToAvoidNameCollisionForPath:path];
对于类型为:/foo/bar/file.png
的给定路径,将返回/foo/bar/file-1.png
,稍后它将增加“-1”,类似于Safari对下载文件所做的操作
更新:
我遵循了Ash Furrow的建议,发布了我的实现作为答案:)我有一个类似的问题,并提出了一个稍微宽泛的方法,即尝试以iTunes相同的方式命名文件(当您将其设置为管理库,并且您有多个同名曲目时,等等) 它在一个循环中工作,因此可以多次调用该函数并仍然生成有效的输出。在解释参数时,
fileName
是没有路径或扩展名的文件名(例如“file”),folder
只是路径(例如“/foo/bar”),而fileType
只是扩展名(例如“png”)。这三个可以作为一个字符串传入,然后再拆分,但在我的情况下,将它们分开是有意义的
currentPath
(可以为空,但不能为空)在重命名文件而不是创建新文件时非常有用。例如,如果您正试图将“/foo/bar/file 1.png”重命名为“/foo/bar/file.png”,则将“/foo/bar/file 1.png”传递给currentPath
,如果“/foo/bar/file.png”已经存在,您将返回开始的路径,而不是看到“/foo/bar/file 1.png”并返回“/foo/bar/file 2.png”
我决定实现我自己的解决方案,我想分享我的代码。这不是最理想的实现,但它似乎起到了作用:
+ (NSString *)stringToAvoidNameCollisionForPath:(NSString *)path {
// raise an exception for invalid paths
if (path == nil || [path length] == 0) {
[NSException raise:@"DMStringUtilsException" format:@"Invalid path"];
}
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
BOOL isDirectory;
// file does not exist, so the path doesn't need to change
if (![manager fileExistsAtPath:path isDirectory:&isDirectory]) {
return path;
}
NSString *lastComponent = [path lastPathComponent];
NSString *fileName = isDirectory ? lastComponent : [lastComponent stringByDeletingPathExtension];
NSString *ext = isDirectory ? @"" : [NSString stringWithFormat:@".%@", [path pathExtension]];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"-([0-9]{1,})$" options:0 error:nil];
NSArray *matches = [regex matchesInString:fileName options:0 range:STRING_RANGE(fileName)];
// missing suffix... start from 1 (foo-1.ext)
if ([matches count] == 0) {
return [NSString stringWithFormat:@"%@-1%@", fileName, ext];
}
// get last match (theoretically the only one due to "$" in the regex)
NSTextCheckingResult *result = (NSTextCheckingResult *)[matches lastObject];
// extract suffix value
NSUInteger counterValue = [[fileName substringWithRange:[result rangeAtIndex:1]] integerValue];
// remove old suffix from the string
NSString *fileNameNoSuffix = [fileName stringByReplacingCharactersInRange:[result rangeAtIndex:0] withString:@""];
// return the path with the incremented counter suffix
return [NSString stringWithFormat:@"%@-%i%@", fileNameNoSuffix, counterValue + 1, ext];
}
。。。以下是我使用的测试:
- (void)testStringToAvoidNameCollisionForPath {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
// bad configs //
STAssertThrows([DMStringUtils stringToAvoidNameCollisionForPath:nil], nil);
STAssertThrows([DMStringUtils stringToAvoidNameCollisionForPath:@""], nil);
// files //
NSString *path = [bundle pathForResource:@"bar-0.abc" ofType:@"txt"];
NSString *savePath = [DMStringUtils stringToAvoidNameCollisionForPath:path];
STAssertEqualObjects([savePath lastPathComponent], @"bar-0.abc-1.txt", nil);
NSString *path1 = [bundle pathForResource:@"bar1" ofType:@"txt"];
NSString *savePath1 = [DMStringUtils stringToAvoidNameCollisionForPath:path1];
STAssertEqualObjects([savePath1 lastPathComponent], @"bar1-1.txt", nil);
NSString *path2 = [bundle pathForResource:@"bar51.foo.yeah1" ofType:@"txt"];
NSString *savePath2 = [DMStringUtils stringToAvoidNameCollisionForPath:path2];
STAssertEqualObjects([savePath2 lastPathComponent], @"bar51.foo.yeah1-1.txt", nil);
NSString *path3 = [path1 stringByDeletingLastPathComponent];
NSString *savePath3 = [DMStringUtils stringToAvoidNameCollisionForPath:[path3 stringByAppendingPathComponent:@"xxx.zip"]];
STAssertEqualObjects([savePath3 lastPathComponent], @"xxx.zip", nil);
NSString *path4 = [bundle pathForResource:@"foo.bar1-1-2-3-4" ofType:@"txt"];
NSString *savePath4 = [DMStringUtils stringToAvoidNameCollisionForPath:path4];
STAssertEqualObjects([savePath4 lastPathComponent], @"foo.bar1-1-2-3-5.txt", nil);
NSString *path5 = [bundle pathForResource:@"bar1-1" ofType:@"txt"];
NSString *savePath5 = [DMStringUtils stringToAvoidNameCollisionForPath:path5];
STAssertEqualObjects([savePath5 lastPathComponent], @"bar1-2.txt", nil);
// folders //
NSString *path6 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"foo1"];
NSString *savePath6 = [DMStringUtils stringToAvoidNameCollisionForPath:path6];
STAssertEqualObjects([savePath6 lastPathComponent], @"foo1-1", nil);
NSString *path7 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"bar1-1"];
NSString *savePath7 = [DMStringUtils stringToAvoidNameCollisionForPath:path7];
STAssertEqualObjects([savePath7 lastPathComponent], @"bar1-2", nil);
NSString *path8 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"foo-5.bar123"];
NSString *savePath8 = [DMStringUtils stringToAvoidNameCollisionForPath:path8];
STAssertEqualObjects([savePath8 lastPathComponent], @"foo-5.bar123-1", nil);
}
为什么不使用GUID作为文件名或文件夹名?检查
[[NSProcessInfo processInfo]globallyUniqueString]
否,我的问题与使字符串唯一无关(在这种情况下,我将使用CFUUIDCreate()),但我希望保留文件名并仅添加后缀以使其唯一:PI实现了我自己的解决方案。。。欢迎评论:)在原始文件名中添加一个时间戳(以秒为单位,从1970年开始)不是很容易吗?您应该发布示例代码作为答案,然后接受它。Sweet。很好。但是注意到它是“命名123.ext”而不是“命名3.ext”,但不管怎样。这是我有意的。如果传入的文件名末尾带有数字,则假定该文件名是要保留的。如果这不是期望的行为,那么在原始文件名的结尾处修剪数字和空白就足够容易了。
- (void)testStringToAvoidNameCollisionForPath {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
// bad configs //
STAssertThrows([DMStringUtils stringToAvoidNameCollisionForPath:nil], nil);
STAssertThrows([DMStringUtils stringToAvoidNameCollisionForPath:@""], nil);
// files //
NSString *path = [bundle pathForResource:@"bar-0.abc" ofType:@"txt"];
NSString *savePath = [DMStringUtils stringToAvoidNameCollisionForPath:path];
STAssertEqualObjects([savePath lastPathComponent], @"bar-0.abc-1.txt", nil);
NSString *path1 = [bundle pathForResource:@"bar1" ofType:@"txt"];
NSString *savePath1 = [DMStringUtils stringToAvoidNameCollisionForPath:path1];
STAssertEqualObjects([savePath1 lastPathComponent], @"bar1-1.txt", nil);
NSString *path2 = [bundle pathForResource:@"bar51.foo.yeah1" ofType:@"txt"];
NSString *savePath2 = [DMStringUtils stringToAvoidNameCollisionForPath:path2];
STAssertEqualObjects([savePath2 lastPathComponent], @"bar51.foo.yeah1-1.txt", nil);
NSString *path3 = [path1 stringByDeletingLastPathComponent];
NSString *savePath3 = [DMStringUtils stringToAvoidNameCollisionForPath:[path3 stringByAppendingPathComponent:@"xxx.zip"]];
STAssertEqualObjects([savePath3 lastPathComponent], @"xxx.zip", nil);
NSString *path4 = [bundle pathForResource:@"foo.bar1-1-2-3-4" ofType:@"txt"];
NSString *savePath4 = [DMStringUtils stringToAvoidNameCollisionForPath:path4];
STAssertEqualObjects([savePath4 lastPathComponent], @"foo.bar1-1-2-3-5.txt", nil);
NSString *path5 = [bundle pathForResource:@"bar1-1" ofType:@"txt"];
NSString *savePath5 = [DMStringUtils stringToAvoidNameCollisionForPath:path5];
STAssertEqualObjects([savePath5 lastPathComponent], @"bar1-2.txt", nil);
// folders //
NSString *path6 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"foo1"];
NSString *savePath6 = [DMStringUtils stringToAvoidNameCollisionForPath:path6];
STAssertEqualObjects([savePath6 lastPathComponent], @"foo1-1", nil);
NSString *path7 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"bar1-1"];
NSString *savePath7 = [DMStringUtils stringToAvoidNameCollisionForPath:path7];
STAssertEqualObjects([savePath7 lastPathComponent], @"bar1-2", nil);
NSString *path8 = [DOCUMENTS_PATH stringByAppendingPathComponent:@"foo-5.bar123"];
NSString *savePath8 = [DMStringUtils stringToAvoidNameCollisionForPath:path8];
STAssertEqualObjects([savePath8 lastPathComponent], @"foo-5.bar123-1", nil);
}