将容器中的文件移动到一个具有挂载卷的文件夹中,使用Docker。

huangapple go评论114阅读模式
英文:

moving a file in a container to a folder that has a mounted volume docker

问题

我正在尝试在Docker上运行一个Go应用程序。但是当我尝试将容器中创建的文件移动到挂载卷所在的文件夹时,我遇到了一个错误:rename /mygo/newt /mygo/store/newt: invalid cross-device link。

以下是我的Go代码:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. )
  9. func main() {
  10. for {
  11. fmt.Println("是否要创建一个文件?输入 y 表示是,输入 n 表示否")
  12. var ans string
  13. fmt.Scanln(&ans)
  14. if ans == "y" {
  15. var userFile string
  16. fmt.Println("请输入文件名")
  17. fmt.Scanln(&userFile)
  18. myfile, err := os.Create(userFile)
  19. if err != nil {
  20. fmt.Printf("创建文件时发生错误:%v\n", err)
  21. return
  22. }
  23. fmt.Println("请输入要写入文件的文本")
  24. reader := bufio.NewReader(os.Stdin)
  25. input, err := reader.ReadString('\t')
  26. if err != nil {
  27. fmt.Println("读取输入时发生错误:", err)
  28. return
  29. }
  30. input = strings.TrimSuffix(input, "\t")
  31. num, err := myfile.WriteString(input)
  32. if err != nil {
  33. fmt.Println("写入文件时发生错误", err)
  34. }
  35. fmt.Printf("已输入 %v 个字符\n", num)
  36. defer myfile.Close()
  37. fmt.Println("已创建文件", userFile)
  38. fmt.Println("===========")
  39. fmt.Println("正在将文件移动到默认文件夹")
  40. pwd, err_pwd := os.Getwd()
  41. if err_pwd != nil {
  42. fmt.Printf("无法获取当前工作目录:%v\n", err_pwd)
  43. }
  44. userFilePath := pwd + "/" + userFile
  45. fmt.Println(pwd)
  46. destinationFilePath := pwd + "/store/" + userFile
  47. //destinationFilePath := pwd + "/default/" + userFile
  48. err_moving := os.Rename(userFilePath, destinationFilePath)
  49. if err_moving != nil {
  50. fmt.Printf("移动文件时发生错误:%v\n", err_moving)
  51. return
  52. }
  53. fmt.Println("文件已移动")
  54. continue
  55. }
  56. pwd, err_pwd := os.Getwd()
  57. if err_pwd != nil {
  58. fmt.Printf("无法获取当前工作目录:%v\n", err_pwd)
  59. }
  60. fmt.Println("请输入要移动到默认位置的完整路径")
  61. var userFilePath string
  62. fmt.Scanln(&userFilePath)
  63. userFileName := filepath.Base(userFilePath)
  64. destinationFilePath := pwd + "/" + userFileName
  65. err_move := os.Rename(userFilePath, destinationFilePath)
  66. if err_move != nil {
  67. fmt.Printf("移动文件时发生错误:%v", err_move)
  68. return
  69. }
  70. fmt.Println("文件已移动")
  71. continue
  72. }
  73. }

Dockerfile如下:

  1. FROM golang
  2. WORKDIR /mygo
  3. COPY . .
  4. RUN go build -o app
  5. CMD ["./app"]

在错误后,程序退出运行。

你可以参考这个链接来运行容器。

英文:

am trying to run a golang application on docker. But when i try to move created file in the container to the folder the created volume is mounted on,i get an error
:rename /mygo/newt /mygo/store/newt: invalid cross-device link

