গো ব্যবহার করে / ফাইল থেকে / পড়তে কীভাবে?


284

আমি নিজে থেকে গো শিখতে চেষ্টা করেছি, তবে সাধারণ ফাইলগুলি থেকে পড়তে এবং লেখার চেষ্টা করতে গিয়ে আমি স্তব্ধ হয়ে পড়েছি।

আমি যতদূর যেতে পারি inFile, _ := os.Open(INFILE, 0, 0), তবে আসলে ফাইলটির বিষয়বস্তু পাওয়া কোনও অর্থবোধ করে না, কারণ পঠন ফাংশনটি []byteপ্যারামিটার হিসাবে নেয় ।

func (file *File) Read(b []byte) (n int, err Error)

উত্তর:


476

আসুন গো-তে ফাইলগুলি পড়ার এবং লেখার সমস্ত পদ্ধতির একটি Go 1- সামঞ্জস্যপূর্ণ তালিকা তৈরি করুন।

কারণ ফাইল এপিআই সম্প্রতি পরিবর্তিত হয়েছে এবং বেশিরভাগ উত্তর উত্তর গো ১ এর সাথে কাজ করে না They এগুলিও মিস করে bufioযা গুরুত্বপূর্ণ আইএমএইচও।

নিম্নলিখিত উদাহরণগুলিতে আমি একটি ফাইল এটি থেকে পড়ে এবং গন্তব্য ফাইলটিতে লিখে কপি করি।

বেসিকগুলি দিয়ে শুরু করুন

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

এখানে আমি ব্যবহার করেছি os.Openএবং os.Createযা চারপাশে সুবিধাজনক মোড়ক os.OpenFile। আমাদের সাধারণত OpenFileসরাসরি কল করার প্রয়োজন হয় না ।

ইওএফের চিকিত্সা করার বিষয়টি লক্ষ্য করুন। প্রতিটি কল Readপূরণ করার চেষ্টা করে bufএবং ততক্ষণে io.EOFএটি ফাইলের শেষে পৌঁছলে ত্রুটি হিসাবে ফিরে আসে । এই ক্ষেত্রে bufএখনও তথ্য রাখা হবে। ফলস্বরূপ কলগুলি Readশূন্যকে রিটার্নে পাঠানো বাইটের সংখ্যা io.EOFহিসাবে এবং ত্রুটি হিসাবে একই হিসাবে আসে। অন্য কোনও ত্রুটি আতঙ্কের দিকে নিয়ে যাবে।

ব্যবহার bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

bufioএখানে কেবল বাফার হিসাবে কাজ করছে, কারণ আমাদের ডেটা নিয়ে তেমন কিছু করার নেই। অন্যান্য পরিস্থিতিতে (বিশেষত পাঠ্য ফাইল সহ) bufioআমাদের সহজেই এবং নমনীয়ভাবে পড়ার জন্য এবং লেখার জন্য একটি দুর্দান্ত এপিআই দিয়ে খুব দরকারী , যখন এটি পর্দার আড়ালে বাফারিং পরিচালনা করে।

ব্যবহার ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

পাই হিসাবে সহজ! তবে আপনি কেবলমাত্র বড় ফাইলের সাথেই কাজ করছেন না তা নিশ্চিত হয়েই এটি ব্যবহার করুন।


55
যে কেউ এই প্রশ্নে হোঁচট খায়, এই লাইব্রেরিগুলি চালু করার আগে এটি 2009 সালে মূলত জিজ্ঞাসা করা হয়েছিল, সুতরাং দয়া করে এই উত্তরটি আপনার গাইড হিসাবে ব্যবহার করুন!
শেঠ হোইনিগ 17'12

1
Golang.org/pkg/os/#File.Write এর মতে , যখন লিখন সমস্ত বাইট না লিখে থাকে, তখন এটি একটি ত্রুটি দেয়। সুতরাং প্রথম উদাহরণে অতিরিক্ত পরীক্ষা করার panic("error in writing")প্রয়োজন নেই ( )।
ayke

15
নোট করুন যে এই উদাহরণগুলি fo.Close () থেকে ত্রুটি রিটার্ন চেক করছে না। লিনাক্স ম্যান পৃষ্ঠাগুলি বন্ধ (2) থেকে: বন্ধ () এর রিটার্ন মানটি পরীক্ষা করা একটি সাধারণ তবে তবুও গুরুতর প্রোগ্রামিং ত্রুটি। এটি সম্পূর্ণ সম্ভব যে পূর্বের লিখন (2) ক্রিয়াকলাপে ত্রুটিগুলি সর্বশেষ চূড়ান্ত () এ রিপোর্ট করা হয়েছিল। ফাইলটি বন্ধ করার সময় রিটার্ন মানটি পরীক্ষা না করা তথ্য নীরব ক্ষতি হতে পারে। এটি বিশেষত এনএফএস এবং ডিস্ক কোটার সাথে লক্ষ্য করা যায়।
নিক ক্রেগ-উড

