Hagamos una lista compatible con Go 1 de todas las formas de leer y escribir archivos en Go.
Debido a que la API de archivo ha cambiado recientemente y la mayoría de las otras respuestas no funcionan con Go 1. También omiten lo bufio
que es importante en mi humilde opinión.
En los siguientes ejemplos, copio un archivo leyéndolo y escribiendo en el archivo de destino.
Comience con lo básico
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)
}
}
}
Aquí utilicé os.Open
y os.Create
que son envoltorios convenientes alrededor os.OpenFile
. Por lo general, no necesitamos llamar OpenFile
directamente.
Aviso de tratamiento de EOF. Read
intenta completar buf
cada llamada y devuelve un io.EOF
error si llega al final del archivo al hacerlo. En este caso buf
aún se conservarán los datos. Las llamadas consiguientes a Read
devuelve cero como el número de bytes leídos e igual io.EOF
que el error. Cualquier otro error provocará pánico.
Utilizando 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
solo está actuando como un búfer aquí, porque no tenemos mucho que ver con los datos. En la mayoría de las otras situaciones (especialmente con archivos de texto) bufio
es muy útil al proporcionarnos una buena API para leer y escribir de manera fácil y flexible, mientras maneja el almacenamiento en búfer detrás de escena.
Utilizando 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)
}
}
¡Muy fácil! Pero úselo solo si está seguro de que no está tratando con archivos grandes.
panic("error in writing")
) no es necesaria.Esta es una buena versión:
fuente
0x777
es falso. En cualquier caso, debería ser más como0644
o0755
(octal, no hexadecimal).Utilizando
io.Copy
Si no tiene ganas de reinventar la rueda, el
io.Copy
yio.CopyN
puede servir bien. Si verifica el origen de la función io.Copy, no es más que una de las soluciones de Mostafa (la 'básica', en realidad) empaquetada en la biblioteca Go. Sin embargo, están usando un buffer significativamente más grande que él.fuente
w.Sync()
después de laio.Copy(w, r)
io.Copy()
solo escribirá los datos con los que lo alimente, por lo que si el archivo existente tenía más contenido, no se eliminará, lo que puede provocar un archivo dañado.w, err := os.Create("output.txt")
, lo que describe no sucede porque "Crear crea o trunca el archivo con nombre. Si el archivo ya existe, se trunca". golang.org/pkg/os/#Create .Con las versiones más nuevas de Go, leer / escribir en / desde el archivo es fácil. Para leer de un archivo:
Para escribir en un archivo:
Esto sobrescribirá el contenido de un archivo (cree un nuevo archivo si no estaba allí).
fuente
[]byte
es un segmento (similar a una subcadena) de todo o parte de una matriz de bytes. Piense en el segmento como una estructura de valores con un campo de puntero oculto para que el sistema ubique y acceda a todo o parte de una matriz (el segmento), más campos para la longitud y la capacidad del segmento, a los que puede acceder utilizando las funcioneslen()
ycap()
.Aquí hay un kit de inicio que funciona para usted, que lee e imprime un archivo binario; necesitará cambiar el
inName
valor literal para referirse a un pequeño archivo en su sistema.fuente
if
bloquePrueba esto:
fuente
Simplemente mirando la documentación, parece que debería declarar un búfer de tipo [] byte y pasarlo a leer que luego leerá hasta tantos caracteres y devolverá el número de caracteres realmente leídos (y un error).
Los documentos dicen
¿Eso no funciona?
EDITAR: Además, creo que quizás debería usar las interfaces Reader / Writer declaradas en el paquete bufio en lugar de usar el paquete os .
fuente
El método de lectura toma un parámetro de byte porque es el búfer en el que leerá. Es un idioma común en algunos círculos y tiene sentido cuando lo piensas.
De esta manera, puede determinar cuántos bytes leerá el lector e inspeccionar el retorno para ver cuántos bytes se leyeron realmente y manejar los errores de manera adecuada.
Como otros han señalado en sus respuestas, bufio es probablemente lo que desea leer de la mayoría de los archivos.
Agregaré otra pista ya que es realmente útil. La mejor forma de leer una línea de un archivo no es mediante el método ReadLine, sino el método ReadBytes o ReadString.
fuente