138 file-io objective-c enumerate nsstring nsstream
在Objective-C中处理大型文本文件的适当方法是什么?假设我需要分别读取每一行,并希望将每一行视为NSString.这样做最有效的方法是什么?
一种解决方案是使用NSString方法:
+ (id)stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc
error:(NSError **)error
Run Code Online (Sandbox Code Playgroud)
然后使用换行符分隔符拆分行,然后遍历数组中的元素.但是,这似乎效率很低.有没有简单的方法将文件视为一个流,枚举每一行,而不是一次只读取它?有点像Java的java.io.BufferedReader.
Yoo*_*Lee 94
这将一般阅读一个工作String的Text.如果你想阅读更长的文本(大文本),那么使用其他人提到的方法,如缓冲(保留内存空间中文本的大小).
NSString* filePath = @""//file path...
NSString* fileRoot = [[NSBundle mainBundle]
pathForResource:filePath ofType:@"txt"];
Run Code Online (Sandbox Code Playgroud)
// read everything from text
NSString* fileContents =
[NSString stringWithContentsOfFile:fileRoot
encoding:NSUTF8StringEncoding error:nil];
// first, separate by new line
NSArray* allLinedStrings =
[fileContents componentsSeparatedByCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
// then break down even further
NSString* strsInOneLine =
[allLinedStrings objectAtIndex:0];
// choose whatever input identity you have decided. in this case ;
NSArray* singleStrs =
[currentPointString componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:@";"]];
Run Code Online (Sandbox Code Playgroud)
你有它.
Qui*_*lor 63
这是一个很好的问题.我认为@Diederik有一个很好的答案,尽管不幸的是Cocoa没有一个机制来确切地说你想做什么.
NSInputStream允许您读取N个字节的块(非常相似java.io.BufferedReader),但您必须自己将其转换为a NSString,然后扫描换行符(或任何其他分隔符)并保存任何剩余的字符以供下次读取,或者读取更多字符如果还没有读取换行符.(NSFileHandle让你读一个NSData你可以转换成一个NSString,但它基本上是相同的过程.)
Apple有一个Stream Programming Guide可以帮助填写详细信息,如果您要处理缓冲区,这个SO问题也可能会有所帮助uint8_t*.
如果您要经常阅读这样的字符串(特别是在程序的不同部分),最好将这种行为封装在一个可以为您处理细节的类中,甚至是子类化NSInputStream(它的设计是子类化)并添加允许您准确读取所需内容的方法.
为了记录,我认为这将是一个很好的功能添加,我将提出一个增强请求,使这成为可能.:-)
编辑:原来这个请求已经存在.有一个雷达可以追溯到2006年(对于Apple内部人来说是rdar:// 4742914).
Ada*_*eld 34
这应该做的伎俩:
#include <stdio.h>
NSString *readLineAsNSString(FILE *file)
{
char buffer[4096];
// tune this capacity to your liking -- larger buffer sizes will be faster, but
// use more memory
NSMutableString *result = [NSMutableString stringWithCapacity:256];
// Read up to 4095 non-newline characters, then read and discard the newline
int charsRead;
do
{
if(fscanf(file, "%4095[^\n]%n%*c", buffer, &charsRead) == 1)
[result appendFormat:@"%s", buffer];
else
break;
} while(charsRead == 4095);
return result;
}
Run Code Online (Sandbox Code Playgroud)
使用方法如下:
FILE *file = fopen("myfile", "r");
// check for NULL
while(!feof(file))
{
NSString *line = readLineAsNSString(file);
// do stuff with line; line is autoreleased, so you should NOT release it (unless you also retain it beforehand)
}
fclose(file);
Run Code Online (Sandbox Code Playgroud)
此代码从文件中读取非换行符,一次最多4095个.如果您的行长度超过4095个字符,则会一直读取,直到它到达换行符或文件结尾.
注意:我没有测试过这段代码.请在使用前进行测试.
Kor*_*nel 12
Mac OS X是Unix,Objective-C是C超集,所以你可以只使用old-school fopen和fgetsfrom <stdio.h>.它保证工作.
[NSString stringWithUTF8String:buf]将C字符串转换为NSString.还有一些方法可以在其他编码中创建字符串,并且无需复制即可创建.
Apple的String编程指南中记录了在Cocoa/Objective-C中读取文本文件的适当方法.阅读和编写文件的部分应该就是你所追求的.PS:什么是"线"?字符串的两个部分用"\n"分隔?还是"\ r"?还是"\ r \n"?或许你真的在段落之后?前面提到的指南还包括将字符串拆分为行或段落的部分.(此部分称为"段落和换行符",并链接到我在上面指出的页面的左侧菜单中.不幸的是,这个站点不允许我发布多个URL,因为我是还不是值得信赖的用户.)
用Knuth来解释:过早的优化是万恶之源.不要简单地假设"将整个文件读入内存"很慢.你有基准测试吗?你知道它实际上是将整个文件读入内存吗?也许它只是返回一个代理对象,并在消耗字符串时继续在后台阅读?(免责声明:我不知道NSString是否真的这样做.可以想象.)重点是:首先采用记录的做事方式.然后,如果基准测试显示这没有您想要的性能,那么优化.
正如@porneL 所说,C api 非常方便。
NSString* fileRoot = [[NSBundle mainBundle] pathForResource:@"record" ofType:@"txt"];
FILE *file = fopen([fileRoot UTF8String], "r");
char buffer[256];
while (fgets(buffer, 256, file) != NULL){
NSString* result = [NSString stringWithUTF8String:buffer];
NSLog(@"%@",result);
}
Run Code Online (Sandbox Code Playgroud)
很多这些答案都是很长的代码块,或者它们在整个文件中读取.我喜欢使用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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,fgetln不会保留换行符.另外,我们+1为str的长度,因为我们想为NULL终止腾出空间.