>>my golang code

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. )
  9. func main() {
  10. for {
  11. fmt.Println("do you want to create a file,y for yes, n for no")
  12. var ans string
  13. fmt.Scanln(&ans)
  14. if ans == "y" {
  15. var userFile string
  16. fmt.Println("enter name of file")
  17. fmt.Scanln(&userFile)
  18. myfile, err := os.Create(userFile)
  19. if err != nil {
  20. fmt.Printf("error creating file::%v\n", err)
  21. return
  22. }
  23. fmt.Println("enter text to write in file")
  24. reader := bufio.NewReader(os.Stdin)
  25. input, err := reader.ReadString('\t')
  26. if err != nil {
  27. fmt.Println("an error occured while reading::", err)
  28. return
  29. }
  30. input = strings.TrimSuffix(input, "\t")
  31. num, err := myfile.WriteString(input)
  32. if err != nil {
  33. fmt.Println("error while writing to file", err)
  34. }
  35. fmt.Printf("%v characters entered \n", num)
  36. defer myfile.Close()
  37. fmt.Println("created a file", userFile)
  38. fmt.Println("===========")
  39. fmt.Println("moving file to default folder")
  40. pwd, err_pwd := os.Getwd()
  41. if err_pwd != nil {
  42. fmt.Printf("could not get current working directory::%v\n", err_pwd)
  43. }
  44. userFilePath := pwd + "/" + userFile
  45. fmt.Println(pwd)
  46. destinationFilePath := pwd + "/store/" + userFile
  47. //destinationFilePath := pwd + "/default/" + userFile
  48. err_moving := os.Rename(userFilePath, destinationFilePath)
  49. if err_moving != nil {
  50. fmt.Printf("Error occured while moving file::%v\n", err_moving)
  51. return
  52. }
  53. fmt.Println("file moved")
  54. continue
  55. }
  56. pwd, err_pwd := os.Getwd()
  57. if err_pwd != nil {
  58. fmt.Printf("could not get current working directory::%v\n", err_pwd)
  59. }
  60. fmt.Println("enter full path to move to default location")
  61. var userFilePath string
  62. fmt.Scanln(&userFilePath)
  63. userFileName := filepath.Base(userFilePath)
  64. destinationFilePath := pwd + "/" + userFileName
  65. err_move := os.Rename(userFilePath, destinationFilePath)
  66. if err_move != nil {
  67. fmt.Printf("error occured while moving file:::%v", err_move)
  68. return
  69. }
  70. fmt.Println("file moved")
  71. continue
  72. }
  73. }

>>dockerfile

  1. FROM golang
  2. WORKDIR /mygo
  3. COPY . .
  4. RUN go build -o app
  5. CMD ["./app"]

running the container

the program exits after the error

答案1

得分: 0

在Linux中,有两种方法可以“重命名”文件。

  1. 将目录项移动到新位置,但保持文件内容不变。

    这种方法的优点是速度快。缺点是当将文件从一个文件系统移动到另一个文件系统时无法使用。

  2. 创建一个新文件,将数据复制到新文件中,然后删除旧文件。

    但是,如果源文件和目标文件位于两个不同的文件系统上,这种方法是可行的。

在这种情况下,方法1无法使用。你需要使用方法2。

更多资源:

  • 这个golang-dev讨论解释了为什么会出现这种情况。
  • 这个问题讨论了相同的问题,但是在C++的上下文中。
  • Go在内部使用renameat()系统调用。这个手册页面解释了它的工作原理。你遇到的具体错误是EXDEV错误:“oldpath和newpath不在同一个挂载的文件系统上。(Linux允许一个文件系统在多个点上挂载,但是即使相同的文件系统在两个点上都挂载了,rename()也不能在不同的挂载点之间工作。)”
英文:

There are two ways to "rename" a file in Linux.

  1. Move the directory entry to a new place, but keep the file contents unchanged.

    This has the advantage of being fast. It has the disadvantage that it doesn't work when moving a file from one filesystem to another.

  2. Create a new file, copy the data to the new file, and delete the old file.

    However, it will work if the source and destination are on two different filesystems.

Method #1 will not work in this case. You need method #2.

More resources:

  • This golang-dev discussion explains why this happens.
  • This question talks about the same problem, but in the context of C++.
  • Go uses the renameat() syscall internally. This manual page explains how it works. The specific error you're encountering is the EXDEV error: "oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points, but rename() does not work across different mount points, even if the same filesystem is mounted on both.)"

huangapple
  • 本文由 发表于 2022年10月7日 09:33:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/73981482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定