2013-12-07 3 views
2

기존의 자식 io.Reader의 버퍼링 된 판독기를 작성해야하지만 해당 판독기는 이미 자식으로부터 읽혀 버퍼링 된 데이터를 찾는 것을 지원해야합니다.버퍼링 된 판독기에서 검색

그래서 n 바이트가 이미 읽혀지면 리더를 재설정하여 0을 오프셋하고 해당 청크를 다시 읽을 수 있기를 바랍니다.

불행히도 bufio.Reader은 (는) 검색을 지원하지 않습니다.

표준을 지원하는 독자가 있습니까? 아니면 내 독자적으로 구현해야합니까?

답변

4

bufio의 목적은 버퍼링 된 I/O를 제공하는 것입니다. 버퍼링 된 I/O는 시간 이동이 아닌 성능을위한 것입니다.

데이터를 바이트 조각으로 읽은 다음 bytes.Reader을 사용하여 추가로 처리 할 수 ​​있습니다.

+0

불행히도 내가 읽어야하는 파일은 청크로 읽히는 상대적으로 큰 다중 부분 파일이므로 그 이유는 모든 것을 메모리에로드해야하는'bytes.Reader'를 사용할 수 없기 때문입니다. 다음 사용자 지정 구현을 사용해야합니다. –

+0

@ErikAigner : 맞춤 구현을 어떻게 진행 했습니까? 필자는 비슷한 상황에 있으며, CSV 데이터의'io.Reader' 바이트 스트림을 들여다보고 나서 csv.NewReader()로 전달하기 전에 구분자를 감지해야합니다. – DanielSmedegaardBuus

0

오픈 도어를 찾고 나서 bufio.Reset()을 사용하여 궁금한 점이 궁금했는데 이상적은 아닙니다. 우선, bufio.Reset의 문서에 "버퍼링 된 데이터를 버리십시오"라고 쓰여 있지만 운영 체제에서도 최근에 읽은 파일 내용을 캐시하지 않습니다.

둘째, bufio가 지정된 파일 위치에서 읽기 및 버퍼링을 시작하지만 섹터 정렬은 고려하지 않기 때문에 시작 지점과 관계없이 한 번에 전체 버퍼를 버퍼링합니다. 따라서 버퍼 크기 (기본적으로 4096)가 파일 시스템의 클러스터 크기와 같다고 가정하고 시작 지점이 클러스터에 정렬되어 있지 않으면 bufio는 읽을 때마다 2 클러스터에서 읽습니다. 성능에 미치는 영향이 눈에 띄는 것은 아닙니다. 사실, 최대한 앞서서 읽음으로써, 나의 정렬 강박 관념이 산출 할 수있는 것보다 성능이 더 나을 수도 있습니다. (추구 후, 파일 위치는 4096의 배수에 반환하지 않는 것을 보여주는)

package main 

import (
    "bufio" 
    "crypto/md5" 
    "fmt" 
    "os" 
) 

func readBytes(r *bufio.Reader, block []byte) { 
    for i := 1; i < len(block); i++ { 
     var err error 
     block[i], err = r.ReadByte() 
     if err != nil { 
      panic(err) 
     } 
    } 
} 

func status(f *os.File, r *bufio.Reader, block []byte, what string) { 
    fpos, err := f.Seek(0, os.SEEK_CUR) 
    if err != nil { 
     panic(err) 
    } 
    fmt.Printf("%s: fpos=%5d, buffered=%4d, md5=%X\n", what, fpos, r.Buffered(), md5.Sum(block)) 
} 

func main() { 
    f, err := os.Open(os.Args[0]) 
    if err != nil { 
     panic(err) 
    } 
    defer func() { f.Close() }() 
    r := bufio.NewReader(f) 
    var block = make([]byte, 2000) 
    status(f, r, block, "initial") 
    readBytes(r, block) 
    status(f, r, block, "block 1") 
    readBytes(r, block) 
    status(f, r, block, "block 2") 
    readBytes(r, block) 
    status(f, r, block, "block 3") 
    f.Seek(2000, os.SEEK_SET) // return to start of buf1a 
    r.Reset(f) 
    readBytes(r, block) 
    status(f, r, block, "block 2") 
    readBytes(r, block) 
    status(f, r, block, "block 3") 
    readBytes(r, block) 
    status(f, r, block, "block 4") 
} 

전형적인 출력 :

이 코드는 실행 자체에서 몇 2,000 바이트 덩어리를 읽고,이 방법을 보여줍니다 생각

initial: fpos= 0, buffered= 0, md5=CF40A1DE3F93B4A025409B5EFA5AA210 
block 1: fpos= 4096, buffered=2096, md5=C7015DD984AB85CCCBD206BA8243647D 
block 2: fpos= 4096, buffered= 96, md5=E0D75F4A6DE681316515F5CD53F0D95C 
block 3: fpos= 8192, buffered=2192, md5=7961B1A889E9793344374B3022314CD0 
block 2: fpos= 6096, buffered=2096, md5=E0D75F4A6DE681316515F5CD53F0D95C 
block 3: fpos= 6096, buffered= 96, md5=7961B1A889E9793344374B3022314CD0 
block 4: fpos=10192, buffered=2192, md5=2A2F77C23EF4651E630855D9C3AA29DE 
관련 문제