在 EasyDSS 的开发过程中,由于有用户在使用过程中出现过误删的操作,所以我们需要对用户上传的视频进行备份,防止用户误删除,此过程需要对文件进行复制。
常用的文件复制功能,直接采用 go 官方库提供的 io.Copy() 方法进行实现。
nBytes, err := io.Copy(destination, source)
以上方法适用于小文件的复制,对于超大文件,比如 500MB 甚至 1GB 以上文件的复制就会出现问题。
io.Copy() 方法的基本逻辑是,一次性将源文件全部读取到内存中,然后从内存中将数据写入到新的文件中。对于较大的文件,比如读取 2GB 大小的视频文件,一次性就会消耗 2GB 的内存,如果电脑内存本身就很小,此时程序就会提供内存不够。因此针对较大文件不应该直接调用此方法。
对于较大文件的复制操作,应该每次都读取很小的数据,比如1024 字节,写入到新的文件中。然后再次读取文件,写入新文件,直到将所有的数据写入到新文件中。
func Copy(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}
if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}
source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
//nBytes, err := io.Copy(destination, source)
nBytes := int64(0)
buf := make([]byte, 4096)
for {
n, err := source.Read(buf)
if err != nil && err != io.EOF {
return 0, err
}
if n == 0 {
break
}
if _, err := destination.Write(buf[:n]); err != nil {
return 0, err
}
// 更新写入的数量
nBytes = nBytes + int64(n)
}
return nBytes, err
}
当读取文件时,遇到 EOF 标志,代表文件读取完毕。上述方法中的核心代码如下。
nBytes := int64(0)
buf := make([]byte, 4096)
for {
n, err := source.Read(buf)
if err != nil && err != io.EOF {
return 0, err
}
if n == 0 {
break
}
if _, err := destination.Write(buf[:n]); err != nil {
return 0, err
}
// 更新写入的数量
nBytes = nBytes + int64(n)
}
EasyDSS是TSINGSEE青犀视频研发的关于互联网视频直播/点播平台,能够接入RTMP协议摄像头及设备,并生成推流地址进行视频监控的推流直播。使用EasyDSS的用户都知道,我们提供了丰富的API接口,开发者可以自由进行二次开发,API接口详情:http://demo.easydss.com:10080/apidoc。