github.com/qiniu/go-sdk/v7@v7.27.0/storagev2/objects/directory.go (about) 1 package objects 2 3 import ( 4 "container/list" 5 "path/filepath" 6 "strings" 7 8 "github.com/qiniu/go-sdk/v7/internal/context" 9 "github.com/qiniu/go-sdk/v7/storagev2/apis" 10 ) 11 12 type ( 13 // 目录 14 Directory struct { 15 bucket *Bucket 16 prefix, pathSeparator string 17 } 18 19 // 条目 20 Entry struct { 21 // 目录名称,仅当条目为目录时才有效 22 DirectoryName string 23 24 // 对象元信息,仅当条目为对象时才有效 25 Object *ObjectDetails 26 } 27 28 // 列举条目选项 29 ListEntriesOptions struct { 30 NeedParts bool // 是否需要分片信息 31 Recursive bool // 是否递归列举 32 } 33 ) 34 35 var SkipDir = filepath.SkipDir 36 37 // 移动目录 38 func (directory *Directory) MoveTo(ctx context.Context, toBucketName, toPrefix string) error { 39 if !strings.HasSuffix(toPrefix, directory.pathSeparator) { 40 toPrefix += directory.pathSeparator 41 } 42 operations := make([]Operation, 0, 16) 43 if err := directory.forEachObject(ctx, func(objectDetails *ObjectDetails) { 44 toObjectName := toPrefix + strings.TrimPrefix(objectDetails.Name, directory.prefix) 45 operations = append(operations, directory.bucket.Object(objectDetails.Name).MoveTo(toBucketName, toObjectName)) 46 }); err != nil { 47 return err 48 } 49 return directory.bucket.objectsManager.Batch(ctx, operations, nil) 50 } 51 52 // 复制目录 53 func (directory *Directory) CopyTo(ctx context.Context, toBucketName, toPrefix string) error { 54 if !strings.HasSuffix(toPrefix, directory.pathSeparator) { 55 toPrefix += directory.pathSeparator 56 } 57 operations := make([]Operation, 0, 16) 58 if err := directory.forEachObject(ctx, func(objectDetails *ObjectDetails) { 59 toObjectName := toPrefix + strings.TrimPrefix(objectDetails.Name, directory.prefix) 60 operations = append(operations, directory.bucket.Object(objectDetails.Name).CopyTo(toBucketName, toObjectName)) 61 }); err != nil { 62 return err 63 } 64 return directory.bucket.objectsManager.Batch(ctx, operations, nil) 65 } 66 67 // 删除目录 68 func (directory *Directory) Delete(ctx context.Context) error { 69 operations := make([]Operation, 0, 16) 70 if err := directory.forEachObject(ctx, func(objectDetails *ObjectDetails) { 71 operations = append(operations, directory.bucket.Object(objectDetails.Name).Delete()) 72 }); err != nil { 73 return err 74 } 75 return directory.bucket.objectsManager.Batch(ctx, operations, nil) 76 } 77 78 func (directory *Directory) forEachObject(ctx context.Context, each func(*ObjectDetails)) error { 79 lister := directory.bucket.List(ctx, &ListObjectsOptions{Prefix: directory.prefix}) 80 defer lister.Close() 81 82 var objectDetails ObjectDetails 83 for lister.Next(&objectDetails) { 84 each(&objectDetails) 85 } 86 87 return lister.Error() 88 } 89 90 // 列举目录条目 91 func (directory *Directory) ListEntries(ctx context.Context, options *ListEntriesOptions, f func(*Entry) error) error { 92 if options == nil { 93 options = &ListEntriesOptions{} 94 } 95 96 directories := list.New() 97 directories.PushBack(directory) 98 return consumeEntries(ctx, directories, options, f) 99 } 100 101 func (directory *Directory) listEntries(ctx context.Context, marker string, needParts bool) ([]*Entry, string, error) { 102 entries := make([]*Entry, 0, 1024) 103 request := apis.GetObjectsRequest{ 104 Bucket: directory.bucket.name, 105 Prefix: directory.prefix, 106 Delimiter: directory.pathSeparator, 107 Marker: marker, 108 NeedParts: needParts, 109 } 110 response, err := directory.bucket.objectsManager.storage.GetObjects(ctx, &request, nil) 111 if err != nil { 112 return nil, "", err 113 } 114 for _, commonPrefix := range response.CommonPrefixes { 115 entries = append(entries, &Entry{DirectoryName: commonPrefix}) 116 } 117 for _, item := range response.Items { 118 objectDetails := new(ObjectDetails) 119 if err = objectDetails.fromListedObjectEntry(&item); err != nil { 120 return nil, "", err 121 } 122 entries = append(entries, &Entry{Object: objectDetails}) 123 } 124 return entries, response.Marker, nil 125 } 126 127 func consumeEntries(ctx context.Context, directories *list.List, options *ListEntriesOptions, f func(*Entry) error) error { 128 var firstElement *list.Element 129 for { 130 if firstElement = directories.Front(); firstElement == nil { 131 break 132 } 133 directories.Remove(firstElement) 134 currentDirectory := firstElement.Value.(*Directory) 135 136 var ( 137 entries []*Entry 138 firstPage = true 139 marker string 140 err error 141 ) 142 nextPage: 143 for firstPage || marker != "" { 144 firstPage = false 145 if entries, marker, err = currentDirectory.listEntries(ctx, marker, options.NeedParts); err != nil { 146 return err 147 } else { 148 for _, entry := range entries { 149 err := f(entry) 150 switch err { 151 case nil: 152 if options.Recursive && entry.DirectoryName != "" { 153 directories.PushBack(&Directory{bucket: currentDirectory.bucket, prefix: entry.DirectoryName, pathSeparator: currentDirectory.pathSeparator}) 154 } 155 case SkipDir: 156 if entry.DirectoryName == "" { 157 continue nextPage 158 } 159 default: 160 return err 161 } 162 } 163 } 164 } 165 } 166 return nil 167 }