RTMP协议视频平台EasyDSS通过Golang实现超大文件复制功能备份文件方法

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

猜你喜欢

转载自blog.csdn.net/EasyDSS/article/details/108766657