Golang中unix.Splice引用问题解决方案(Mac平台)

Golang中unix.Splice引用问题解决方案(Mac平台) 大家好,

我正在尝试使用 [https://github.com/mkevac/goduplicator](https://github.com/mkevac/goduplicator) 但遇到了错误。

# github.com/mkevac/goduplicator
./main.go:91:12: undefined: unix.Splice
./main.go:96:12: undefined: unix.Splice
./main.go:156:14: undefined: unix.Splice
./main.go:169:12: undefined: unix.Splice
./main.go:182:17: undefined: unix.Tee
./main.go:194:12: undefined: unix.Splice

我的 go 环境

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/myuser/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/myuser/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/d7/r0r3h23974j593016t5snysjp001nc/T/go-build860538255=/tmp/go-build -gno-record-gcc-switches -fno-common"

我的 Go 版本 go version go1.12.5 darwin/amd64

我不知道为什么会发生这种情况。


更多关于Golang中unix.Splice引用问题解决方案(Mac平台)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

因为 Darwin 似乎没有实现这些功能。

更多关于Golang中unix.Splice引用问题解决方案(Mac平台)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Mac平台上,unix.Spliceunix.Tee函数不可用,因为macOS系统调用不支持这些功能。这些函数只在Linux平台上可用。

解决方案是使用平台特定的条件编译,或者使用其他方法实现相同的功能。以下是几种解决方案:

方案1:使用条件编译

创建两个文件,一个用于Linux,一个用于其他平台:

splice_linux.go

// +build linux

package main

import "golang.org/x/sys/unix"

func splice(srcFD int, dstFD int, len int) (int, error) {
    return unix.Splice(srcFD, nil, dstFD, nil, len, 0)
}

func tee(srcFD int, dstFD int, len int) (int, error) {
    return unix.Tee(srcFD, dstFD, len, 0)
}

splice_other.go

// +build !linux

package main

import "io"

func splice(srcFD int, dstFD int, len int) (int, error) {
    // 使用io.CopyBuffer作为替代方案
    buffer := make([]byte, len)
    n, err := io.ReadAtLeast(io.NewSectionReader(&fileReader{fd: srcFD}, 0, 1<<63-1), buffer, len)
    if err != nil && err != io.EOF {
        return 0, err
    }
    
    written, err := io.Writer(&fileWriter{fd: dstFD}).Write(buffer[:n])
    if err != nil {
        return 0, err
    }
    return written, nil
}

func tee(srcFD int, dstFD int, len int) (int, error) {
    // 在非Linux平台上,Tee功能需要手动实现
    buffer := make([]byte, len)
    n, err := io.ReadAtLeast(io.NewSectionReader(&fileReader{fd: srcFD}, 0, 1<<63-1), buffer, len)
    if err != nil && err != io.EOF {
        return 0, err
    }
    
    // 这里需要同时写入两个目标,但原文件位置需要保持不变
    // 这需要更复杂的实现
    return n, nil
}

type fileReader struct {
    fd int
}

func (fr *fileReader) Read(p []byte) (int, error) {
    // 使用系统调用实现读取
    return unix.Read(fr.fd, p)
}

type fileWriter struct {
    fd int
}

func (fw *fileWriter) Write(p []byte) (int, error) {
    // 使用系统调用实现写入
    return unix.Write(fw.fd, p)
}

方案2:使用io.Copy替代

对于简单的文件复制,可以使用标准库的io.Copy

package main

import (
    "io"
    "os"
)

func copyFile(src, dst string) error {
    srcFile, err := os.Open(src)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    dstFile, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer dstFile.Close()

    _, err = io.Copy(dstFile, srcFile)
    return err
}

方案3:使用bufio进行缓冲复制

package main

import (
    "bufio"
    "os"
)

func bufferedCopy(src, dst string) error {
    srcFile, err := os.Open(src)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    dstFile, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer dstFile.Close()

    reader := bufio.NewReader(srcFile)
    writer := bufio.NewWriter(dstFile)
    
    buffer := make([]byte, 32*1024) // 32KB buffer
    
    for {
        n, err := reader.Read(buffer)
        if n > 0 {
            _, writeErr := writer.Write(buffer[:n])
            if writeErr != nil {
                return writeErr
            }
        }
        if err != nil {
            if err.Error() == "EOF" {
                break
            }
            return err
        }
    }
    
    return writer.Flush()
}

主要原因是macOS的Darwin内核不支持splicetee系统调用,这些是Linux特有的零拷贝技术。在Mac平台上需要使用传统的文件I/O方法来实现相同的功能。

回到顶部