在 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。