[objective-c] 목표 -C : 파일을 한 줄씩 읽기

Objective-C에서 큰 텍스트 파일을 처리하는 적절한 방법은 무엇입니까? 각 줄을 개별적으로 읽고 각 줄을 NSString으로 취급하려고한다고 가정 해 봅시다. 가장 효율적인 방법은 무엇입니까?

한 가지 해결책은 NSString 방법을 사용하는 것입니다.

+ (id)stringWithContentsOfFile:(NSString *)path
      encoding:(NSStringEncoding)enc
      error:(NSError **)error 

그런 다음 줄 바꿈 구분 기호로 줄을 분할 한 다음 배열의 요소를 반복합니다. 그러나 이것은 상당히 비효율적입니다. 파일을 한 번에 모두 읽는 대신 파일을 스트림으로 취급하여 각 줄을 열거하는 쉬운 방법이 있습니까? Java의 java.io.BufferedReader를 좋아하십시오.



답변

좋은 질문입니다. @Diederik 은 좋은 대답을 가지고 있다고 생각 하지만, Cocoa가 정확히 당신이하고 싶은 일에 대한 메커니즘을 가지고 있지 않다는 것은 불행합니다.

NSInputStreamN 바이트 청크 (매우 유사 java.io.BufferedReader) 를 읽을 수는 있지만 직접로 변환 NSString한 다음 줄 바꿈 (또는 다른 구분 기호)을 스캔하고 다음 읽기를 위해 나머지 문자를 저장하거나 더 많은 문자를 읽으십시오 개행을 아직 읽지 않은 경우. ( NSFileHandle당신은 읽을 수 NSData있는 당신이 다음에 변환 할 수 있습니다NSString 있지만 본질적으로 동일한 프로세스입니다.)

Apple은 세부 사항을 작성하는 데 도움 이되는 스트림 프로그래밍 안내서 를 가지고 있으며이 SO 질문uint8_t*버퍼를 다루는 데 도움이 될 수 있습니다 .

당신이 (특히 프로그램의 다른 부분에) 자주 같은 문자열을 읽기 위하여려고하는 경우 당신에 대한 세부 정보를 처리, 또는 서브 클래스 수있는 클래스에서이 동작을 캡슐화하는 좋은 아이디어가 될 것입니다 NSInputStream(이 있어요 수 있도록 설계 서브 클래스 )와 정확히 당신이 원하는 것을 읽을 수 있도록 방법을 추가.

레코드의 경우이 기능을 추가하는 것이 좋을 것으로 생각되며이를 가능하게하는 개선 요청을 제출할 것입니다. 🙂


편집 : 이 요청이 이미 존재합니다. 이를 위해 2006 년부터 데이트 한 레이더가 있습니다 (Apple-internal people의 경우 rdar : // 4742914).


답변

이것은 일반적으로 읽기 A의 작동 String에서 Text. 더 긴 텍스트 (큰 텍스트) 를 읽으려면 버퍼링 (메모리 공간에서 텍스트 크기 예약) 과 같은 다른 사람들이 언급 한 방법을 사용하십시오 .

텍스트 파일을 읽었다 고 가정하십시오.

NSString* filePath = @""//file path...
NSString* fileRoot = [[NSBundle mainBundle]
               pathForResource:filePath ofType:@"txt"];

새 줄을 제거하고 싶습니다.

// 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:@";"]];

거기 있어요


답변

트릭을 수행해야합니다.

#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;
}

다음과 같이 사용하십시오.

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

이 코드는 파일에서 개행 문자를 한 번에 최대 4095 개까지 읽습니다. 4095자를 초과하는 줄이 있으면 줄 바꿈이나 파일 끝이 될 때까지 계속 읽습니다.

참고 :이 코드는 테스트하지 않았습니다. 사용하기 전에 테스트하십시오.


답변

Mac OS X은 Unix이고 Objective-C는 C 수퍼 셋이므로 구식 fopenfgets에서 사용할 수 있습니다 <stdio.h>. 작동합니다.

[NSString stringWithUTF8String:buf]C 문자열을로 변환합니다 NSString. 다른 인코딩으로 문자열을 작성하고 복사하지 않고 작성하는 방법도 있습니다.


답변

NSInputStream파일 스트림에 대한 기본 구현이있는 것을 사용할 수 있습니다 . 바이트를 버퍼로 읽을 수 있습니다 ( read:maxLength:메소드). 개행을 위해 버퍼를 직접 스캔해야합니다.


답변

Cocoa / Objective-C에서 텍스트 파일을 읽는 적절한 방법은 Apple의 String 프로그래밍 안내서에 설명되어 있습니다. 파일읽고 쓰는 부분은 당신이 추구하는 것이어야합니다. PS : “라인”이란 무엇입니까? “\ n”으로 구분 된 문자열의 두 섹션? 아니면 “\ r”? 아니면 “\ r \ n”? 아니면 실제로 단락 뒤에 있습니까? 앞에서 언급 한 안내서에는 문자열을 줄이나 단락으로 나누는 섹션도 포함되어 있습니다. (이 섹션은 “단락 및 줄 바꿈”이라고하며 위에서 지적한 페이지의 왼쪽 메뉴에 링크되어 있습니다. 불행히도이 사이트에서는 내가 URL을 두 개 이상 게시 할 수 없습니다. 신뢰할 수있는 사용자가 아닙니다.)

크 누스의 말을 인용하자면 : 조기 최적화는 모든 악의 근원입니다. 단순히 “전체 파일을 메모리로 읽는”속도가 느리다고 가정하지 마십시오. 벤치마킹 했습니까? 실제로 전체 파일을 메모리로 읽는다는 것을 알고 있습니까? 어쩌면 단순히 프록시 객체를 반환하고 문자열을 소비하면서 장면 뒤에서 계속 읽는가? ( 면책 조항 : NSString이 실제로이 작업을 수행하는지 알 수 없습니다. 아마도 가능합니다. ) 요점은 : 먼저 문서화 된 방식으로 작업을 수행하는 것입니다. 그런 다음 벤치 마크에서 원하는 성능이없는 것으로 나타나면 최적화하십시오.


답변

이러한 많은 답변은 긴 코드 덩어리이거나 전체 파일에서 읽습니다. 이 작업에 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은 개행 문자를 유지하지 않습니다. 또한 NULL 종료를위한 공간을 만들고 싶기 때문에 str의 길이를 +1합니다.