2015-03-28 14 views
6

Tôi có tệp phẳng có 339276 dòng văn bản trong đó có kích thước 62,1 MB. Tôi đang cố gắng để đọc trong tất cả các dòng, phân tích chúng dựa trên một số điều kiện tôi có và sau đó chèn chúng vào một cơ sở dữ liệu.Làm cách nào để đọc trong một tệp phẳng lớn ở Golang

Tôi đã cố gắng sử dụng vòng lặp bufio.Scan() và bufio.Text() để lấy dòng nhưng tôi đã hết dung lượng bộ nhớ đệm. Tôi chuyển sang sử dụng bufio.ReadLine/ReadString/ReadByte (Tôi đã thử từng) và có cùng một vấn đề với mỗi. Tôi không có đủ dung lượng bộ đệm.

Tôi đã thử sử dụng đọc và đặt kích thước bộ đệm nhưng tài liệu cho biết đó thực sự là một const có thể được tạo nhỏ hơn nhưng không bao giờ lớn hơn 64 * 1024 byte. Sau đó tôi đã cố gắng sử dụng File.ReadAt nơi tôi thiết lập các postilion bắt đầu và di chuyển nó cùng như tôi đã mang trong mỗi phần không có avail. Tôi đã xem xét các ví dụ sau và giải thích (không phải là một danh sách đầy đủ):

Read text file into string array (and write) How to Read last lines from a big file with Go every 10 secs reading file line by line in go

Làm thế nào để đọc toàn bộ tập tin (hoặc từng dòng hoặc toàn bộ điều cùng một lúc) vào một lát để tôi có thể làm mọi thứ với các dòng?

Dưới đây là một số mã mà tôi đã cố gắng:

    file, err := os.Open(feedFolder + value) 
       handleError(err) 
       defer file.Close() 
       //    fileInfo, _ := file.Stat() 
       var linesInFile []string 

      r := bufio.NewReader(file) 
      for { 
        path, err := r.ReadLine("\n") // 0x0A separator = newline 

        linesInFile = append(linesInFile, path) 
        if err == io.EOF { 
          fmt.Printf("End Of File: %s", err) 
          break 
        } else if err != nil { 
          handleError(err) // if you return error 
        } 
      } 
      fmt.Println("Last Line: ", linesInFile[len(linesInFile)-1]) 

Đây là cái gì khác tôi đã cố gắng:

var fileSize int64 = fileInfo.Size() 
    fmt.Printf("File Size: %d\t", fileSize) 
    var bufferSize int64 = 1024 * 60 
    bytes := make([]byte, bufferSize) 
    var fullFile []byte 
    var start int64 = 0 
    var interationCounter int64 = 1 
    var currentErr error = nil 
     for currentErr != io.EOF { 
      _, currentErr = file.ReadAt(bytes, st) 
      fullFile = append(fullFile, bytes...) 
      start = (bufferSize * interationCounter) + 1 
      interationCounter++ 
      } 
    fmt.Printf("Err: %s\n", currentErr) 
    fmt.Printf("fullFile Size: %s\n", len(fullFile)) 
    fmt.Printf("Start: %d", start) 

    var currentLine []string 


    for _, value := range fullFile { 
     if string(value) != "\n" { 
      currentLine = append(currentLine, string(value)) 
     } else { 
     singleLine := strings.Join(currentLine, "") 
     linesInFile = append(linesInFile, singleLine) 
     currentLine = nil 
       } 
     } 

Tôi đang ở một mất mát. Hoặc là tôi không hiểu chính xác bộ đệm hoạt động như thế nào hoặc tôi không hiểu cái gì khác. Cảm ơn vì đã đọc.

+3

Đừng đọc nó tất cả trong cùng một lúc . Hấp nó. Sử dụng 'bufio.Scanner' (vì bạn dường như chỉ ra nó dựa trên dòng), xử lý dòng, chèn vào db của bạn, * rồi quên dòng đó *. –

+0

