Чтение в строках в текстовом файле, сортировка, затем перезапись файла - PullRequest
6 голосов
/ 15 сентября 2011

Я пытаюсь написать функцию go, которая будет читать строки в текстовом файле, сортировать их (в алфавитном порядке) и перезаписывать их обратно в файл.Прямо сейчас я могу эмулировать cat, но не могу манипулировать содержимым элементов в read_line.

func sort() {

    ff, _ := os.OpenFile(file, os.O_RDWR, 0666)
    f := bufio.NewReader(ff)
    for {
        read_line, _ := f.ReadString('\n')
        fmt.Print(read_line)
        if read_line == "" {
            break
        }
    }
    ff.Close()
}

Когда я использую ReadString, как я могу сохранить каждую строку в срез (или есть лучший способ сохранить их, чтобы я мог манипулировать ими)?Тогда я бы использовал пакет сортировки способом, подобным этому:

sorted := sort.Strings(lines) 

, затем, чтобы записать в файл, я использую что-то похожее на следующее, хотя я не включил его, потому что япока что получил "сортировку" на работу:

io.WriteString(ff, (lines + "\n"))

Заранее благодарен за любые предложения!

Ответы [ 4 ]

4 голосов
/ 15 сентября 2011

Например,

package main

import (
    "bufio"
    "fmt"
    "os"
    "sort"
)

func readLines(file string) (lines []string, err os.Error) {
    f, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    defer f.Close()
    r := bufio.NewReader(f)
    for {
        const delim = '\n'
        line, err := r.ReadString(delim)
        if err == nil || len(line) > 0 {
            if err != nil {
                line += string(delim)
            }
            lines = append(lines, line)
        }
        if err != nil {
            if err == os.EOF {
                break
            }
            return nil, err
        }
    }
    return lines, nil
}

func writeLines(file string, lines []string) (err os.Error) {
    f, err := os.Create(file)
    if err != nil {
        return err
    }
    defer f.Close()
    w := bufio.NewWriter(f)
    defer w.Flush()
    for _, line := range lines {
        _, err := w.WriteString(line)
        if err != nil {
            return err
        }
    }
    return nil
}

func main() {
    file := `lines.txt`
    lines, err := readLines(file)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    sort.Strings(lines)
    err = writeLines(file, lines)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}
1 голос
/ 15 сентября 2011

, так как вы собираетесь сортировать строки, вам нужно прочитать весь файл.вы можете либо сделать файл с помощью io/ioutil.ReadAll, либо просто написать небольшую функцию.когда у вас есть строки файла, их сортировка может быть выполнена с помощью вызова sort.Strings.Я добавлю, возможно, слишком многословную версию, которая, надеюсь, иллюстрирует, как это можно сделать.Я также рекомендую прочитать это превосходное объяснение того, как работает пакет сортировки go: Пакет сортировки Go

package main

import (
    "os"
    "bufio"
    "fmt"
    "sort"
)

// slurp file into slice of lines/strings
func slurp(f string) (lines []string, e os.Error) {

    var fd *os.File
    var line string
    var bufRd *bufio.Reader
    var keepReading bool = true

    fd, e = os.Open(f)

    if e != nil {
        return nil, e
    }

    defer fd.Close()

    bufRd = bufio.NewReader(fd)

    for keepReading {
        line, e = bufRd.ReadString('\n')
        switch e {
        case nil:
            lines = append(lines, line)
        case os.EOF:
            lines = append(lines, line)
            keepReading = false
        default:
            return lines, e
        }
    }

    return lines, nil
}

// test stuff out..
func main() {

    if len(os.Args) > 1 {

        lines, e := slurp(os.Args[1])

        if e != nil {
            fmt.Fprintf(os.Stderr,"%s\n", e)
            os.Exit(1)
        }

        fmt.Println("\n----- unsorted -----\n")

        for _, line := range lines {
            fmt.Printf("%s", line)
        }

        fmt.Println("\n----- sorted -----\n")

        sort.Strings(lines)

        for _, line := range lines {
            fmt.Printf("%s", line)
        }
    }
}

обратите внимание, что сортировка на месте, поэтому она ничего не возвращает

0 голосов
/ 26 мая 2015

Просто интересно, насколько удобно использовать Unix sort для этой цели.Я знаю, что этот код не работает во многих сценариях развертывания, но я считаю, что стоит упомянуть в качестве опции:

package main

import (
    "os"
    "os/exec"
)

func main() {
    file := "file.txt"

    command := []string{"sort", file, "-o", file}

    cmd := exec.Command(command[0], command[1:]...)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr

    if err := cmd.Run(); err != nil {
        panic(err)
    }
}

Мысли?

0 голосов
/ 26 сентября 2014

Это довольно простой способ сделать это.

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

// allow [][]byte to implement the sort.Interface interface
type lexicographically [][]byte

// bytes.Compare compares the byte slices lexicographically (alphabetically)
func (l lexicographically) Less(i, j int) bool { return bytes.Compare(l[i], l[j]) < 0 }
func (l lexicographically) Len() int           { return len(l) }
func (l lexicographically) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }

func SortFile(name string) error {
    content, err := ioutil.ReadFile(name)
    if err != nil {
        return err
    }

    lines := bytes.Split(content, []byte{'\n'})
    sort.Sort(lexicographically(lines))

    content = bytes.Join(lines, []byte{'\n'})
    return ioutil.WriteFile(name, content, 0644)
}
...