英文:
How to create a 10MB file filled with "000000..." data in golang?
问题
我打算在类似日志或磁盘队列的系统中使用fdatasync。
首先要在类似ext4的文件系统中创建一个包含"000000..."的10MB文件。
但是我不知道如何正确地做到这一点。
英文:
I am intended to use fdatasync in a system like log or diskqueue.
The first thing is to create a 10MB file with "000000..." in file system like ext4.
But I don't know how to do it properly.
答案1
得分: 17
jnml@fsc-r630:~/src/tmp/SO/16797380$ ls -l
总计 4
-rw-rw-r-- 1 jnml jnml 186 5月 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
总计 4
-rw-rw-r-- 1 jnml jnml 10000000 5月 29 07:55 foo.bar
-rw-rw-r-- 1 jnml jnml 186 5月 29 07:54 main.go
jnml@fsc-r630:~/src/tmp/SO/16797380$
英文:
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$
答案2
得分: 5
如果您使用的是Unix系统,那么您可以非常快速地创建一个稀疏文件。稀疏文件填充了零(ASCII NUL),直到写入数据之前实际上不占用磁盘空间,但读取是正确的。
生成一个名为output
的10MB文件。
$ ls -l output
-rw-r--r-- 1 user user 10485760 May 28 18:58 output
$ du -hs output
4.0K output
更新 很久以后
我在rclone中解决了这个问题。即在不写入数据或创建稀疏文件的情况下预分配文件。您无法直接使用标准库进行操作,而且它也不是跨平台的,但是在Linux中使用fallocate系统调用和FALLOC_FL_KEEP_SIZE
标志是正确的方法。在Windows中也可以这样做。
这里是相关代码的链接:Windows和Linux,这是Linux代码:
var (
fallocFlags = [...]uint32{
unix.FALLOC_FL_KEEP_SIZE, // 默认
unix.FALLOC_FL_KEEP_SIZE | unix.FALLOC_FL_PUNCH_HOLE, // 用于ZFS #3066
}
fallocFlagsIndex int32
)
// 为了性能原因预分配文件
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
}
flags := fallocFlags[index]
err := unix.Fallocate(int(out.Fd()), flags, 0, size)
if err == unix.ENOTSUP {
// 尝试下一个标志组合
index++
atomic.StoreInt32(&fallocFlagsIndex, index)
fs.Debugf(nil, "preAllocate: 在fallocate上遇到错误,尝试组合 %d/%d: %v", index, len(fallocFlags), err)
goto again
}
// FIXME 可能需要在这里做一些处理
// if err == unix.ENOSPC {
// log.Printf("No space")
// }
return err
}
英文:
If you are using unix, then you can create a sparse file very quickly. A sparse file is filled with zero (ascii NUL) and doesn't actually take up the disk space until it is written to, but reads correctly.
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")
}
}
Which produces a 10MB file called output
.
$ ls -l output
-rw-r--r-- 1 user user 10485760 May 28 18:58 output
$ du -hs output
4.0K output
Update much later
I solved exactly this problem in rclone. Namely preallocating files without writing the data, or creating a sparse file. You can't do it directly from the standard library and it isn't cross platform, but using the fallocate syscall with the FALLOC_FL_KEEP_SIZE
flag is the way to go in linux. You can also do this in windows.
Here are links to the relevant code in windows and linux and here is the linux code:
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
}
答案3
得分: 0
尝试这个:
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])
}
英文:
Try this:
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])
}
答案4
得分: -2
这将在当前目录中创建一个名为testfile
的10000000字节文件。
package main
import (
"fmt"
"os"
)
func main() {
data := make([]byte, int(1e7), int(1e7)) // 初始化一个空的字节切片
f, err := os.Create("testfile")
if err != nil {
fmt.Printf("错误:%s", err)
}
defer f.Close()
size, err := f.Write(data) // 将其写入文件
if err != nil {
fmt.Printf("错误:%s", err)
}
fmt.Printf("%d 字节已写入", size)
}
希望对你有所帮助。
英文:
This will create a 10000000 byte file in the current directory named testfile
.
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)
}
Hope that helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论