实现BuffereFileWriter| 青训营

96 阅读5分钟

实现BuffereFileWriter

分析

想要实现此功能

1、首先,需要一个结构体BuffereFIleWriter,用于保存缓冲区的数据和文件句柄。

2、在结构体中,我们需要定义一个缓冲区数组和一个文件句柄指针。

3、接着,我们需要实现一个构造函数 NewBufferedFileWriter,它接受一个文件句柄作为参数,并返回一个 BufferedFileWriter 的指针。

4、在构造函数中,我们需要初始化结构体的字段,包括缓冲区和文件句柄。

5、接下来,我们需要实现 Write 方法,用于将数据写入缓冲区。

6、在 Write 方法中,我们需要判断数据是否超过缓冲区的大小,如果超过,则直接将数据写入文件;如果没有超过,则将数据复制到缓冲区,并更新缓冲区的位置。

7、我们还需要实现一个 Flush 方法,用于将缓冲区中的数据写入文件并清空缓冲区。

8、转换,让string类型的都可以写入。字符串转切片函数WriteString

9、最后,我们可以编写一个测试函数,调用 NewBufferedFileWriter 创建一个 BufferedFileWriter,并使用 Write 方法写入数据,然后调用 Flush 方法将数据写入文件。

那我们来实践一下步骤吧。

创建结构体 BufferedFileWriter

我们需要一个结构体来保存缓冲区的数据和文件句柄

type BufferedFileWriter struct {
    //定义字段  ,缓冲区数组   以及文件指针
    buffer      [1024]byte
    endPos      int // 已写入缓冲区的数据长度
    fileHandler *os.File
}

讲解: 在这一步,我们创建了一个结构体 BufferedFileWriter

它包含了一个大小为 1024 的字节数组作为缓冲区,一个记录已写入缓冲区数据长度的字段 endPos,以及一个指向文件句柄的指针 fileHandler

实现构造函数 NewBufferedFileWriter

描述: 我们需要实现一个构造函数,该函数接受一个文件句柄作为参数,并返回一个 BufferedFileWriter 的实例。

//创建构造函数
func NewBufferedFileWriter(fd *os.File) *BufferedFileWriter {
    //初始化字段
    return &BufferedFileWriter{
        fileHandler: fd,
    }
}

讲解: 在这一步,我们定义了一个构造函数 NewBufferedFileWriter

它接受一个文件句柄 fd 作为参数,并返回一个新的 BufferedFileWriter 实例,初始化其中的 fileHandler 字段为传入的文件句柄。

实现 Write 方法

描述: 我们需要实现一个 Write 方法,用于将数据写入缓冲区。如果数据大小超过缓冲区大小,则直接写入文件;否则,将数据复制到缓冲区并更新位置。

//第五步实现writer方法
func (writer *BufferedFileWriter) Write(content []byte) {
// 有点意思是结构体的方法前面的括号就是 哪个类型的结构体

   //判断缓冲区大小
   if len(content) >= 1024 {
        writer.fileHandler.Write(content)
    } else {
        if writer.endPos+len(content) >= 1024 {
            writer.Flush()
            writer.Write(content)
        } else {
            copy(writer.buffer[writer.endPos:], content)
            writer.endPos += len(content)
        }
    }
}

讲解: 在这一步,我们实现了 Write 方法。

首先,我们检查传入的数据是否超过缓冲区大小,如果超过,则直接写入文件。

如果没有超过,我们检查是否将数据写入缓冲区后,缓冲区已满,如果已满则调用 Flush 方法,然后递归调用 Write 方法。

否则,我们使用 copy 函数将数据复制到缓冲区中,并更新 endPos

实现 Flush 方法

描述: 我们需要实现一个 Flush 方法,用于将缓冲区中的数据写入文件并清空缓冲区。

//创建Flush用于 将缓冲区写入文件
func (writer *BufferedFileWriter) Flush() {
    if writer.endPos > 0 {
        writer.fileHandler.Write(writer.buffer[0:writer.endPos])
        // 这个数组[:] 加 " : "  是把数组转化为切片  // 真正写入磁盘
        writer.endPos = 0
    }
}

