mongodb保存文件的时候不能识别一样的文件

pj199 2014-08-13 04:00:53
RT;写了个小代码用来保存文件到mongodb中,但是当我再次运行的时候发现数据库里有两条一样的记录
package main

import (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"io"
"os"
)

func check(err error) {
if err != nil {
return
}
}
func main() {
f, err := os.Open("D:/test.txt")
check(err)
defer f.Close()

session, err := mgo.Dial("127.0.0.1")
if err != nil {
panic(err)
}
defer session.Close()
db := session.DB("filedb")
file, err := db.GridFS("fs").Create("test.txt")
io.Copy(file, f)
err = file.Close()
check(err)
file1, err := db.GridFS("fs").Open("test.txt")
io.Copy(os.Stdout, file1)
err = file1.Close()
fmt.Println(file1.Id())
fmt.Println(file1.UploadDate())
fmt.Println(file1.Size())


}
我的代码求指点
...全文
246 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
pj199 2014-08-15
  • 打赏
  • 举报
回复
又考虑到,删除以后建立新文件不安全。改
引用 9 楼 svenwang 的回复:
[quote=引用 8 楼 u012905769 的回复:] [quote=引用 6 楼 svenwang 的回复:] [quote=引用 4 楼 u012905769 的回复:] [quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] io.Copy放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
[/quote] dst, err = db.GridFS("fs").Open("test.txt")过后好像不可以_, err = io.Copy(dst, src),显示panic: GridFile is open for reading,我看文档里也只是read操作,
file, err := db.GridFS("fs").Open("myfile.txt")
check(err)
b := make([]byte, 8192)
n, err := file.Read(b)
check(err)
fmt.Println(string(b))
check(err)
err = file.Close()
check(err)
fmt.Printf("%d bytes read\n", n)
没有说可以覆盖掉原文件的操作,我想是不是如果打开的时候存在就删除重新建个最新的[/quote] 确实是Open的文件是只读的,不能再io.Copy。感觉这里API设计的有些问题,既然是只读的,为什么还有提供Write函数呢。 如果存在就删除再新建文件的思路应该是可行的。 [/quote] 看文档的时候每次看到gridfs里面的setname函数就感觉是个鸡肋,突然想起来昨天写的删除文件建立新文件这样不安全,如果建立新文件失败了,原文件已经被删了,应该先建立文件然后再删除,先建立的文件肯定不能同名,所以删除后再把这个文件改名

package main
import (
	"fmt"
	"gopkg.in/mgo.v2"
	"io"
	"os"
	//"gopkg.in/mgo.v2/bson"
)
func check(err error) {
	if err != nil {
		panic(err)
	}
}
func main() {
	src, err := os.Open("D:/mongodb/data/db/test.txt")
	if err != nil {
		fmt.Printf("打开本地文件错误\n")
	}
	defer src.Close()
	session, err := mgo.Dial("127.0.0.1")
	if err != nil {
		fmt.Printf("链接数据库错误\n")
	}
	defer session.Close()
	db := session.DB("filedb")
	dst, err := db.GridFS("fs").Open("test.txt")
	if err != nil {
		fmt.Printf("要打开的文件不存在\n")
		if err != mgo.ErrNotFound {
			fmt.Printf("mgo错误\n")
		}
		// create the file when failing to open it
		dst, err = db.GridFS("fs").Create("test.txt")
		_, err = io.Copy(dst, src)
		if err != nil {
			fmt.Printf("创建文件错误\n")
		}
		//defer dst.Close()
	} else {
		fmt.Printf("要打开的文件存在,重新建立,删除原有的文件\n")
		dst, err = db.GridFS("fs").Create("test.txt.dat")
		fmt.Printf("创立新文件test.txt.dat\n")
		_, err = io.Copy(dst, src)
		if err != nil {
			fmt.Printf("创建文件错误\n")
		}
		err = db.GridFS("fs").Remove("test.txt")
		if err != nil {
			fmt.Printf("删除文件错误\n")
		}
		dst.SetName("test.txt")
		fmt.Printf("创建新文件test.txt\n")
	}
	defer dst.Close()
}
}
pj199 2014-08-14
  • 打赏
  • 举报
