Давайте создадим Go 1-совместимый список всех способов чтения и записи файлов в Go.
Поскольку файловый API недавно изменился, и большинство других ответов не работают с Go 1. Они также пропускают, 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
напрямую.
Обратите внимание на лечение EOF. 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
это очень полезно, предоставляя нам хороший API для простого и гибкого чтения и записи, в то время как он обрабатывает буферизацию за кулисами.
С помощью 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)
}
}
Проще простого! Но используйте его, только если вы уверены, что не имеете дело с большими файлами.
panic("error in writing")
) не требуется.Это хорошая версия:
источник
0x777
является поддельным. В любом случае, это должно быть больше как0644
или0755
(восьмеричное, а не шестнадцатеричное).С помощью
io.Copy
Если вы не хотите изобретать велосипед, то
io.Copy
иio.CopyN
может служить вам хорошо. Если вы проверите источник функции io.Copy, это не что иное, как одно из решений Mostafa (собственно, «базовое»), упакованное в библиотеку Go. Они используют значительно больший буфер, чем он.источник
w.Sync()
послеio.Copy(w, r)
io.Copy()
будут записываться только те данные, которыми вы его кормите, поэтому, если в существующем файле было больше содержимого, он не будет удален, что может привести к повреждению файла.w, err := os.Create("output.txt")
, то, что вы описываете, не произойдет, потому что «Create создает или усекает указанный файл. Если файл уже существует, он усекается». golang.org/pkg/os/#Create .В новых версиях Go чтение / запись в / из файла становится проще. Чтобы прочитать из файла:
Для записи в файл:
Это перезапишет содержимое файла (создайте новый файл, если его там не было).
источник
[]byte
является срезом (похожим на подстроку) всего или части байтового массива. Думайте о срезе как о структуре значений со скрытым полем указателя, чтобы система могла найти и получить доступ ко всему или части массива (среза), а также к полям для длины и емкости среза, к которым вы можете получить доступ, используяlen()
иcap()
функции ,Вот вам рабочий стартовый комплект, который читает и печатает двоичный файл; вам нужно изменить
inName
буквальное значение, чтобы ссылаться на небольшой файл в вашей системе.источник
if
блокаПопробуй это:
источник
Просто просматривая документацию, кажется, что вы должны просто объявить буфер типа [] byte и передать его для чтения, который затем прочитает до такого количества символов и вернет количество фактически прочитанных символов (и ошибку).
Документы говорят
Это не работает?
РЕДАКТИРОВАТЬ: Кроме того, я думаю, что вы, возможно, следует использовать интерфейсы Reader / Writer, объявленные в пакете bufio , вместо использования пакета os .
источник
Метод Read принимает параметр байта, потому что это буфер, в который он будет читать. Это распространенная идиома в некоторых кругах, и она имеет смысл, когда вы думаете об этом.
Таким образом, вы можете определить, сколько байтов будет прочитано читателем, и просмотреть возвращаемый результат, чтобы увидеть, сколько фактически было прочитано байтов, и соответствующим образом обработать любые ошибки.
Как указали другие в своих ответах, bufio - это, вероятно, то, что вы хотите прочитать из большинства файлов.
Я добавлю еще одну подсказку, поскольку она действительно полезна. Чтение строки из файла лучше всего выполнять не методом ReadLine, а методом ReadBytes или ReadString.
источник