Objective-C:逐行读取文件

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

这将一般阅读一个工作StringText.如果你想阅读更长的文本(大文本),那么使用其他人提到的方法,如缓冲(保留内存空间中文本的大小).

假设你读了一个文本文件.

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)

你有它.

  • 这个问题没有回应.问题是逐行读取文件以减少内存使用量 (37认同)
  • 我有一个70 MB的文件,使用这段代码来读取文件并不是因为它会线性增加内存.谁能帮我? (17认同)

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).

  • 请参阅Dave DeLong在此处解决此问题的综合方法:http://stackoverflow.com/questions/3707427#3711079 (10认同)

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 fopenfgetsfrom <stdio.h>.它保证工作.

[NSString stringWithUTF8String:buf]将C字符串转换为NSString.还有一些方法可以在其他编码中创建字符串,并且无需复制即可创建.


die*_*ikh 9

您可以使用NSInputStream哪个具有文件流的基本实现.您可以将字节读入缓冲区(read:maxLength:方法).您必须自己扫描缓冲区以获取换行符.


Sti*_*set 6

Apple的String编程指南中记录了在Cocoa/Objective-C中读取文本文件的适当方法.阅读和编写文件的部分应该就是你所追求的.PS:什么是"线"?字符串的两个部分用"\n"分隔?还是"\ r"?还是"\ r \n"?或许你真的在段落之后?前面提到的指南还包括将字符串拆分为行或段落的部分.(此部分称为"段落和换行符",并链接到我在上面指出的页面的左侧菜单中.不幸的是,这个站点不允许我发布多个URL,因为我是还不是值得信赖的用户.)

用Knuth来解释:过早的优化是万恶之源.不要简单地假设"将整个文件读入内存"很慢.你有基准测试吗?你知道它实际上是将整个文件读入内存吗?也许它只是返回一个代理对象,并在消耗字符串时继续在后台阅读?(免责声明:我不知道NSString是否真的这样做.可以想象.)重点是:首先采用记录的做事方式.然后,如果基准测试显示这没有您想要的性能,那么优化.


wda*_*xna 5

正如@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)


DCu*_*rro 5

很多这些答案都是很长的代码块,或者它们在整个文件中读取.我喜欢使用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终止腾出空间.