파일에서 한줄씩 읽어 들이기 - Objective-C

파이썬에서는 텍스트 파일을 가리키는 파일 객체는 파일 내용의 각 라인에 대한 이터레이터처럼 작동한다. 따라서 별다른 노력을 들이지 않고 for ... in 구문을 통해서 텍스트 파일의 각 라인을 읽어서 처리하는 것이 가능하다. 이 기능의 멋진 점은 파일 객체가 느긋하게 동작하기 때문에 각 라인이 필요한 시점에 한 라인씩 읽어들인다는 것인데, 따라서 각 라인의 길이가 적절하다면 파일의 크기가 아무리 크더라도 안전하게 읽어들일 수 있다는 것이다.

Objective-C에서 텍스트 파일은 보통 NSStringstringWithContentOfFile: 메소드를 사용한다. 이 메소드의 문제는 파일을 한 번에 읽어들인 다는 점이다. 따라서 읽을 파일이 얼마나 클 것인지에 대한 제약이 확실하지 않다면 사용하기 위험한 방법일 수 있다.

이런 경우에 사용할 수 있는 방법으로 NSInputStream을 이용하는 것을 들 수 있다. (참고: Reading From Input Streams) 문제는 이 입력 스트림은 단순히 파일만을 위한 클래스가 아니어서 비동기로 작동한다. 정해진 분량만큼 버퍼로 읽어들인 후 이벤트를 생성해서 델리게이트가 처리하는 방식으로 돌아가기 때문에 파일에 사용하기에는 좀 번거로운 면이 있다.

조금씩 읽기

이래 저래 방법이 없나 알아보던 중에 그냥 C로 구현하면 되지하는 생각이 들었다.

NSString * readLineAsNSString(FILE *file) {
    int charsRead = 4096;
    char buffer[4096];
    NSMutableString *result = [NSMutableString stringWithCapacity:4096];
    while( charsRead == 4096) {
        if (fscanf(file, "%4095[^\r\n]%n%*[\r\n]", buffer, &charsRead) == 1) {
            [result appendFormat:@"%s", buffer];
        } else {
            break;
        }
    }
    return result;
}

위 코드는 흔한? fscanf() 함수를 사용한다. scan* 류의 함수는 입력 받는 형식에 대해 포맷을 지정할 수 있다는 것은 기본적으로 알고 있는 것인데, 여기에 사용되는 포맷에 몇 가지 기능이 더 있다.

  • 먼저 포맷 앞에 숫자를 표시하면 최대 해당 바이트 수까지를 읽어들인다는 뜻이다. 그리고 %[^...] 포맷은 [^...] 내부의 문자가 아닌 것을 읽겠다는 이야기다. 따라서 %4095[^\r\n] 은 개행문자까지 읽어들이되, 개행 문자 앞의 최대 4095 바이트를 읽는다는 이야기다.
  • %n 은 바로 앞의 패턴에서 읽어들인 바이트 수를 의미한다.
  • %*는 이 이후의 읽어들인 분량은 읽기만 하고 버퍼로 옮기지는 않는다. %*[...] 는 …까지를 읽되, 읽기만 하고 무시한다. 왜냐하면 앞에서 [^\r\n]에 의해서 개행 문자 앞까지만 읽었기 때문이다.

이 함수를 사용하면 열어 놓은 파일을 매번 넘겨서 한 줄씩 읽어들일 수 있게 된다. 물론 한 줄이 4095자보다 길다면, 그 4095자까지만 읽게 될 것이다. 다음과 같은 식으로 파일을 열어서 한 줄씩 출력할 수 있다.

사용법

FILE *f = fopen("mytext.txt", "r");
while (!feof(f)) {
    NSString *line = readLineAsNSString(f);
    NSLog(@"%@", line);
}
fclose(f);

feof() 함수는 파일의 끝에 도달했는지 여부를 체크하는 함수이다. (파일의 끝까지 읽었다면 1을 리턴) 이 함수를 사용하여 루프를 돌면서 파일을 한 줄 씩 처리할 수 있다.

Read more

워드프레스에서 고스트로 이전

워드프레스에서 고스트로 이전

이 글을 쓰면서도 믿기 힘든 사실인데, 블로그라는 걸 처음 시작한지가 20년이 되었습니다. 이글루스에서 처음 시작했다가, SK컴즈가 인수한다고 발표함과 동시에 워드프레스로 플랫폼을 옮겼죠. 워드프레스오 옮긴 이후에는 호스팅 환경을 이리 저리 옮기긴 했지만 거의 18년 가까이 워드프레스를 사용해온 것 같습니다. 그 동안 워드프레스는 블로깅 툴에서 명실상부한 범용CMS로 발전했습니다. 사실 웬만한 홈페이지들은 이제

By sooop
띄어쓰기에 대한 생각

띄어쓰기에 대한 생각

업무 메일을 쓸 때 가장 많이 쓰는 말 중에 하나가 메일 말미에 ‘업무에 참고 부탁 드립니다.‘인데요, 어느 날부터 아웃룩에서 이 ‘부탁 드립니다’가 틀렸다고 맞춤법 지적을 하기 시작했습니다. 맞는 말은 ‘부탁드립니다’라고 붙여 쓰는 거라고. 사실 아래아한글 시절부터 이전의 MS워드까지, 워드프로세서들의 한국어 맞춤법 검사 실력은 거의 있으나 마나 한

By sooop

구글 포토에서 아이클라우드로 탈출한 후기

한 때 구글 포토가 백업 용량을 무제한으로 제공해 주겠다고해서, 구글 포토를 사용해서 사진을 백업해왔습니다. 물론 이 이야기의 결말은 저나 이 글을 읽고 있는 여러분이나 모두 알고 있습니다. 사실 AI에게 학습 시킬 이미지 데이터를 모으기 위한 것일 뿐이라거나 하는 이야기는 그 당시에도 있었습니다만, 에이 그래도 구글인데 용량은 넉넉하게 주겠지…하는 순진한

By sooop

Julia의 함수 사용팁

연산자의 함수적 표기 Julia의 연산자는 기본적으로 함수이며, 함수 호출 표기와 같은 방식으로 호출하는 것이 가능합니다. 또한 그 자체로 함수이기 때문에 filter(), map() 과 같이 함수를 인자로 받는 함수에도 연산자를 그대로 적용하는 것이 가능합니다. 특히 + 연산자는 sum() 함수와 같이 여러 인자를 받아 인자들의 합을 구할 수 있습니다. 2 + 3 # = 5 +(2,

By sooop