在Cocoa中如何重命名文件?

24

如何重命名文件并保留在同一目录中?

我有一个包含完整文件路径的字符串和一个包含新文件名(不包含路径)的字符串,例如:

NSString *old_filepath = @"/Volumes/blah/myfilewithrubbishname.avi";
NSString *new_filename = @"My Correctly Named File.avi";

我知道NSFileManager的movePath:toPath:handler:方法,但我不知道如何构建新文件的路径。

基本上,我正在寻找以下Python代码的等效代码:

>>> import os
>>> old_filepath = "/Volumes/blah/myfilewithrubbishname.avi"
>>> new_filename = "My Correctly Named File.avi"
>>> dirname = os.path.split(old_filepath)[0]
>>> new_filepath = os.path.join(dirname, new_filename)
>>> print new_filepath
/Volumes/blah/My Correctly Named File.avi
>>> os.rename(old_filepath, new_filepath)
5个回答

36

NSFileManager和NSWorkspace都有文件操作方法,但NSFileManager的- (BOOL)movePath:(NSString *)source toPath:(NSString *)destination handler:(id)handler 可能是你最好的选择。使用NSString的路径操作方法来正确获取文件和文件夹名称。例如,

NSString *newPath = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newFilename];
[[NSFileManager defaultManager] movePath:oldPath toPath:newPath handler:nil];

这两个类在文档中都有很好地解释,如果您有任何不理解的地方,请留下评论。


啊哈,我之前漏掉了stringBy___PathComponents方法,谢谢! - dbr
18
movePath:toPath:handler:已被弃用,推荐使用moveItemAtPath:toPath:error:。如果失败,后者会告诉您为什么失败,同时请注意保持原意不变。 - Peter Hosey
嗨,@Marc Charbonneau。我知道这个答案很好。但是我的问题是,我想让“newFilename”有一个“/”。例如,我想将“123.mp3”重命名为“12/3.mp3”,但它不起作用。我认为NSFileManager将“/”视为路径。 - Vienta
自OS X 10.5起已被弃用。 - Aviram Netanel

14

值得注意的是,将文件移动到其本身将会失败。我有一个方法,将空格替换为下划线并将文件名转换为小写,然后将文件重命名为新名称。只有一个单词的文件名将在重命名时失败,因为在不区分大小写的文件系统上,新名称将与原名称相同。

我解决这个问题的方法是进行两步重命名,首先将文件重命名为临时名称,然后再将其重命名为预期的名称。

以下是一些伪代码,用于解释此过程:

NSString *source = @"/FILE.txt";
NSString *newName = [[source lastPathComponent] lowercaseString];
NSString *target = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];

[[NSFileManager defaultManager] movePath:source toPath:target error:nil]; // <-- FAILS
解决方案:
NSString *source = @"/FILE.txt";
NSString *newName = [[source lastPathComponent] lowercaseString];

NSString *temp = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-temp", newName]];
NSString *target = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];

[[NSFileManager defaultManager] movePath:source toPath:temp error:nil];
[[NSFileManager defaultManager] movePath:temp toPath:target error:nil];

2
我会说,在移动文件之前仅检查新旧名称是否相等可能比移动文件两次对性能更好。 - 11684
1
但这并不能实现改变文件名大小写的目标。 - Joe Strout

8

我只想让新手更容易理解。这是所有代码:

    NSString *oldPath = @"/Users/brock/Desktop/OriginalFile.png";
NSString *newFilename = @"NewFileName.png";

NSString *newPath = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newFilename];
[[NSFileManager defaultManager] movePath:oldPath toPath:newPath handler:nil];

NSLog( @"File renamed to %@", newFilename );

4

这里是一个更近期的iOS示例,NSFileManager方法有一点不同:

NSString *newFilename = [NSString stringWithFormat:@"%@.m4a", newRecording.title];

NSString *newPath = [[newRecording.localPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newFilename];
[[NSFileManager defaultManager] moveItemAtPath:newRecording.localPath toPath:newPath error:nil];

0
为了更加完美,NSFileManager中有一个类别:
@implementation NSFileManager (FileManipulations)


- (void)changeFileNamesInDirectory:(NSString *)directory changeBlock:(NSString * (^) (NSString *fileName))block
{
    NSString *inputDirectory = directory;

    NSFileManager *fileManager = [NSFileManager new];

    NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:inputDirectory error:nil];
    for (NSString *fileName in fileNames) {

        NSString *newFileName =  block(fileName);

        NSString *oldPath = [NSString stringWithFormat:@"%@/%@", inputDirectory, oldFileName];
        // move to temp path so case changes can happen
        NSString *tempPath = [NSString stringWithFormat:@"%@-tempName", oldPath];
        NSString *newPath = [[oldPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:newFileName];

        NSError *error = nil;
        [fileManager moveItemAtPath:oldPath toPath:tempPath error:&error];
        if (error) {
            NSLog(@"%@", [error localizedDescription]);
            return;
        }
        [fileManager moveItemAtPath:tempPath toPath:newPath error:&error];
        if (error) {
            NSLog(@"%@", [error localizedDescription]);
        }
    }
}


@end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接