Podstawowe operacje na plikach
W bibliotece standardowej nie ma zbyt wielu funkcji skrótowych do pracy na plikach, ale same "niskie" funkcje nie są szczególnie skomplikowane i czasem warto mieć pod kontrolą każdy aspekt otwierania pliku. Przybliżę podstawowe operacje na plikach, które możesz replikować gdzie ci się żywnie podoba.
Podstawowe operacje na plikach to:
- tworzenie plików
- otwieranie plików
- czytanie zawartości plików
- pisanie do pliku
- zamykanie pliku
Otwieranie i czytanie plików
Do zwykłego wczytania całej zawartości pliku polecam io/ioutils.ReadFile.
Jeśli potrzebujesz wczytywać fragmenty, to lepiej sprawdzi się os.Open.
Wszystkie możliwe operacje na plikach można wykonać za pomocą os.OpenFile, której
zastosowanie znajdziesz w ostatniej sekcji.
io/ioutils.ReadFile
Link do specyfikacji.
Sygnatura func ReadFile(filename string) ([]byte, os.Error), wymaga podania
nazwy pliku (jego ścieżki), a zwraca wycinek bajtów i wartość spełniającą
interfejs os.Error.
Jako przykład zastosowania niech służy program czytający zawartość pliku i wyprowadzający go na ekran
package main import ( "io/ioutil" "os" "fmt" ) func main() { arguments := os.Args if len(arguments) < 2 { fmt.Println("Podaj nazwę pliku który chcesz wczytać") os.Exit(1) } filename := arguments[1] fcontents, err := ioutil.ReadFile(filename) if err != nil { fmt.Printf("Błąd wczytywania pliku %v \n", filename) os.Exit(1) } os.Stdout.Write(fcontents) //dodajmy kończącą nową linię os.Stdout.Write([]byte("\n")) }
os.Open
os.Open zwróci wartość typu *os.File, dzięki której możemy manipulować
danymi pliku, zaś on sam zostanie otwarty tylko do odczytu.
Jako przykład napiszemy funkcję, która zwraca wartość []string, której
elementy odpowiadają pojedynczym liniom pliku tekstowego.
func ReadLines(filename string) (lines []string, err os.Error) { file, err := os.Open(filename) if err != nil { return } reader := bufio.NewReader(file) for bline, e := reader.ReadBytes('\n'); e == nil; bline, e = reader.ReadBytes('\n') { lines = append(lines, string(bline)) } return }
Tworzenie i zapisywanie plików
Plik można stworzyć za pośrednictwem czterech różniących się funkcji.
os.Create
Link do specyfikacji
Sygnatura funkcji func Create(name string) (file *File, err Error), mówi nam
że parametrem ma być nazwa pliku (ścieżka do pliku), a zwrócone zostaną wskaźnik
na wartość typu os.File i wartość spełniająca interfejs os.Error.
Wywołanie tej funkcji zaowocuje stworzeniem pliku i ustawieniem jego praw na
0666, czyli do odczytu i zapisu dla wszystkich. W przypadku gdy wskazany plik
już istniał zostanie on opróżniony. os.Create zapewnia nas, że plik będzie
pusty i gotowy do zapisu i ewentualnego odczytu.
Prosty przykład, w którym utworzymy plik, zapiszemy w nim ciąg znaków i wczytamy jego zawartość i wyświetlimy na ekranie: main.go
package main import ( "fmt" "os" ) func main() { contents := "Zawartość pliku otworzonego funkcją os.Create" filename := "oscreate.test" file, err := os.Create() defer file.Close()//zamknij plik tuż po wyjściu z funkcji if err != nil { fmt.Println("Błąd tworzenia pliku", err) os.Exit(1) } _, werr := file.Write([]byte(contents)) if werr != nil { fmt.Println("Błąd zapisywania do pliku", werr) os.Exit(1) } _, serr := file.Seek(0, 0) //przesuwamy wewnętrzny kursor pliku na jego początek if serr != nil { fmt.Println("Błąd przesuwania kursora pliku", werr) os.Exit(1) } buf := make([]byte, len(contents) + 1) file.Read(buf) fmt.Println(string(buf)) os.Exit(0) }
io/ioutil.WriteFile
ioutil.WriteFile to funkcja przeznaczona tylko i wyłącznie do zapisywania
określonego bufora danych do pliku, jej przewaga nad os.Create, polega na tym
że można określić jaki ma być poziom dostępu do pliku, no i nie trzeba operować
na obiekcie typu *os.File.
Sygnatura tej funkcji wygląda następująco: func WriteFile(filename string, data []byte, perm uint32) os.Error.
Jako parametry przyjmuje nazwę (ścieżkę), ciąg bajtów do zapisania i
poziom uprawnień do tworzonego pliku. Zwraca wartość typu os.Error, która jest
nilem jeśli nie było żadnego, błędu.
@see{error handling}
Przykład będzie skromniejszy niż poprzedni, gdyż nie możemy manipulować wartością
typu os.File, bo jej nie otrzymujemy.
package main import ( "fmt" "io/ioutil" "os" ) func main() { contents := "Zawartość pliku otworzonego funkcją ioutil.WriteFile" filename := "oscreate.test" err := ioutil.WriteFile(filename , []byte(contents), 0666) if err != nil { fmt.Println("Błąd tworzenia pliku", err) os.Exit(1) } fmt.Println("wszystko poszło jak należy") os.Exit(0) }
io/ioutil.TempFile
Link do specyfikacji
Ta funkcja pozwoli nam na utworzenie pliku tymczasowego o unikalnej nazwie we
wskazanym katalogu.
Sygnatura func TempFile(dir, prefix string) (f *os.File, err os.Error), czyli
musimy wskazać katalog docelowy i prefix nazwy pliku. Funkcja sama dobierze
unikalną nazwę którą możemy uzyskać wywołując metodę f.Name() na wartości
typu os.File.
io/ioutil.TempFile nie dostarcza mechanizmów do automatycznego usuwania plików
tymczasowych, program sam musi zadbać o sprzątanie po sobie
Przykład:
package main import ( "fmt" "io/ioutil" "os" ) func main() { contents := "Zawartość pliku otworzonego funkcją ioutil.WriteFile" fileprefix := "tmpfile" dir := "./" file, err := ioutil.TempFile(dir, filename) if err != nil { fmt.Println("Błąd tworzenia pliku", err) os.Exit(1) } fmt.Println("Plik utworzony i otwarty") file.Write([]byte(contents)) os.Exit(0) }
os.OpenFile
To najbardziej ogólna z funkcji otwierających plik, dzięki odpowiedniemu doborowi przełączników możemy także tworzyć nowe pliki. We wcześniejszych przykładach wszystkie funkcje, albo tworzyły puste pliki albo czyściły już istniejące w trakcie wywołania. Pokażę jak otwierać i tworzyć pliki do których chcemy dopisywać dane, przydatne przy pisaniu logów.
package main import ( "os" "fmt" ) func OpenAppendOnlyFile(name string) (*os.File, os.Error) { openflags := os.O_APPEND|os.O_CREATE|os.O_WRONLY fileperm := 0755 return os.OpenFile(name, openflags, fileperm ) } func main() { file, err := OpenAppendOnlyFile("new.log") if err != nil { fmt.Println("Błąd otwierania pliku", err) os.Exit(1) } n, err := file.Write([]byte("jeden\n")) if err != nil { fmt.Println("Błąd zapisu", err) os.Exit(1) } fmt.Println("zapisano", n, "bytesów"); defer file.Close() }
Wszystko o języku programowania Go