回复
引用 9 楼 svenwang 的回复:
[quote=引用 8 楼 u012905769 的回复:] [quote=引用 6 楼 svenwang 的回复:] [quote=引用 4 楼 u012905769 的回复:] [quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] io.Copy放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
[/quote] dst, err = db.GridFS("fs").Open("test.txt")过后好像不可以_, err = io.Copy(dst, src),显示panic: GridFile is open for reading,我看文档里也只是read操作,
file, err := db.GridFS("fs").Open("myfile.txt")
check(err)
b := make([]byte, 8192)
n, err := file.Read(b)
check(err)
fmt.Println(string(b))
check(err)
err = file.Close()
check(err)
fmt.Printf("%d bytes read\n", n)
没有说可以覆盖掉原文件的操作,我想是不是如果打开的时候存在就删除重新建个最新的[/quote] 确实是Open的文件是只读的,不能再io.Copy。感觉这里API设计的有些问题,既然是只读的,为什么还有提供Write函数呢。 如果存在就删除再新建文件的思路应该是可行的。 [/quote] 唉,write函数writes the provided data to the file在GridFiles好鸡肋啊,先按照删除在新建吧,还有一个星期交工,要整合的太多了,时间太紧了
svenwang 2014-08-14
  • 打赏
  • 举报
回复
引用 8 楼 u012905769 的回复:
[quote=引用 6 楼 svenwang 的回复:] [quote=引用 4 楼 u012905769 的回复:] [quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] io.Copy放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
[/quote] dst, err = db.GridFS("fs").Open("test.txt")过后好像不可以_, err = io.Copy(dst, src),显示panic: GridFile is open for reading,我看文档里也只是read操作,
file, err := db.GridFS("fs").Open("myfile.txt")
check(err)
b := make([]byte, 8192)
n, err := file.Read(b)
check(err)
fmt.Println(string(b))
check(err)
err = file.Close()
check(err)
fmt.Printf("%d bytes read\n", n)
没有说可以覆盖掉原文件的操作,我想是不是如果打开的时候存在就删除重新建个最新的[/quote] 确实是Open的文件是只读的,不能再io.Copy。感觉这里API设计的有些问题,既然是只读的,为什么还有提供Write函数呢。 如果存在就删除再新建文件的思路应该是可行的。
pj199 2014-08-14
  • 打赏
  • 举报
回复
引用 6 楼 svenwang 的回复:
[quote=引用 4 楼 u012905769 的回复:] [quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] io.Copy放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
[/quote] dst, err = db.GridFS("fs").Open("test.txt")过后好像不可以_, err = io.Copy(dst, src),显示panic: GridFile is open for reading,我看文档里也只是read操作,
file, err := db.GridFS("fs").Open("myfile.txt")
check(err)
b := make([]byte, 8192)
n, err := file.Read(b)
check(err)
fmt.Println(string(b))
check(err)
err = file.Close()
check(err)
fmt.Printf("%d bytes read\n", n)
没有说可以覆盖掉原文件的操作,我想是不是如果打开的时候存在就删除重新建个最新的
pj199 2014-08-14
  • 打赏
  • 举报
回复
引用 6 楼 svenwang 的回复:
[quote=引用 4 楼 u012905769 的回复:] [quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] 放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
[/quote] 谢谢了,我这个本地的文件实际运行的时候是没有的,远程客户端上传文件到mongodb,然后我从mongodb里面取文件,所以才不用的io.Copy,我没说清楚,这个是我单拿出来测试下的
svenwang 2014-08-13
  • 打赏
  • 举报
回复
引用 4 楼 u012905769 的回复:
[quote=引用 1 楼 svenwang 的回复:] 你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试[/quote] io.Copy放在if外,这样就可以把本地的文件复制到打开或新建的mgo中的文件。难道你的需求不是这样?那可能是我理解错了。 不过if里的赋值语句我多写了一个":",应该是

