借助TCP完成文件的传输,基本思路如下:

  1. 发送方(客户端)向服务端发送文件名,服务端保存该文件名。
  2. 接收方(服务端)向客户端返回一个消息ok,确认文件名保存成功。
  3. 发送方(客户端)收到消息后,开始向服务端发送文件数据。
  4. 接收方(服务端)读取文件内容,写入到之前保存好的文件中。
os包中的stat()
func Stat(name string) (FileInfo, error) 
type FileInfo interface {
   Name() string       
   Size() int64        
   Mode() FileMode     
   ModTime() time.Time 
   IsDir() bool        
   Sys() interface{}   
}
发送端:
package main

import (
	"fmt"
	"io"
	"net"
	"os"
)

func sendFile(conn net.Conn, filePath string) {
	// 只读打开文件
	f, err := os.Open(filePath)
	if err != nil {
		fmt.Println("os.Open err:", err)
		return
	}
	defer f.Close()

	// 从本文件中,读数据,写给网络接收端。 读多少,写多少。原封不动。
	buf := make([]byte, 1024)
	for {
		n, err := f.Read(buf)
		if err != nil {
			if err == io.EOF {
				fmt.Println("发送文件完成。")
			} else {
				fmt.Println("os.Open err:", err)
			}
			return
		}
		// 写到网络socket中
		_, err = conn.Write(buf[:n])
		if err != nil {
			fmt.Println("conn.Write err:", err)
			return
		}
	}
}

func main() {
	list := os.Args // 获取命令行参数

	if len(list) != 2 {
		fmt.Println("格式为:go run xxx.go 文件绝对路径")
		return
	}
	// 提取 文件的绝对路径
	filePath := list[1]

	//提取文件名
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		fmt.Println("os.Stat err:", err)
		return
	}
	fileName := fileInfo.Name()

	// 主动发起连接请求
	conn, err := net.Dial("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println("net.Dial err:", err)
		return
	}
	defer conn.Close()

	// 发送文件名给 接收端
	_, err = conn.Write([]byte(fileName))
	if err != nil {
		fmt.Println("conn.Write err:", err)
		return
	}
	// 读取服务器回发的 OK
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println("conn.Read err:", err)
		return
	}

	if "ok" == string(buf[:n]) {
		// 写文件内容给服务器——借助conn
		sendFile(conn, filePath)
	}
}
接收端:
package main

import (
	"fmt"
	"net"
	"os"
)

func recvFile(conn net.Conn, fileName string) {
	// 按照文件名创建新文件
	f, err := os.Create(fileName)
	if err != nil {
		fmt.Println("os.Create err:", err)
		return
	}
	defer f.Close()

	// 从 网络中读数据,写入本地文件
	buf := make([]byte, 1024)
	for {
		n, _ := conn.Read(buf)
		if n == 0 {
			fmt.Println("接收文件完成。")
			return
		}
		// 写入本地文件,读多少,写多少。
		f.Write(buf[:n])
	}
}

func main() {
	// 创建用于监听的socket
	listener, err := net.Listen("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println(" net.Listen err:", err)
		return
	}
	defer listener.Close()

	fmt.Println("接收端启动成功,等待发送端发送文件!")

	// 阻塞监听
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println(" listener.Accept() err:", err)
		return
	}
	defer conn.Close()

	// 获取文件名,保存
	buf := make([]byte, 1024)
	n, err := conn.Read(buf)
	if err != nil {
		fmt.Println(" conn.Read err:", err)
		return
	}
	fileName := string(buf[:n])

	// 回写 ok 给发送端
	conn.Write([]byte("ok"))

	// 获取文件内容
	recvFile(conn, fileName)
}