file - gratis - ¿Cómo leer/escribir desde/a un archivo usando Go?
files go para pc (8)
Con las nuevas versiones de Go, leer / escribir en / desde un archivo es fácil. Para leer de un archivo:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("text.txt")
if err != nil {
return
}
fmt.Println(string(data))
}
Para escribir en un archivo:
package main
import "os"
func main() {
file, err := os.Create("text.txt")
if err != nil {
return
}
defer file.Close()
file.WriteString("test/nhello")
}
Esto sobrescribirá el contenido de un archivo (cree un archivo nuevo si no estaba allí).
He estado tratando de aprender Ve por mi cuenta, pero me he quedado perplejo al intentar leer y escribir en archivos normales.
Puedo llegar hasta inFile, _ := os.Open(INFILE, 0, 0)
, pero realmente no tiene sentido obtener el contenido del archivo, porque la función de lectura toma un []byte
como parámetro.
func (file *File) Read(b []byte) (n int, err Error)
El método de lectura toma un parámetro de byte porque ese es el búfer en el que leerá. Es un idioma común en algunos círculos y tiene sentido cuando piensas en ello.
De esta manera, puede determinar cuántos bytes leerá el lector e inspeccionar la devolución para ver cuántos bytes realmente se leyeron y manejar los errores de manera adecuada.
Como otros han señalado en sus respuestas, bufio es probablemente lo que quieres para leer desde la mayoría de los archivos.
Agregaré otra pista ya que es realmente útil. La lectura de una línea de un archivo se logra mejor no con el método ReadLine sino con el método ReadBytes o ReadString.
Esta es una buena versión:
package main
import (
"io/ioutil";
)
func main() {
contents,_ := ioutil.ReadFile("plikTekstowy.txt")
println(string(contents))
ioutil.WriteFile("filename", contents, 0644)
}
Hagamos una lista compatible con Go 1 de todas las formas de leer y escribir archivos en Go.
Debido a que la API de archivos ha cambiado recientemente y la mayoría de las otras respuestas no funcionan con Go 1. También se pierden bufio
cual es IMHO importante.
En los siguientes ejemplos copio un archivo al leerlo y escribirlo 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 de os.OpenFile
. Generalmente no necesitamos llamar a OpenFile
directamente.
Aviso de tratamiento de EOF. Read
intenta llenar buf
en cada llamada y devuelve io.EOF
como error si llega al final del archivo al hacerlo. En este caso buf
todavía conservará los datos. Las llamadas io.EOF
a Read
devuelven cero como el número de bytes leídos y la misma io.EOF
como error. Cualquier otro error dará lugar a un pánico.
Usando 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
está actuando como un búfer aquí, porque no tenemos mucho que ver con los datos. En la mayoría de las demás situaciones (especialmente con archivos de texto), bufio
es muy útil porque nos bufio
una buena API para leer y escribir de manera fácil y flexible, mientras maneja el almacenamiento en búfer entre bastidores.
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.
Prueba esto:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
Solo mirando la documentación, parece que debería declarar un búfer de tipo [] byte y pasarlo a lectura, que luego leerá hasta tantos caracteres y devolverá el número de caracteres realmente leídos (y un error).
Los docs dicen
Leer lee hasta len (b) bytes del archivo. Devuelve el número de bytes leídos y un error, si lo hubiera. EOF se señala mediante un conteo de cero con err establecido en EOF.
¿Eso no funciona?
EDITAR: También, creo que debería usar las interfaces de Reader / Writer declaradas en el paquete bufio en lugar de usar el paquete os .
[]byte
es una porción (similar a una subcadena) de todo o parte de una matriz de bytes. Piense en la división como una estructura de valor con un campo de puntero oculto para que el sistema localice y acceda a la totalidad o parte de una matriz (la división), más campos para la longitud y la capacidad de la división, a la que puede acceder usando la len()
y funciones cap()
.
Aquí hay un kit de inicio que funciona para usted, que lee e imprime un archivo binario; deberá cambiar el valor literal de inName
para referirse a un archivo pequeño en su sistema.
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();
}
Usando 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)
}
Si no tienes ganas de reinventar la rueda, io.Copy
y io.CopyN
pueden servir bien. Si verifica la fuente 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 búfer significativamente más grande que él.