12
সুতরাং, একটি "বড়" ফাইল কি? 1KB? 1MB? 1GB? বা "বড়" কি মেশিনের হার্ডওয়ারের উপর নির্ভর করে?
425nesp

3
@ 425nesp এটি পুরো ফাইলটিকে মেমরির মধ্যে পড়ে, তাই এটি চলমান মেশিনে উপলব্ধ মেমরির পরিমাণের উপর নির্ভর করে।
মোস্তফা

49

এটি ভাল সংস্করণ:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}

8
এটি মেমরিতে পুরো ফাইল সঞ্চয় করে। ফাইলটি যেহেতু বড় হতে পারে তাই আপনি যা করতে চান তা সর্বদা নাও হতে পারে।
ব্যবহারকারী 7610

9
এছাড়াও, 0x777বোগাস হয়। যাই হোক না কেন, এটি আরও বেশি পছন্দ 0644বা 0755(অষ্টাল, হেক্স নয়) হওয়া উচিত।
সিএনএসটি

@ সিএনএসটি 0x777 থেকে 0644 এ পরিবর্তন করেছে
ট্রেন্টন

31

ব্যবহার io.Copy

package main

import (
    "io"
    "log"
    "os"
)

func main () {
    // open files r and w
    r, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer r.Close()

    w, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer w.Close()

    // do the actual work
    n, err := io.Copy(w, r)
    if err != nil {
        panic(err)
    }
    log.Printf("Copied %v bytes\n", n)
}

আপনি যদি চাকাটিকে পুনর্সংশ্লিষ্ট করার মতো মনে করেন না, io.Copyএবং io.CopyNআপনাকে ভালভাবে পরিবেশন করতে পারে। আপনি যদি io.Copy ফাংশনের উত্সটি পরীক্ষা করেন তবে এটি গো লাইব্রেরিতে মোস্তফার একটি সমাধান ('বেসিক' আসলে) প্যাকেজড ছাড়া কিছুই নয়। যদিও তার চেয়ে তারা উল্লেখযোগ্যভাবে বৃহত্তর বাফার ব্যবহার করছে।


5
উল্লেখ করার এক জিনিস মূল্য - নিশ্চিত করুন যে ফাইলের বিষয়বস্তু ডিস্কে লেখা হয়েছিল হতে চাইলে আমাদের অবশ্যই ব্যবহার করতে হবে w.Sync()পরেio.Copy(w, r)
Shay Tsadok

এছাড়াও, আপনি যদি ইতিমধ্যে বিদ্যমান ফাইলে io.Copy()লিখেন তবে কেবলমাত্র আপনি যে ডেটা দিয়ে খাওয়ান তা কেবল লিখে রাখবেন, সুতরাং যদি বিদ্যমান ফাইলে আরও সামগ্রী থাকে তবে এটি সরানো হবে না, যার ফলে ফাইলটি দুর্নীতিগ্রস্থ হতে পারে।
ইনভিডিয়ান

1
@ ইনভিডিয়ান এটি সমস্ত আপনি কীভাবে গন্তব্য ফাইল খুলবেন তার উপর নির্ভর করে। আপনি যদি করেন তবে w, err := os.Create("output.txt")যা বর্ণনা করেছেন তা ঘটে না, কারণ "তৈরি করুন নামযুক্ত ফাইলটি তৈরি করে বা কাটাবে the যদি ফাইলটি ইতিমধ্যে বিদ্যমান থাকে, তবে এটি কেটে ফেলা হবে।" golang.org/pkg/os/# তৈরি করুন
ব্যবহারকারী 7610

এটি সঠিক উত্তর হওয়া উচিত কারণ এটি চাকাটি পুনরায় উদ্ভাবন না করে পুরো ফাইলটি পড়ার আগে একবারে না পড়ে read
এলি ডেভিস

11

নতুন গো সংস্করণগুলির সাথে ফাইল থেকে / পড়া / পড়া সহজ। একটি ফাইল থেকে পড়তে:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

একটি ফাইল লিখতে:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

এটি কোনও ফাইলের সামগ্রীতে ওভাররাইট করবে (এটি যদি না থাকে তবে একটি নতুন ফাইল তৈরি করুন)।


10

[]byteসমস্ত বা বাইট অ্যারের অংশের একটি স্লাইস (একটি সাবস্ট্রিংয়ের অনুরূপ)। স্লাইসটিকে সিস্টেমের জন্য কোনও অ্যারের (স্লাইস) সমস্ত অংশ বা অ্যাক্সেস করার জন্য কোনও লুকানো পয়েন্টার ক্ষেত্রের সাথে মান কাঠামো হিসাবে ভাবুন, স্লাইসের দৈর্ঘ্য এবং ক্ষমতা জন্য ক্ষেত্রগুলি, যা আপনি len()এবং cap()ফাংশনগুলি ব্যবহার করে অ্যাক্সেস করতে পারবেন ।

আপনার জন্য এখানে একটি কার্যক্ষম স্টার্টার কিট রয়েছে যা একটি বাইনারি ফাইল পড়ে এবং মুদ্রণ করে; inNameআপনার সিস্টেমে একটি ছোট ফাইল উল্লেখ করার জন্য আপনাকে আক্ষরিক মান পরিবর্তন করতে হবে ।

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}