Cảm ơn bạn đã phản hồi. Làm thế nào để quên dòng đó? Trong nỗ lực của tôi để sử dụng bufio.Scanner khi tôi nhấn dòng 63700 (gần) trong tập tin của tôi, tôi ngừng đọc trong dòng mới. Sự hiểu biết của tôi là vì tôi đã nhấn MaxScanTokenSize (http://golang.org/pkg/bufio/#pkg-constants) của máy quét.Tôi rất thích đọc dòng, phân tích nó, và vứt nó đi nhưng tôi không biết làm thế nào để ném nó đi một phần để máy quét tiếp tục di chuyển qua toàn bộ tập tin. – rvrtex

+0

@DaveC Hm ... Bộ đệm hấp. – fuz

Trả lời

5

bufio.Scan()bufio.Text() trong một vòng lặp hoàn toàn làm việc cho tôi vào một file với kích thước lớn hơn nhiều, vì vậy tôi giả sử bạn có dòng vượt quá khả năng đệm. Sau đó

  • kiểm tra đường dây của bạn kết thúc
  • và đó Go phiên bản bạn sử dụng path, err :=r.ReadLine("\n") // 0x0A separator = newline? Hình như func (b *bufio.Reader) ReadLine() (line []byte, isPrefix bool, err error) có giá trị trả về isPrefix đặc biệt đối với trường hợp sử dụng của bạn http://golang.org/pkg/bufio/#Reader.ReadLine
+1

Đây là cách chính xác để thực hiện việc này. Sau khi một số tái bao thanh toán để quên mỗi dòng đầu vào theo @ DaveC đề nghị và sử dụng '.Scan()' và '.Text()' Tôi chạy nó một lần nữa và có cùng một vấn đề. Sau đó tôi đã đi và nhìn vào tập tin tôi đã thực sự chạy chương trình của tôi chống lại và thấy tập tin là vấn đề. Chương trình đã làm chính xác những gì nó nên làm và tôi đã có các tập tin xấu ở phía máy chủ của tôi. Bài học kinh nghiệm, đôi khi nó không phải là chương trình xấu nhưng đầu vào xấu. Cảm ơn sự giúp đỡ của bạn, với nó tôi đã làm cho chương trình của tôi chạy hiệu quả hơn nhiều. – rvrtex

3

Không rõ ràng là cần phải đọc trong tất cả các dòng trước khi phân tích chúng và chèn chúng vào cơ sở dữ liệu. Cố gắng tránh điều đó.

Bạn có một tệp nhỏ: "tệp phẳng có 339276 dòng văn bản trong đó có kích thước 62,1 MB". Ví dụ,

package main 

import (
    "bytes" 
    "fmt" 
    "io" 
    "io/ioutil" 
) 

func readLines(filename string) ([]string, error) { 
    var lines []string 
    file, err := ioutil.ReadFile(filename) 
    if err != nil { 
     return lines, err 
    } 
    buf := bytes.NewBuffer(file) 
    for { 
     line, err := buf.ReadString('\n') 
     if len(line) == 0 { 
      if err != nil { 
       if err == io.EOF { 
        break 
       } 
       return lines, err 
      } 
     } 
     lines = append(lines, line) 
     if err != nil && err != io.EOF { 
      return lines, err 
     } 
    } 
    return lines, nil 
} 

func main() { 
    // a flat file that has 339276 lines of text in it for a size of 62.1 MB 
    filename := "flat.file" 
    lines, err := readLines(filename) 
    fmt.Println(len(lines)) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
} 
0

Dường như với tôi biến thể này readLines là ngắn hơn và nhanh hơn so với đề nghị peterSO

func readLines(filename string) (map[int]string, error) { 
    lines := make(map[int]string) 

    data, err := ioutil.ReadFile(filename) 
    if err != nil { 
     return nil, err 
    } 

    for n, line := range strings.Split(string(data), "\n") { 
     lines[n] = line 
    } 

    return lines, nil 
} 
Các vấn đề liên quan