আমি কীভাবে গো ব্যবহার করে দক্ষতার সাথে একটি বড় ফাইল ডাউনলোড করতে পারি?


106

গো ব্যবহার করে কোনও বৃহত ফাইল ডাউনলোড করার কোনও উপায় আছে যা কোনও ফাইলে লেখার আগে মেমরির মধ্যে এটি সমস্ত সংরক্ষণ করার পরিবর্তে সামগ্রীটি কোনও ফাইলে সরাসরি সংরক্ষণ করবে? কারণ ফাইলটি এত বড়, কোনও ফাইলকে লেখার আগে মেমরির মধ্যে এটি সমস্ত সঞ্চয় করে সমস্ত মেমরি ব্যবহার করতে চলেছে।

উত্তর:


214

আমি ধরে নেব যে আপনি HTTP- র মাধ্যমে ডাউনলোড বোঝাতে চাইছেন (ব্রেভিটির জন্য ত্রুটি চেক বাদ দেওয়া হয়েছে):

import ("net/http"; "io"; "os")
...
out, err := os.Create("output.txt")
defer out.Close()
...
resp, err := http.Get("http://example.com/")
defer resp.Body.Close()
...
n, err := io.Copy(out, resp.Body)

Http.Response এর দেহটি একটি পাঠক, সুতরাং আপনি কোনও পাঠককে গ্রহণযোগ্য কোনও ফাংশন ব্যবহার করতে পারেন, যেমন, একবারে সব চেয়ে একবারে কিছু অংশ পড়ুন। এই নির্দিষ্ট ক্ষেত্রে, io.Copy()আপনার জন্য উদ্বেগ কাজ করে।


85
নোট করুন যে io.Copyইনপুট থেকে 32kb (সর্বাধিক) পড়ে এবং সেগুলিকে আউটপুট লিখে দেয়, তারপরে পুনরাবৃত্তি করে। সুতরাং স্মৃতি নিয়ে চিন্তা করবেন না।
মোশে রেভাঃ

ডাউনলোড অগ্রগতি বাতিল কিভাবে?
জেলান ইয়াং

আপনি নির্ধারিত সময়সীমার পরে ডাউনলোডটি বাতিল করতে এটি ব্যবহার করতে পারেনclient := http.Client{Timeout: 10 * time.Second,} client.Get("http://example.com/")
ভরথ কুমার

55

স্টিভ এম এর উত্তরের আরও বর্ণনামূলক সংস্করণ।

import (
    "os"
    "net/http"
    "io"
)

func downloadFile(filepath string, url string) (err error) {

  // Create the file
  out, err := os.Create(filepath)
  if err != nil  {
    return err
  }
  defer out.Close()

  // Get the data
  resp, err := http.Get(url)
  if err != nil {
    return err
  }
  defer resp.Body.Close()

  // Check server response
  if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("bad status: %s", resp.Status)
  }

  // Writer the body to file
  _, err = io.Copy(out, resp.Body)
  if err != nil  {
    return err
  }

  return nil
}

1
আমার মহাবিশ্বে আমি একটি ডিএসএল বাস্তবায়ন করেছি যা একটি ফাইল ডাউনলোড করার দরকার ছিল ... যতক্ষণ না আমি কিছু ওএস কমপ্যাট এবং ক্রুট ইস্যুতে পড়ে যাই যা আমি সত্যই আশেপাশে কনফিগার করতে চাই না কারণ এটি কার্যকর () কার্ল করা সহজ ছিল কারণ এটি একটি বোধগম্য সুরক্ষা মডেল। সুতরাং আপনি এই কোডটি দিয়ে আমার সিআরএল প্রতিস্থাপন করুন এবং একটি 10-15x পারফরম্যান্স উন্নতি পেয়েছেন। Duh!
রিচার্ড

14

উপরে বর্ণিত উত্তরটি io.Copyহ'ল আপনার প্রয়োজনটি হ'ল তবে আপনি যদি ভাঙা ডাউনলোডগুলি পুনরায় শুরু করা, অটো-নামকরণ ফাইলগুলি, চেকসামের যাচাইকরণ বা একাধিক ডাউনলোডের অগ্রগতি পর্যবেক্ষণের মতো অতিরিক্ত বৈশিষ্ট্যে আগ্রহী হন তবে দখল প্যাকেজটি চেকআউট করুন ।


লিঙ্কটি অবজ্ঞাত হয়ে গেলে তথ্যটি ক্ষতিগ্রস্ত হবে না তা নিশ্চিত করতে আপনি একটি কোড স্নিপেট যুক্ত করতে পারেন?
030

-6
  1. এখানে একটি নমুনা। https://github.com/thbar/golang-playground/blob/master/download-files.go

  2. এছাড়াও আমি আপনাকে কিছু কোড দিতে সাহায্য করতে পারে।

কোড:

func HTTPDownload(uri string) ([]byte, error) {
    fmt.Printf("HTTPDownload From: %s.\n", uri)
    res, err := http.Get(uri)
    if err != nil {
        log.Fatal(err)
    }
    defer res.Body.Close()
    d, err := ioutil.ReadAll(res.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("ReadFile: Size of download: %d\n", len(d))
    return d, err
}

func WriteFile(dst string, d []byte) error {
    fmt.Printf("WriteFile: Size of download: %d\n", len(d))
    err := ioutil.WriteFile(dst, d, 0444)
    if err != nil {
        log.Fatal(err)
    }
    return err
}

func DownloadToFile(uri string, dst string) {
    fmt.Printf("DownloadToFile From: %s.\n", uri)
    if d, err := HTTPDownload(uri); err == nil {
        fmt.Printf("downloaded %s.\n", uri)
        if WriteFile(dst, d) == nil {
            fmt.Printf("saved %s as %s\n", uri, dst)
        }
    }
}

13
এই উদাহরণটি সম্পূর্ণ কন্টেন্টকে মেমোরিতে পড়বে ioutil.ReadAll()। এটি ঠিক আছে, যতক্ষণ আপনি ক্ষুদ্র ফাইল নিয়ে কাজ করছেন।
eduncan911

13
@ এডুঙ্কান ৯১১, তবে এই প্রশ্নের পক্ষে এটি ঠিক নয়, যা স্পষ্টভাবে বড় ফাইলগুলির বিষয়ে কথা বলে এবং এগুলি সমস্ত স্মৃতিতে চুষতে চায় না।
ডেভ সি

2
ঠিক ঠিক তাই, এ কারণেই আমি এতো মন্তব্য করেছি - অন্যদেরও জানতে হবে এবং এটি বড় ফাইলগুলির জন্য ব্যবহার না করা।
eduncan911

4
এটি কোনও সৌম্য উত্তর নয় এবং প্রকৃতপক্ষে সরানো উচিত। কোডের একটি বড় স্তূপের মধ্যে রিডএল ব্যবহার একটি বড় ফাইল ব্যবহৃত না হওয়া পর্যন্ত অপেক্ষা করা একটি সুপ্ত সমস্যা। যা ঘটে তা হ'ল যদি বড় ফাইলগুলিতে রিডআল থাকে তবে সাধারণত প্রতিক্রিয়া হ'ল উচ্চ মেমরির খরচ এবং বর্ধিত এডাব্লুএস বিলগুলি কিছুটা ব্যর্থ না হওয়া পর্যন্ত। সমস্যাটি আবিষ্কার হওয়ার সময়, বিলগুলি ইতিমধ্যে বেশি।
রব
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.