doulangchao8934 2015-12-15 16:01
浏览 98
已采纳

如何使用go传输多个文件

I am trying to write a program in go which has two parts. One part is the client who tries to upload multiple pictures to the other part the server.

The server side should do the following:

  1. Get the number of files which will be send
  2. Loop for every file
  3. Get filename
  4. Get the file and save it
  5. Go to 3

So far the server side is doing the following:

func getFileFromClient(connection net.Conn) {
    var numberOfPics int
    var err error
    var receivedBytes int64
    var fileName string
    r := bufio.NewReader(connection)
    strNumberOfPics, err := r.ReadString('
')
    if err != nil {
        fmt.Printf("Error reading: %s
", err)
        return
    }
    fmt.Printf("Read: %s
", strNumberOfPics)
    strNumberOfPics = strings.Trim(strNumberOfPics, "
")
    numberOfPics, err = strconv.Atoi(strNumberOfPics)
    if err != nil {
        fmt.Printf("Error Atoi: %s
", err)
        panic("Atoi")
    }
    fmt.Printf("Receiving %d pics:
", numberOfPics)
    for i := 0; i < numberOfPics; i++ {
        // Getting the file name:
        fileName, err = r.ReadString('
')
        if err != nil {
            fmt.Printf("Error receiving: %s
", err)
        }
        fmt.Printf("Filename: %s
", fileName)
        fileName = strings.Trim(fileName, "
")
        f, err := os.Create(fileName)
        defer f.Close()
        if err != nil {
            fmt.Println("Error creating file")
        }
        receivedBytes, err = io.Copy(f, connection)
        if err != nil {
            panic("Transmission error")
        }

        fmt.Printf("Transmission finished. Received: %d 
", receivedBytes)
    }
}

io.Copy is working for just one file and nothing additional (because it does not empty the queue I think). I do not want to reconnect every time for every file if I do not have too. But I am not sure what I actually can do about that.

Has anyone any suggestions of an existing package or method which could help? Or example code? Or am I just plain wrong and it is a bad idea to even try this with go?

I think it might be enough if the server is able to flush the connection buffer after every read so no additional info is read and/or copied.

Really looking forward for help, thanks in advance

EDIT: Updated Code still not working. I think it might be the bufio.reader

func getFileFromClient(connection net.Conn) {
    var numberOfPics int
    var err error
    var receivedBytes int64
    var fileName string
    r := bufio.NewReader(connection)
    strNumberOfPics, err := r.ReadString('
')
    if err != nil {
        fmt.Printf("Error reading: %s
", err)
        return
    }
    strNumberOfPics = strings.Trim(strNumberOfPics, "
")
    numberOfPics, err = strconv.Atoi(strNumberOfPics)
    if err != nil {
        fmt.Printf("Error Atoi: %s
", err)
        panic("Atoi")
    }
    fmt.Printf("Receiving %d pics:
", numberOfPics)
    for i := 0; i < numberOfPics; i++ {
        // Getting the file name:
        fileName, err = r.ReadString('
')
        if err != nil {
            fmt.Printf("Error receiving: %s
", err)
        }
        fileName = strings.Trim(fileName, "
")
        fmt.Printf("Filename: %s
", fileName)
        f, err := os.Create(fileName)
        defer f.Close()
        if err != nil {
            fmt.Println("Error creating file")
        }
        // Get the file size
        strFileSize, err := r.ReadString('
')
        if err != nil {
            fmt.Printf("Read size error %s
", err)
            panic("Read size")
        }
        strFileSize = strings.Trim(strFileSize, "
")
        fileSize, err := strconv.Atoi(strFileSize)
        if err != nil {
            fmt.Printf("Error size Atoi: %s
", err)
            panic("size Atoi")
        }
        fmt.Printf("Size of pic: %d
", fileSize)

        receivedBytes, err = io.CopyN(f, connection, int64(fileSize))
        if err != nil {
            fmt.Printf("Transmission error: %s
", err)
            panic("Transmission error")
        }
        fmt.Printf("Transmission finished. Received: %d 
", receivedBytes)
    }
}

EDIT 2: I did not get this solution to work. I am pretty sure it is because I used bufio. I did however get it to work by transmitting a single zip file with io.copy. Another solution which worked was to transmit a zip file by using http. If you are stuck trying something similar and need help feel free to send me a message. Thanks to all of you for your help

  • 写回答

2条回答 默认 最新

  • duancan9815 2015-12-15 16:22
    关注

    Keeping your implementation so far, the thing you're missing is that io.Copy() reads from source until it finds an EOF, so it will read all the remaining images in one go.

    Also, the client must send, for each image, its size in bytes (you could do that after sending the name). In the server, just read the size and then use io.CopyN() to read that exact number of bytes.

    EDIT: as a matter of fact, you could also do things like you were doing and send images in parallel instead of serially, that would mean you open a new connection for each file transfer and then read all of the file withouth needing to send the amount of images or their size.

    In case you want an alternative, a good option would be using good 'ol HTTP and multipart requests. There's the built-in module mime/multipart that allows you to do file transfers over HTTP. Of course, that would mean you'd have to rewrite your program.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置