借助TCP完成文件的传输,基本思路如下:
- 发送方(客户端)向服务端发送文件名,服务端保存该文件名。
- 接收方(服务端)向客户端返回一个消息ok,确认文件名保存成功。
- 发送方(客户端)收到消息后,开始向服务端发送文件数据。
- 接收方(服务端)读取文件内容,写入到之前保存好的文件中。
首先获取文件名。借助os包中的stat()
函数来获取文件属性信息。在函数返回的文件属性中包含文件名和文件大小。Stat参数name传入的是文件访问的绝对路径。FileInfo中的Name()函数可以将文件名单独提取出来。
func Stat(name string) (FileInfo, error)
type FileInfo interface {Name() string Size() int64 Mode() FileMode ModTime() time.Time IsDir() bool Sys() interface{}
}
发送端:
package mainimport ("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}// 读取服务器回发的 OKbuf := make([]byte, 1024)n, err := conn.Read(buf)if err != nil {fmt.Println("conn.Read err:", err)return}if "ok" == string(buf[:n]) {// 写文件内容给服务器——借助connsendFile(conn, filePath)}
}
接收端:
package mainimport ("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() {// 创建用于监听的socketlistener, 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)
}