假设我有这样的文本文件 my.txt
this is line 1
this is line 2
....
this is line 999999
this is line 1000000
在 Unix 中,我可以通过发出“head -1000 my.txt | tail -1”之类的命令来获得“这是第 1000 行”的行。在 Objective-C 中得到这个的相应方法是什么?
假设我有这样的文本文件 my.txt
this is line 1
this is line 2
....
this is line 999999
this is line 1000000
在 Unix 中,我可以通过发出“head -1000 my.txt | tail -1”之类的命令来获得“这是第 1000 行”的行。在 Objective-C 中得到这个的相应方法是什么?
如果一次将整个内容存储在内存中并不是太低效,那么最紧凑的调用序列(为了更简单的说明,我已经扩展为多行)将是:
NSError *error = nil;
NSString *sourceString = [NSString stringWithContentsOfFile:@"..."
encoding:NSUTF8StringEncoding error:&error];
NSArray *lines = [sourceString componentsSeparatedByCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
NSString *relevantLine = [lines objectAtIndex:1000];
您应该检查 oferror
和count
of的值以lines
进行验证。
编辑:与 Nathan 的回答相比,按集合中的字符拆分的好处是,您将接受可能分隔换行符的五个 unicode 字符中的任何一个,其中几个字符彼此相邻的任何地方都算作仅一次休息(根据例如\r\n
)。
NSInputStream
如果内存占用是一个问题,这可能是您必须处理的问题,它几乎不比 C 的 stdio.h fopen/fread/etc 进化,所以您将不得不编写自己的小循环来冲刺.
答案没有解释如何读取太大而无法保存在内存中的文件。在 Objective-C 中没有很好的解决方案来读取大型文本文件而不将它们放入内存(这并不总是一种选择)。
在这些情况下,我喜欢使用 c 方法:
FILE* file = fopen("path to my file", "r");
size_t length;
char *cLine = fgetln(file,&length);
while (length>0) {
char str[length+1];
strncpy(str, cLine, length);
str[length] = '\0';
NSString *line = [NSString stringWithFormat:@"%s",str];
% Do what you want here.
cLine = fgetln(file,&length);
}
请注意, fgetln 不会保留您的换行符。此外,我们将 str 的长度 +1,因为我们想为 NULL 终止腾出空间。
我不认为这是完全重复的,因为听起来您想跳过文件中的某些行,但是您可以轻松使用此处的方法:
Objective-C:逐行读取文件 (有一些示例代码的具体答案)
循环输入文件,读入一大块数据,然后寻找换行符。数一数,当你打到正确的数字时,输出那个之后的数据,直到下一个。
您的示例看起来可能有数十万行,因此绝对不要只将文件读入 NSString,也绝对不要将其转换为 NSArray。
如果您想使用更高级的 NSInputStream 方式(在字符集解码方面具有一些关键优势),这里有一个很好的示例,它展示了轮询以使用来自流源的所有数据的基本思想(在文件示例中,它有点矫枉过正)。它用于输出,但这个想法也适用于输入: 轮询与运行循环调度
最简单的方法是使用 NSString 文件方法之一加载文件,然后使用 -[NSString componentsSeparatedByString:] 方法获取每一行的数组。
或者您可以使用 NSScanner,扫描换行符/回车符,对它们进行计数,直到找到您感兴趣的行。
如果您真的担心内存使用情况,您可以查看 NSInputStream 使用它来读取文件,并计算换行符的数量。很遗憾 NSScanner 不能与 NSInputStream 一起使用。