亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

正在獲取“恐慌:os:在使用O_APPEND打開的文件上無效使用 WriteAt”

正在獲取“恐慌:os:在使用O_APPEND打開的文件上無效使用 WriteAt”

Go
ibeautiful 2022-09-19 10:10:21
我是Go的新手。我開始編寫我的第一個代碼,我必須從AWS下載一堆CSV。我不明白為什么它給我以下錯誤與O_APPEND模式。如果我刪除 ,我只得到最后一個文件數據,這不是目標。os.O_APPEND目標是將所有 CSV 文件下載到本地的一個文件中。我想了解我做錯了什么。package mainimport (    "fmt"    "os"    "path/filepath"    "github.com/aws/aws-sdk-go/aws"    "github.com/aws/aws-sdk-go/aws/credentials"    "github.com/aws/aws-sdk-go/aws/session"    "github.com/aws/aws-sdk-go/service/s3"    "github.com/aws/aws-sdk-go/service/s3/s3manager")const (    AccessKeyId     = "xxxxxxxxx"    SecretAccessKey = "xxxxxxxxxxxxxxxxxxxx"    Region          = "eu-central-1"    Bucket          = "dexter-reports"    bucketKey       = "Jenkins/pluginVersions/")func main() {    // Load the Shared AWS Configuration    os.Setenv("AWS_ACCESS_KEY_ID", AccessKeyId)    os.Setenv("AWS_SECRET_ACCESS_KEY", SecretAccessKey)    filename := "JenkinsPluginDetais.txt"    cred := credentials.NewStaticCredentials(AccessKeyId, SecretAccessKey, "")    config := aws.Config{Credentials: cred, Region: aws.String(Region), Endpoint: aws.String("s3.amazonaws.com")}    file, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)    if err != nil {        panic(err)    }    defer file.Close()    sess, err := session.NewSession(&config)    if err != nil {        fmt.Println(err)    }    //list Buckets    ObjectList := listBucketObjects(sess)    //loop over the obectlist. First initialize the s3 downloader via s3manager    downloader := s3manager.NewDownloader(sess)    for _, item := range ObjectList.Contents {        csvFile := filepath.Base(*item.Key)        if csvFile != "pluginVersions" {            downloadBucketObjects(downloader, file, csvFile)        }    }}func listBucketObjects(sess *session.Session) *s3.ListObjectsV2Output {    //create a new s3 client    svc := s3.New(sess)    resp, err := svc.ListObjectsV2(&s3.ListObjectsV2Input{        Bucket: aws.String(Bucket),        Prefix: aws.String(bucketKey),    })    if err != nil {        panic(err)    }    return resp}
查看完整描述

2 回答

?
回首憶惘然

TA貢獻1847條經驗 獲得超11個贊

首先,我不明白為什么你首先需要旗幟。根據我的理解,您可以省略.os.O_APPENDos.O_APPEND


現在,讓我們來看看為什么會發生這種情況的實際問題:


文檔 (參考: https://man7.org/linux/man-pages/man2/open.2.html):O_APPEND


O_APPEND

              The file is opened in append mode.  Before each write(2),

              the file offset is positioned at the end of the file, as

              if with lseek(2).  The modification of the file offset and

              the write operation are performed as a single atomic step.

因此,對于每個對文件的調用,偏移量都位于文件的末尾。write


但據說使用的是方法,即(*s3Manager.Download).DownloadWriteAt


文檔 :WriteAt


$ go doc os WriteAt


package os // import "os"


func (f *File) WriteAt(b []byte, off int64) (n int, err error)

    WriteAt writes len(b) bytes to the File starting at byte offset off. It

    returns the number of bytes written and an error, if any. WriteAt returns a

    non-nil error when n != len(b).


    If file was opened with the O_APPEND flag, WriteAt returns an error.

請注意最后一行,如果文件是用標志打開的,它將導致錯誤,它甚至是正確的,因為 WriteAt 的第二個參數是偏移量,但混合的行為和偏移量搜索可能會產生問題,導致意外的結果,并且它出錯了。O_APPENDO_APPENDWriteAt


查看完整回答
反對 回復 2022-09-19
?
明月笑刀無情

TA貢獻1828條經驗 獲得超4個贊

考慮 s3 管理器的定義。下載器:


func (d Downloader) Download(w io.WriterAt, input *s3.GetObjectInput, options ...func(*Downloader)) (n int64, err error)

第一個參數是 ;此接口是:io.WriterAt


type WriterAt interface {

    WriteAt(p []byte, off int64) (n int, err error)

}

這意味著該函數將調用您正在傳遞的方法中的方法。根據文件.寫在的文檔DownloadWriteAtFile


如果使用O_APPEND標志打開文件,則 WriteAt 將返回錯誤。


因此,這解釋了為什么您會收到錯誤,但提出了一個問題“為什么使用和不接受(和調用)?答案可以在文檔中找到:DownloadWriteAtio.WriterWrite


w io.作者可以通過操作系統來滿足。用于執行多部分并發下載的文件,或使用 aws 在內存 [] 字節包裝器中。寫入緩沖區


因此,為了提高性能,可能會對文件的某些部分發出多個同時請求,然后在收到這些請求時將其寫出(這意味著它可能不會按順序寫入數據)。這也解釋了為什么多次調用函數時,使用相同的結果覆蓋數據(當檢索文件的每個塊時,它會在輸出文件中的適當位置將其寫出;這將覆蓋已經存在的任何數據)。DownloaderFileDownloader


文檔中的上述引用也指出了一個可能的解決方案;使用 aws。WriteAtBuffer,下載完成后,將數據寫入您的文件(然后可以使用 打開該文件) - 如下所示:O_APPEND


buf := aws.NewWriteAtBuffer([]byte{})

numBytes, err := downloader.Download(buf,

        &s3.GetObjectInput{

            Bucket: aws.String(Bucket),

            Key:    aws.String(fileToDownload),

        })


if err != nil {

    panic(err)

}

_, err = file.Write(buf.Bytes())

if err != nil {

    panic(err)

}

另一種方法是下載到臨時文件中,然后將其附加到輸出文件中(如果文件很大,則可能需要執行此操作)。


查看完整回答
反對 回復 2022-09-19
  • 2 回答
  • 0 關注
  • 87 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號