github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/pcsutil/checksum/checksum.go (about) 1 // Package checksum 校验本地文件包 2 package checksum 3 4 import ( 5 "crypto/md5" 6 "github.com/fzfile/BaiduPCS-Go/pcsutil/cachepool" 7 "github.com/fzfile/BaiduPCS-Go/pcsutil/converter" 8 "hash/crc32" 9 "io" 10 "os" 11 ) 12 13 const ( 14 // DefaultBufSize 默认的bufSize 15 DefaultBufSize = int(256 * converter.KB) 16 ) 17 18 const ( 19 // CHECKSUM_MD5 获取文件的 md5 值 20 CHECKSUM_MD5 int = 1 << iota 21 // CHECKSUM_SLICE_MD5 获取文件前 sliceSize 切片的 md5 值 22 CHECKSUM_SLICE_MD5 23 // CHECKSUM_CRC32 获取文件的 crc32 值 24 CHECKSUM_CRC32 25 ) 26 27 type ( 28 // LocalFileMeta 本地文件元信息 29 LocalFileMeta struct { 30 Path string `json:"path"` // 本地路径 31 Length int64 `json:"length"` // 文件大小 32 SliceMD5 []byte `json:"slicemd5"` // 文件前 requiredSliceLen (256KB) 切片的 md5 值 33 MD5 []byte `json:"md5"` // 文件的 md5 34 CRC32 uint32 `json:"crc32"` // 文件的 crc32 35 ModTime int64 `json:"modtime"` // 修改日期 36 } 37 38 // LocalFileChecksum 校验本地文件 39 LocalFileChecksum struct { 40 LocalFileMeta 41 bufSize int 42 sliceSize int 43 buf []byte 44 file *os.File // 文件 45 } 46 ) 47 48 func NewLocalFileChecksum(localPath string, sliceSize int) *LocalFileChecksum { 49 return NewLocalFileChecksumWithBufSize(localPath, DefaultBufSize, sliceSize) 50 } 51 52 func NewLocalFileChecksumWithBufSize(localPath string, bufSize, sliceSize int) *LocalFileChecksum { 53 return &LocalFileChecksum{ 54 LocalFileMeta: LocalFileMeta{ 55 Path: localPath, 56 }, 57 bufSize: bufSize, 58 sliceSize: sliceSize, 59 } 60 } 61 62 // OpenPath 检查文件状态并获取文件的大小 (Length) 63 func (lfc *LocalFileChecksum) OpenPath() error { 64 if lfc.file != nil { 65 lfc.file.Close() 66 } 67 68 var err error 69 lfc.file, err = os.Open(lfc.Path) 70 if err != nil { 71 return err 72 } 73 74 info, err := lfc.file.Stat() 75 if err != nil { 76 return err 77 } 78 79 lfc.Length = info.Size() 80 lfc.ModTime = info.ModTime().Unix() 81 return nil 82 } 83 84 // GetFile 获取文件 85 func (lfc *LocalFileChecksum) GetFile() *os.File { 86 return lfc.file 87 } 88 89 // Close 关闭文件 90 func (lfc *LocalFileChecksum) Close() error { 91 if lfc.file == nil { 92 return ErrFileIsNil 93 } 94 95 return lfc.file.Close() 96 } 97 98 func (lfc *LocalFileChecksum) initBuf() { 99 if lfc.buf == nil { 100 lfc.buf = cachepool.RawMallocByteSlice(lfc.bufSize) 101 } 102 } 103 104 func (lfc *LocalFileChecksum) writeChecksum(data []byte, wus ...*ChecksumWriteUnit) (err error) { 105 doneCount := 0 106 for _, wu := range wus { 107 _, err := wu.Write(data) 108 switch err { 109 case ErrChecksumWriteStop: 110 doneCount++ 111 continue 112 case nil: 113 default: 114 return err 115 } 116 } 117 if doneCount == len(wus) { 118 return ErrChecksumWriteAllStop 119 } 120 return nil 121 } 122 123 func (lfc *LocalFileChecksum) repeatRead(wus ...*ChecksumWriteUnit) (err error) { 124 if lfc.file == nil { 125 return ErrFileIsNil 126 } 127 128 lfc.initBuf() 129 130 defer func() { 131 _, err = lfc.file.Seek(0, os.SEEK_SET) // 恢复文件指针 132 if err != nil { 133 return 134 } 135 }() 136 137 // 读文件 138 var ( 139 n int 140 ) 141 read: 142 for { 143 n, err = lfc.file.Read(lfc.buf) 144 switch err { 145 case io.EOF: 146 err = lfc.writeChecksum(lfc.buf[:n], wus...) 147 break read 148 case nil: 149 err = lfc.writeChecksum(lfc.buf[:n], wus...) 150 default: 151 return 152 } 153 } 154 switch err { 155 case ErrChecksumWriteAllStop: // 全部结束 156 err = nil 157 } 158 return 159 } 160 161 func (lfc *LocalFileChecksum) createChecksumWriteUnit(cw ChecksumWriter, isAll, isSlice bool, getSumFunc func(sliceSum interface{}, sum interface{})) (wu *ChecksumWriteUnit, deferFunc func(err error)) { 162 wu = &ChecksumWriteUnit{ 163 ChecksumWriter: cw, 164 End: lfc.LocalFileMeta.Length, 165 OnlySliceSum: !isAll, 166 } 167 168 if isSlice { 169 wu.SliceEnd = int64(lfc.sliceSize) 170 } 171 172 return wu, func(err error) { 173 if err != nil { 174 return 175 } 176 getSumFunc(wu.SliceSum, wu.Sum) 177 } 178 } 179 180 // Sum 计算文件摘要值 181 func (lfc *LocalFileChecksum) Sum(checkSumFlag int) (err error) { 182 lfc.fix() 183 wus := make([]*ChecksumWriteUnit, 0, 2) 184 if (checkSumFlag & (CHECKSUM_MD5 | CHECKSUM_SLICE_MD5)) != 0 { 185 md5w := md5.New() 186 wu, d := lfc.createChecksumWriteUnit( 187 NewHashChecksumWriter(md5w), 188 (checkSumFlag&CHECKSUM_MD5) != 0, 189 (checkSumFlag&CHECKSUM_SLICE_MD5) != 0, 190 func(sliceSum interface{}, sum interface{}) { 191 if sliceSum != nil { 192 lfc.SliceMD5 = sliceSum.([]byte) 193 } 194 if sum != nil { 195 lfc.MD5 = sum.([]byte) 196 } 197 }, 198 ) 199 200 wus = append(wus, wu) 201 defer d(err) 202 } 203 if (checkSumFlag & CHECKSUM_CRC32) != 0 { 204 crc32w := crc32.NewIEEE() 205 wu, d := lfc.createChecksumWriteUnit( 206 NewHash32ChecksumWriter(crc32w), 207 true, 208 false, 209 func(sliceSum interface{}, sum interface{}) { 210 if sum != nil { 211 lfc.CRC32 = sum.(uint32) 212 } 213 }, 214 ) 215 216 wus = append(wus, wu) 217 defer d(err) 218 } 219 220 err = lfc.repeatRead(wus...) 221 return 222 } 223 224 func (lfc *LocalFileChecksum) fix() { 225 if lfc.sliceSize <= 0 { 226 lfc.sliceSize = DefaultBufSize 227 } 228 if lfc.bufSize < DefaultBufSize { 229 lfc.bufSize = DefaultBufSize 230 } 231 }