SplitFile ...
(filePath string, fileChunkSizeInMB uint64)
| 20 | |
| 21 | // SplitFile ... |
| 22 | func SplitFile(filePath string, fileChunkSizeInMB uint64) ([]*os.File, error) { |
| 23 | if fileChunkSizeInMB == 0 { |
| 24 | return openSingleFile(filePath) |
| 25 | } |
| 26 | |
| 27 | file, err := os.Open(filePath) |
| 28 | if err != nil { |
| 29 | return nil, err |
| 30 | } |
| 31 | defer file.Close() |
| 32 | |
| 33 | fileInfo, err := file.Stat() |
| 34 | if err != nil { |
| 35 | return nil, err |
| 36 | } |
| 37 | |
| 38 | var fileSize = uint64(fileInfo.Size()) |
| 39 | var fileChunkSize = toBytes(fileChunkSizeInMB) |
| 40 | |
| 41 | // calculate total number of parts the file will be chunked into |
| 42 | totalPartsNum := uint64(math.Ceil(float64(fileSize) / float64(fileChunkSize))) |
| 43 | if totalPartsNum <= 1 { |
| 44 | return openSingleFile(filePath) |
| 45 | } |
| 46 | |
| 47 | partsTempDir := filepath.Join(os.TempDir(), generateHash()) |
| 48 | errCreatingTempDir := os.MkdirAll(partsTempDir, os.ModePerm) |
| 49 | if errCreatingTempDir != nil { |
| 50 | return nil, errCreatingTempDir |
| 51 | } |
| 52 | |
| 53 | baseFileName := filepath.Base(filePath) |
| 54 | var fileParts []*os.File |
| 55 | |
| 56 | for i := uint64(0); i < totalPartsNum; i++ { |
| 57 | filePartName := baseFileName + ".part." + strconv.FormatUint(i, 10) |
| 58 | tempFile := filepath.Join(partsTempDir, filePartName) |
| 59 | filePart, err := os.Create(tempFile) |
| 60 | if err != nil { |
| 61 | return nil, err |
| 62 | } |
| 63 | |
| 64 | partSize := int64(minUint64(fileChunkSize, fileSize-i*fileChunkSize)) |
| 65 | _, err = io.CopyN(filePart, file, partSize) |
| 66 | if err != nil { |
| 67 | filePart.Close() |
| 68 | return nil, err |
| 69 | } |
| 70 | |
| 71 | filePart.Seek(0, io.SeekStart) |
| 72 | fileParts = append(fileParts, filePart) |
| 73 | } |
| 74 | return fileParts, nil |
| 75 | } |
| 76 | |
| 77 | func openSingleFile(path string) ([]*os.File, error) { |
| 78 | f, err := os.Open(path) |
no test coverage detected