1. go
  2. /standard library
  3. /files

Working with Files in Go

Go provides robust file handling capabilities through the os and io/ioutil packages. This guide covers common file operations and best practices.

Basic File Operations

Opening and Closing Files

func openFile() error {
    // Open file for reading
    file, err := os.Open("input.txt")
    if err != nil {
        return fmt.Errorf("opening file: %w", err)
    }
    defer file.Close()

    // Open file for writing
    writeFile, err := os.Create("output.txt")
    if err != nil {
        return fmt.Errorf("creating file: %w", err)
    }
    defer writeFile.Close()

    return nil
}

Reading Files

// Read entire file
func readEntireFile(filename string) ([]byte, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        return nil, fmt.Errorf("reading file: %w", err)
    }
    return data, nil
}

// Read file line by line
func readLines(filename string) error {
    file, err := os.Open(filename)
    if err != nil {
        return fmt.Errorf("opening file: %w", err)
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        line := scanner.Text()
        // Process line
        fmt.Println(line)
    }

    return scanner.Err()
}

Writing Files

// Write entire file
func writeFile(filename string, data []byte) error {
    err := os.WriteFile(filename, data, 0644)
    if err != nil {
        return fmt.Errorf("writing file: %w", err)
    }
    return nil
}

// Write file line by line
func writeLines(filename string, lines []string) error {
    file, err := os.Create(filename)
    if err != nil {
        return fmt.Errorf("creating file: %w", err)
    }
    defer file.Close()

    writer := bufio.NewWriter(file)
    for _, line := range lines {
        _, err := writer.WriteString(line + "\n")
        if err != nil {
            return fmt.Errorf("writing line: %w", err)
        }
    }

    return writer.Flush()
}

File Information

Getting File Info

func getFileInfo(filename string) error {
    info, err := os.Stat(filename)
    if err != nil {
        if os.IsNotExist(err) {
            return fmt.Errorf("file does not exist: %w", err)
        }
        return fmt.Errorf("getting file info: %w", err)
    }

    fmt.Printf("Name: %s\n", info.Name())
    fmt.Printf("Size: %d bytes\n", info.Size())
    fmt.Printf("Mode: %s\n", info.Mode())
    fmt.Printf("Modified: %s\n", info.ModTime())
    fmt.Printf("Is Directory: %t\n", info.IsDir())

    return nil
}

Checking File Existence

func fileExists(filename string) bool {
    _, err := os.Stat(filename)
    return !os.IsNotExist(err)
}

Directory Operations

Creating Directories

func createDirs() error {
    // Create single directory
    err := os.Mkdir("newdir", 0755)
    if err != nil {
        return fmt.Errorf("creating directory: %w", err)
    }

    // Create directory with parents
    err = os.MkdirAll("path/to/nested/dir", 0755)
    if err != nil {
        return fmt.Errorf("creating nested directories: %w", err)
    }

    return nil
}

Reading Directory Contents

func listDirectory(path string) error {
    entries, err := os.ReadDir(path)
    if err != nil {
        return fmt.Errorf("reading directory: %w", err)
    }

    for _, entry := range entries {
        info, err := entry.Info()
        if err != nil {
            return fmt.Errorf("getting entry info: %w", err)
        }

        fmt.Printf("Name: %s, Size: %d, IsDir: %t\n",
            info.Name(), info.Size(), info.IsDir())
    }

    return nil
}

File Permissions

Setting Permissions

func setPermissions(filename string) error {
    // Set file permissions (read/write for owner, read for others)
    err := os.Chmod(filename, 0644)
    if err != nil {
        return fmt.Errorf("setting permissions: %w", err)
    }

    return nil
}

Changing Ownership

func changeOwnership(filename string) error {
    // Change file owner and group
    err := os.Chown(filename, uid, gid)
    if err != nil {
        return fmt.Errorf("changing ownership: %w", err)
    }

    return nil
}

Best Practices

  1. Always Close Files

    file, err := os.Open("file.txt")
    if err != nil {
        return err
    }
    defer file.Close()
    
  2. Use Buffered IO for Performance

    file, err := os.Create("large-file.txt")
    if err != nil {
        return err
    }
    defer file.Close()
    
    writer := bufio.NewWriter(file)
    defer writer.Flush()
    
  3. Handle Temporary Files

    tempFile, err := os.CreateTemp("", "prefix-*.txt")
    if err != nil {
        return err
    }
    defer os.Remove(tempFile.Name())
    defer tempFile.Close()
    
  4. Check File Size Before Reading

    func readIfNotTooLarge(filename string, maxSize int64) ([]byte, error) {
        info, err := os.Stat(filename)
        if err != nil {
            return nil, err
        }
        if info.Size() > maxSize {
            return nil, fmt.Errorf("file too large")
        }
        return os.ReadFile(filename)
    }
    

Next Steps