Golang文件处理方法详解

Golang文件处理方法详解 如何在Go语言中以映射(map)的形式对文件进行读写操作?例如:如果 f 是一个文件结构体类型的对象,那么我该如何实现 f.write("key", "value") 这样的方法,使得 fmt.Println(f.read("key")) 能够输出对应的值?

func main() {
    fmt.Println("hello world")
}
3 回复

嗯,你应该在最初的帖子中就包含这些信息。这看起来像是一个练习题。你尝试过哪些解决方法?它有效吗?

顺便说一下:请使用编辑区域顶部的 < /> 按钮来缩进代码。目前代码非常难以阅读。

更多关于Golang文件处理方法详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


标准库中没有提供此功能的类型。但你可以使用一个简单的库,例如 github.com/magiconair/properties

package main

import (
	"fmt"
	"io/ioutil"
	"log"

	// https://pkg.go.dev/github.com/magiconair/properties?
	"github.com/magiconair/properties"
)

func main() {
	// 声明一个 properties 实例并放入一些值。
	p := properties.NewProperties()
	p.Set("key1", "value1")
	p.Set("key2", "value2")

	// 打开一个临时文件。
	tmpfile, err := ioutil.TempFile("", "*.properties")
	if err != nil {
		log.Panic(err)
	}

	// 记住文件名。
	fn := tmpfile.Name()

	// 将属性写入文件。
	_, err = p.Write(tmpfile, properties.UTF8)
	if err != nil {
		log.Panic(err)
	}

	err = tmpfile.Close()
	if err != nil {
		log.Panic(err)
	}

	// 现在重新读入属性。
	q := properties.MustLoadFile(fn, properties.UTF8)

	// 并打印其中一个已使用键的值。
	v, ok := q.Get("key1")
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("key1 missing")
	}
}

在Go语言中,可以通过自定义类型和结构体方法来实现以映射形式读写文件的功能。以下是一个完整的示例:

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"sync"
)

// FileMap 自定义文件映射类型
type FileMap struct {
	filePath string
	data     map[string]string
	mu       sync.RWMutex
}

// NewFileMap 创建新的FileMap实例
func NewFileMap(filePath string) (*FileMap, error) {
	fm := &FileMap{
		filePath: filePath,
		data:     make(map[string]string),
	}
	
	// 加载现有数据
	if err := fm.load(); err != nil && !os.IsNotExist(err) {
		return nil, err
	}
	
	return fm, nil
}

// Write 写入键值对
func (fm *FileMap) Write(key, value string) error {
	fm.mu.Lock()
	defer fm.mu.Unlock()
	
	fm.data[key] = value
	return fm.save()
}

// Read 读取键对应的值
func (fm *FileMap) Read(key string) (string, bool) {
	fm.mu.RLock()
	defer fm.mu.RUnlock()
	
	value, exists := fm.data[key]
	return value, exists
}

// load 从文件加载数据
func (fm *FileMap) load() error {
	file, err := os.Open(fm.filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	
	decoder := json.NewDecoder(file)
	return decoder.Decode(&fm.data)
}

// save 保存数据到文件
func (fm *FileMap) save() error {
	file, err := os.Create(fm.filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	
	encoder := json.NewEncoder(file)
	encoder.SetIndent("", "  ")
	return encoder.Encode(fm.data)
}

// Delete 删除键值对
func (fm *FileMap) Delete(key string) error {
	fm.mu.Lock()
	defer fm.mu.Unlock()
	
	delete(fm.data, key)
	return fm.save()
}

// GetAll 获取所有键值对
func (fm *FileMap) GetAll() map[string]string {
	fm.mu.RLock()
	defer fm.mu.RUnlock()
	
	copied := make(map[string]string)
	for k, v := range fm.data {
		copied[k] = v
	}
	return copied
}

func main() {
	// 创建FileMap实例
	fm, err := NewFileMap("data.json")
	if err != nil {
		fmt.Printf("创建FileMap失败: %v\n", err)
		return
	}
	
	// 写入数据
	err = fm.Write("name", "Alice")
	if err != nil {
		fmt.Printf("写入失败: %v\n", err)
	}
	
	err = fm.Write("age", "30")
	if err != nil {
		fmt.Printf("写入失败: %v\n", err)
	}
	
	// 读取数据
	if value, exists := fm.Read("name"); exists {
		fmt.Printf("f.read(\"name\") = %s\n", value)
	}
	
	if value, exists := fm.Read("age"); exists {
		fmt.Printf("f.read(\"age\") = %s\n", value)
	}
	
	// 读取不存在的键
	if value, exists := fm.Read("nonexistent"); exists {
		fmt.Println(value)
	} else {
		fmt.Println("键不存在")
	}
	
	// 获取所有数据
	allData := fm.GetAll()
	fmt.Printf("所有数据: %v\n", allData)
}

如果需要更简单的文本格式(非JSON),可以使用以下实现:

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"sync"
)

type TextFileMap struct {
	filePath string
	mu       sync.RWMutex
}

func NewTextFileMap(filePath string) *TextFileMap {
	return &TextFileMap{filePath: filePath}
}

func (tfm *TextFileMap) Write(key, value string) error {
	tfm.mu.Lock()
	defer tfm.mu.Unlock()
	
	// 读取现有数据
	data, err := tfm.readAll()
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	
	// 更新数据
	data[key] = value
	
	// 写回文件
	return tfm.writeAll(data)
}

func (tfm *TextFileMap) Read(key string) (string, bool) {
	tfm.mu.RLock()
	defer tfm.mu.RUnlock()
	
	data, err := tfm.readAll()
	if err != nil {
		return "", false
	}
	
	value, exists := data[key]
	return value, exists
}

func (tfm *TextFileMap) readAll() (map[string]string, error) {
	file, err := os.Open(tfm.filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	
	data := make(map[string]string)
	scanner := bufio.NewScanner(file)
	
	for scanner.Scan() {
		line := scanner.Text()
		parts := strings.SplitN(line, "=", 2)
		if len(parts) == 2 {
			data[parts[0]] = parts[1]
		}
	}
	
	return data, scanner.Err()
}

func (tfm *TextFileMap) writeAll(data map[string]string) error {
	file, err := os.Create(tfm.filePath)
	if err != nil {
		return err
	}
	defer file.Close()
	
	writer := bufio.NewWriter(file)
	for key, value := range data {
		_, err := writer.WriteString(fmt.Sprintf("%s=%s\n", key, value))
		if err != nil {
			return err
		}
	}
	return writer.Flush()
}

func main() {
	f := NewTextFileMap("data.txt")
	
	// 写入数据
	f.Write("language", "Golang")
	f.Write("version", "1.21")
	
	// 读取数据
	if value, exists := f.Read("language"); exists {
		fmt.Printf("f.read(\"language\") = %s\n", value)
	}
	
	if value, exists := f.Read("version"); exists {
		fmt.Printf("f.read(\"version\") = %s\n", value)
	}
}

这两个示例分别展示了使用JSON格式和文本格式实现文件映射读写的方法。FileMap类型提供了WriteRead方法,完全符合你描述的使用方式。

回到顶部