如何在 golang 中创建一个充满"000000..."数据的 10MB 文件?



我打算在log或diskqueue这样的系统中使用fdatasync。第一件事是在ext4这样的文件系统中创建一个带有"000000…"的10MB文件。但是我不知道怎么做才合适。

jnml@fsc-r630:~/src/tmp/SO/16797380$ ls -l
celkem 4
-rw-rw-r-- 1 jnml jnml 186 kvě 29 07:54 main.go
jnml@fsc-r630:~/src/tmp/SO/16797380$ cat main.go 
package main
import (
        "log"
        "os"
)
func main() {
        f, err := os.Create("foo.bar")
        if err != nil {
                log.Fatal(err)
        }
        if err := f.Truncate(1e7); err != nil {
                log.Fatal(err)
        }
}
jnml@fsc-r630:~/src/tmp/SO/16797380$ go run main.go 
jnml@fsc-r630:~/src/tmp/SO/16797380$ ls -l
celkem 4
-rw-rw-r-- 1 jnml jnml 10000000 kvě 29 07:55 foo.bar
-rw-rw-r-- 1 jnml jnml      186 kvě 29 07:54 main.go
jnml@fsc-r630:~/src/tmp/SO/16797380$ 

如果您使用的是unix,那么您可以非常快速地创建一个稀疏文件。稀疏文件用零(ascii NUL)填充,并且在写入之前实际上不占用磁盘空间,但读取正确。

package main
import (
    "log"
    "os"
)
func main() {
    size := int64(10 * 1024 * 1024)
    fd, err := os.Create("output")
    if err != nil {
        log.Fatal("Failed to create output")
    }
    _, err = fd.Seek(size-1, 0)
    if err != nil {
        log.Fatal("Failed to seek")
    }
    _, err = fd.Write([]byte{0})
    if err != nil {
        log.Fatal("Write failed")
    }
    err = fd.Close()
    if err != nil {
        log.Fatal("Failed to close file")
    }
}

生成一个10MB的文件output

$ ls -l output 
-rw-r--r-- 1 user user 10485760 May 28 18:58 output
$ du -hs output 
4.0K    output

稍后更新

我完全解决了这个问题。即在不写入数据或创建稀疏文件的情况下预分配文件。您不能直接从标准库中执行此操作,而且它不是跨平台的,但是在linux中使用带有FALLOC_FL_KEEP_SIZE标志的fallocate系统调用是可行的。您也可以在windows中这样做。

下面是windows和linux的相关代码链接,下面是linux的代码:

var (
    fallocFlags = [...]uint32{
        unix.FALLOC_FL_KEEP_SIZE,                             // Default
        unix.FALLOC_FL_KEEP_SIZE | unix.FALLOC_FL_PUNCH_HOLE, // for ZFS #3066
    }
    fallocFlagsIndex int32
)
// preAllocate the file for performance reasons
func preAllocate(size int64, out *os.File) error {
    if size <= 0 {
        return nil
    }
    index := atomic.LoadInt32(&fallocFlagsIndex)
again:
    if index >= int32(len(fallocFlags)) {
        return nil // Fallocate is disabled
    }
    flags := fallocFlags[index]
    err := unix.Fallocate(int(out.Fd()), flags, 0, size)
    if err == unix.ENOTSUP {
        // Try the next flags combination
        index++
        atomic.StoreInt32(&fallocFlagsIndex, index)
        fs.Debugf(nil, "preAllocate: got error on fallocate, trying combination %d/%d: %v", index, len(fallocFlags), err)
        goto again
    }
    // FIXME could be doing something here
    // if err == unix.ENOSPC {
    //  log.Printf("No space")
    // }
    return err
}

试试这个:

package foo
import "io"
func WriteBytes(w io.Writer, c byte, n uint) {
    buf := make([]byte,0x1000)
    for i := 0 ; i < len(buf) ; i++ {
        buf[i] = c
    }
    for i := 0 ; i < n >> 24 ; i++ {
        w.Write(buf)
    }
    w.Write(buf[:n & 0xfff])
}

这将在当前目录下创建一个名为testfile的10000000字节文件。

package main
import (
    "fmt"
    "os"
)
func main() {
    data := make([]byte, int(1e7), int(1e7)) // Initialize an empty byte slice
    f, err := os.Create("testfile")
    if err != nil {
        fmt.Printf("Error: %s", err)
    }
    defer f.Close()
    size, err := f.Write(data) // Write it to the file
    if err != nil {
        fmt.Printf("Error: %s", err)
    }
    fmt.Printf("%d bytes written", size)
}

希望对你有帮助。

最新更新