>  기사  >  백엔드 개발  >  Go의 긴 텍스트 파일에서 패턴이 포함된 줄을 무시합니다.

Go의 긴 텍스트 파일에서 패턴이 포함된 줄을 무시합니다.

WBOY
WBOY앞으로
2024-02-13 13:57:19993검색

在 Go 中忽略长文本文件中包含模式的行

php Editor Apple Go 언어에서는 대용량 텍스트 파일을 처리해야 하는 경우가 많습니다. 때때로 우리는 특정 패턴을 포함하는 행에만 관심이 있고 다른 행은 무시합니다. 다행히 Go에서는 정규식과 bufio.Scanner를 사용하여 이 목표를 달성할 수 있습니다. 정규식을 사용하여 줄을 일치시키고 스캐너를 통해 파일을 한 줄씩 실행함으로써 관심 없는 줄을 쉽게 필터링할 수 있습니다. 이 팁은 효율성을 향상시킬 뿐만 아니라 코드를 더욱 간결하고 읽기 쉽게 만듭니다. 다음으로 Go에서 긴 텍스트 파일의 패턴이 포함된 줄을 무시하는 방법을 살펴보겠습니다.

질문 내용

go에서 긴 텍스트 파일(ascii 보장)에서 패턴이 포함된 줄을 무시하는 기능을 구현하려고 합니다

저는 withoutignorewithignore 下面的函数都接受文件名参数输入并返回 *byte.buffer,随后可用于写入 io.writer입니다.

withignore 函数采用附加参数 pattern 从文件中排除包含模式的行。该函数可以工作,但通过基准测试,发现它比 慢 5 倍而不忽略 . 개선할 수 있는 방법이 있나요?

으아악

벤치마크

으아악

명령줄에서도 사용할 수 있습니다“base64dump.log”生成

package main

import (
    "bufio"
    "bytes"
    "io"
    "log"
    "os"
)

func withoutignore(f string) (*bytes.buffer, error) {
    rfd, err := os.open(f)
    if err != nil {
        log.fatal(err)
    }

    defer func() {
        if err := rfd.close(); err != nil {
            log.fatal(err)
        }
    }()

    inputbuffer := make([]byte, 1048576)
    var bytesread int

    var bs []byte
    opbuffer := bytes.newbuffer(bs)

    for {
        bytesread, err = rfd.read(inputbuffer)

        if err == io.eof {
            return opbuffer, nil
        }

        if err != nil {
            return nil, nil
        }

        _, err = opbuffer.write(inputbuffer[:bytesread])
        if err != nil {
            return nil, err
        }
    }
    return opbuffer, nil
}

func withignore(f, pattern string) (*bytes.buffer, error) {
    rfd, err := os.open(f)
    if err != nil {
        log.fatal(err)
    }

    defer func() {
        if err := rfd.close(); err != nil {
            log.fatal(err)
        }
    }()

    scanner := bufio.newscanner(rfd)
    var bs []byte
    buffer := bytes.newbuffer(bs)
    for scanner.scan() {
        if !bytes.contains(scanner.bytes(), []byte(pattern)) {
            _, err := buffer.writestring(scanner.text() + "\n")
            if err != nil {
                return nil, nil
            }
        }
    }

    return buffer, nil
}

func main() {
    // buff, err := withoutignore("base64dump.log")
    buff, err := withignore("base64dump.log", "audit")
    if err != nil {
        log.fatal(err)
    }

    _, err = buff.writeto(os.stdout)
    if err != nil {
        log.fatal(err)
    }
}

Solution

ASCII가 보장되므로 byte 수준에서 직접 작동할 수 있습니다.

그러나 입력을 읽을 때 각 바이트에서 개행 문자를 확인한 다음 줄 내에서 패턴을 다시 검색하면 작업이 각 바이트에 적용됩니다.

반면, 각 입력 바이트를 확인하지 않고도 입력 블록을 읽고 텍스트의 패턴에 대한 최적화된 검색을 수행하면 입력 바이트당 작업을 최소화할 수 있습니다.

예를 들어 boyer-moore 문자열 검색 알고리즘입니다. Go에 내장된 bytes.index 기능도 최적화되었습니다. 물론 달성되는 속도는 입력 데이터와 실제 모드에 따라 달라집니다. 질문에 지정된 입력에 대해 측정 시 `bytes.index의 성능이 크게 향상되었습니다.

프로그램

  • 블록 크기가 최대 줄 길이보다 상당히 길어야 하는 블록을 읽을 때 64kb보다 큰 값이 좋을 것입니다. 테스트에서는 질문에 1mb를 사용했습니다.
  • 블록은 일반적으로 개행으로 끝나지 않으므로 블록 끝에서 다음 개행까지 검색하고 검색을 이 슬라이스로 제한하고 다음 패스를 위해 나머지 데이터를 기억하세요
  • 마지막 블록이 반드시 개행 문자로 끝나는 것은 아닙니다
  • 고성능 바둑 기능의 도움으로 bytes.index 블록에서 패턴이 발생하는 위치를 찾을 수 있습니다
  • 찾은 위치에서 앞뒤 개행 문자 검색
  • 그런 다음 블록은 해당 줄의 시작 부분으로 출력됩니다
  • 그리고 패턴이 나타나는 줄의 끝부터 계속 검색하세요
  • 다른 위치가 검색되지 않으면 나머지 위치를 출력하세요
  • 다음 청크를 읽고 파일 끝에 도달할 때까지 다시 설명된 단계를 적용하세요

참고할 만한

읽기 작업은 블록 크기보다 적은 데이터를 반환할 수 있으므로 데이터의 블록 크기를 읽을 때까지 읽기 작업을 반복하는 것이 좋습니다.

벤치마크

최적화된 코드는 일반적으로 훨씬 더 복잡하지만 나중에 살펴보겠지만 훨씬 더 나은 성능을 발휘합니다.

으아악

여기서 최적화된 코드benchmarktestfilter-8只比没有过滤的操作慢1.9倍左右,而benchmarktestwithignore-8방법은 필터링되지 않은 비교 값보다 5.4배 느립니다.

다른 관점에서 살펴보세요. 최적화된 코드는 최적화되지 않은 코드보다 2.8배 빠릅니다.

코드

물론, 자체 테스트를 위한 코드는 다음과 같습니다.

으아악

벤치마크 섹션은 다음과 같습니다.

으아악

필터 기능이 분할되어 실제 작업은 func filter(reader io.reader,pattern []byte, chunksize int) (*bytes.buffer, error)에서 이루어집니다.

여기에는 없지만 인덱스를 다룰 때 반드시 권장되는 리더 및 청크 크기를 주입하여 단위 테스트 생성을 준비하거나 고려했습니다.

그러나 여기서 중요한 점은 성능을 크게 향상시킬 수 있는 방법을 찾는 것입니다.

위 내용은 Go의 긴 텍스트 파일에서 패턴이 포함된 줄을 무시합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 stackoverflow.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제