讲解: 在这一步,我们实现了 Flush 方法。如果缓冲区中有数据(endPos > 0),我们将缓冲区中的数据写入文件,然后清空缓冲区并将 endPos 重置为0。

实现 WriteString 方法

描述: 我们实现一个 WriteString 方法,该方法将字符串转换为切片,并调用 Write 方法进行写入。

//字符串转为切片
func (writer *BufferedFileWriter) WriteString(content string) {
    writer.Write([]byte(content))
}

讲解: 在这一步,我们实现了 WriteString 方法,它将输入的字符串转换为字节数组,并调用已实现的 Write 方法进行写入。

编写测试函数

描述: 最后,我们可以编写一个测试函数,以验证 BufferedFileWriter 是否正常工作。在测试函数中,我们创建一个文件句柄,使用 NewBufferedFileWriter 创建一个 BufferedFileWriter 实例,多次使用 WriteString 方法写入数据,最后使用 Flush 方法将数据写入文件。

//编写测试函数
func testBufferWriter() {
    fout, err := os.OpenFile("output.txt", os.O_CREATE|os.O_TRUNC, os.ModePerm)
    if err != nil {
        return
    }
    defer fout.Close()

    writer := NewBufferedFileWriter(fout)
    for i := 0; i < 500; i++ {
        writer.WriteString("0123456789\n")
    }
    writer.Flush()
}

讲解: 在这一步,我们编写了一个名为 testBufferWriter 的测试函数。

在该函数中,我们创建一个文件句柄,使用 NewBufferedFileWriter 创建一个 BufferedFileWriter 实例,并使用 WriteString 方法多次写入数据。

最后,我们使用 Flush 方法将剩余的数据写入文件。这个测试函数可以验证 BufferedFileWriter 是否正常工作,能够高效地写入大量数据。

总结

到这里,我们已经成功地实现了一个缓冲文件写入的功能。这个 BufferedFileWriter 结构体可以在写入大量数据时提高性能,减少频繁的磁盘写入操作,从而更加高效地操作文件。

完整代码实现

package main

import (
	"fmt"
	"os"
)

// 第一步创建结构体
type BufferedFileWriter struct {
    
   // 第二部定义字段  ,缓冲区数组   以及文件指针
	buffer      [1024]byte
	endPos      int //已写入缓冲区的数据长度
	fileHandler *os.File
}

// 第三步创建构造函数
func NewBufferedFileWriter(fd *os.File) *BufferedFileWriter {
    
    // 第四步  初始化字段
	return &BufferedFileWriter{
		fileHandler: fd,
	}
}


// 第七步  创建Flush用于 将缓冲区写入文件
func (writer *BufferedFileWriter) Flush() {
	if writer.endPos > 0 {
		writer.fileHandler.Write(writer.buffer[0:writer.endPos]) // 这个数组[:] 加 " : "  是把数组转化为切片
		fmt.Println("真正写入磁盘")
		writer.endPos = 0
	}

}

// 第五步实现writer方法
func (writer *BufferedFileWriter) Write(content []byte) { // 有点意思是结构体的方法前面的括号就是 哪个类型的结构体
    
    // 第六步判断缓冲区大小
	if len(content) >= 1024 {
		writer.fileHandler.Write(content)
	} else {
		if writer.endPos+len(content) >= 1024 {
			writer.Flush()
			writer.Write(content)
		} else {
			copy(writer.buffer[writer.endPos:], content)
			writer.endPos += len(content)
		}
	}
    
}

//  第八步  字符串转为切片
func (writer *BufferedFileWriter) WriteString(content string) {
	writer.Write([]byte(content))
}

// 第九步编写测试函数
func testBufferWriter() {
	fout, err := os.OpenFile("zcy.txt", os.O_CREATE|os.O_TRUNC, os.ModePerm)
	if err != nil {
		return
	}
	defer fout.Close()

	writer := NewBufferedFileWriter(fout)
	for i := 0; i < 500; i++ {
		writer.WriteString("0123456789\n")
	}
	
    
}