9
গো কনভেনশনটি হ'ল প্রথমে ত্রুটিটি যাচাই করা হবে এবং সাধারণ if
কোডটিকে

@ জুরিলি: ত্রুটি দেখা দিলে যদি ফাইলটি খোলা থাকে, আপনি কীভাবে এটি বন্ধ করবেন?
পিটারসো

10
@ পেটারসো: ডিফার ইউজ করুন
জেমস অ্যান্টিল

তবে কেন একটি [256] বাইট গ্রহণ করা হয়নি এবং বুফ ইন স্পষ্টভাবে নিরীহ এবং ভার্বোস (তবে স্পষ্টত ভুল নয়) - মেক ([] বাইট, 256) গ্রহণযোগ্য?
কার্ডিফ স্পেস ম্যান

7

এটা চেষ্টা কর:

package main

import (
  "io"; 
  )


func main() {
  contents,_ := io.ReadFile("filename");
  println(string(contents));
  io.WriteFile("filename", contents, 0644);
}

1
আপনি যদি পুরো ফাইলটি একবারে পড়তে চান তবে এটি কাজ করবে। যদি ফাইলটি সত্যিই বড় হয় বা আপনি কেবল এর কিছু অংশ পড়তে চান তবে এটি আপনি যা খুঁজছেন তা তা নাও হতে পারে।
ইভান শ

3
আপনার সত্যই ত্রুটি কোডটি পরীক্ষা করা উচিত, এবং এটির মতো এড়ানো উচিত নয় !!
হাসেন

7
এটি এখন ioutil প্যাকেজে স্থানান্তরিত হয়েছে। সুতরাং এটি ioutil.ReadFile () হবে
ক্রিস্টোফার

আমি ঠিক করেছি তাই এটি 0644 বলে
জোয়াকিম

1

কেবলমাত্র ডকুমেন্টেশনটি দেখে মনে হচ্ছে আপনার কেবল প্রকারের একটি বাফার ঘোষণা করা উচিত [] বাইট এবং এটি পড়ার জন্য এটি পাস করতে হবে যা তখন সেই অনেকগুলি অক্ষর পর্যন্ত পড়তে পারে এবং প্রকৃতপক্ষে পড়া অক্ষরের সংখ্যা (এবং একটি ত্রুটি) ফেরত দেয়।

ডকস বলে

ফাইল থেকে লেন (খ) বাইট পর্যন্ত পড়ুন Read এটি পঠিত বাইট সংখ্যা এবং একটি ত্রুটি, যদি থাকে তবে প্রদান করে। ইওএফটি ইওএফ-তে সেট করা ত্রুটিযুক্ত একটি শূন্য গণনা দ্বারা সংকেতযুক্ত।

এটা কি কাজ করে না?

সম্পাদনা: এছাড়াও, আমি মনে করি আপনার সম্ভবত ওএস প্যাকেজটি ব্যবহারের পরিবর্তে বুফিও প্যাকেজে ঘোষিত রিডার / রাইটার ইন্টারফেসগুলি ব্যবহার করা উচিত ।


আপনার কাছে আমার ভোট রয়েছে কারণ আপনি প্রকৃত লোকেরা ডকুমেন্টেশন পড়লে কী দেখেন তা সত্যই স্বীকার করেন, যাঁরা গোপনে অভ্যস্ত হন তাদের পার্ট করার পরিবর্তে তারা যখন ফাংশনটির ডকুমেন্টেশন পড়েন তারা ইতিমধ্যে পরিচিত EM
কার্ডিফ স্পেস ম্যান

1

পঠন পদ্ধতিটি বাইট প্যারামিটার নেয় কারণ এটি যে বাফারটি এতে পড়বে। এটি কয়েকটি চেনাশোনাগুলিতে একটি সাধারণ আইডিয়াম এবং আপনি যখন এটি সম্পর্কে চিন্তা করেন তখন কিছুটা বোধগম্য হয়।

এই পদ্ধতিতে আপনি কতগুলি বাইট পাঠক দ্বারা পড়বেন তা নির্ধারণ করতে পারবেন এবং কতগুলি বাইট আসলে পড়েছিল এবং কোনও ত্রুটি যথাযথভাবে পরিচালনা করেছেন তা দেখতে রিটার্নটি পরীক্ষা করতে পারবেন।

অন্যরা যেমন তাদের উত্তরগুলিতে ইঙ্গিত করেছে বুফিও সম্ভবত আপনি বেশিরভাগ ফাইল থেকে পড়ার জন্য চান।

আমি সত্যিই দরকারী যেহেতু আমি অন্য একটি ইঙ্গিত যুক্ত করব। কোনও ফাইল থেকে একটি লাইন পড়া সবচেয়ে ভাল রিডলাইন পদ্ধতি দ্বারা নয় বরং এর পরিবর্তে রিডবাইটস বা রিডস্ট্রিং পদ্ধতি দ্বারা সম্পন্ন হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.