dst, err = db.GridFS("fs").Create("test.txt")
pj199 2014-08-13
  • 打赏
  • 举报
回复
引用 2 楼 svenwang 的回复:
你说有两条一样的记录,大概是因为Create的这个特性:

// Create creates a new file with the provided name in the GridFS.  If the file
// name already exists, a new version will be inserted with an up-to-date
// uploadDate that will cause it to be atomically visible to the Open and
// OpenId methods.
恩,这段我看了,感觉没办法总是会生成新的一样的记录,后面用了open,却没想到用open来判断,我菜鸟太水了,大神啊
pj199 2014-08-13
  • 打赏
  • 举报
回复
引用 1 楼 svenwang 的回复:
你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}
check函数是里面返回值是因为还有别的函数里面用到,最后加个合适的返回值。 我一开始一个fmt.Println(file1.Id())是在file1.close()之前的,后来又加了几个没换行直接写在了file1.close()之后,没注意运行了一切正常。 我想是把本地的一个文件保存到mongodb里面,然后再打开读取,我看了你的里面这句话_, err = io.Copy(dst, src)是要放在if{}外面逻辑上不对啊, 这样通过打开判断是不是要新建一个文件,感觉可以,我试试
svenwang 2014-08-13
  • 打赏
  • 举报
回复
根据Open的说明:

// Open returns the most recently uploaded file with the provided
// name, for reading. If the file isn't found, err will be set
// to mgo.ErrNotFound.
可以先Open,如果失败并且错误是NotFound,然后再去Create:

package main
 
import (
    "fmt"
    "io"
    "os"
 
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)
 
func check(err error) {
    if err != nil {
        panic(err)
    }
}
 
func main() {
    src, err := os.Open("D:/test.txt")
    check(err)
    defer src.Close()
 
    session, err := mgo.Dial("127.0.0.1")
    check(err)
    defer session.Close()
 
    db := session.DB("filedb")
    dst, err = db.GridFS("fs").Open("test.txt")
    if err != nil {
		if err != mgo.ErrNotFound {
			panic(err)
		}
        // create the file when failing to open it
        dst, err := db.GridFS("fs").Create("test.txt")
        check(err)
    }
    defer dst.Close()
    _, err = io.Copy(dst, src)
    check(err)
 
    fmt.Println(dst.Id())
    fmt.Println(dst.UploadDate())
    fmt.Println(dst.Size())
}
svenwang 2014-08-13
  • 打赏
  • 举报
回复
你说有两条一样的记录,大概是因为Create的这个特性:

// Create creates a new file with the provided name in the GridFS.  If the file
// name already exists, a new version will be inserted with an up-to-date
// uploadDate that will cause it to be atomically visible to the Open and
// OpenId methods.
svenwang 2014-08-13
  • 打赏
  • 举报
回复
你这段代码问题挺多的。 1.check函数没有任何作用,因为那个return是从check里返回,并不会从main里返回 2.file1关闭了不应该再调用file1的方法 看你代码的逻辑,似乎是打算如果数据库里没有文件就创建一个文件。我把代码重新组织了一下,你看看对不对:

package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	src, err := os.Open("D:/test.txt")
	check(err)
	defer src.Close()

	session, err := mgo.Dial("127.0.0.1")
	check(err)
	defer session.Close()

	db := session.DB("filedb")
	dst, err = db.GridFS("fs").Open("test.txt")
	if err != nil {
		// create the file when failing to open it
		dst, err := db.GridFS("fs").Create("test.txt")
		check(err)
	}
	_, err = io.Copy(dst, src)
	check(err)
	defer dst.Close()

	fmt.Println(dst.Id())
	fmt.Println(dst.UploadDate())
	fmt.Println(dst.Size())
}

2,190

社区成员

发帖
与我相关
我的任务
社区描述
go语言学习与交流版
社区管理员
  • go语言社区
  • Freeman Z
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