go-特性5

文件的copy与文件的读写

应用场景

上传下载文件

  • 标准库 net/http 提供了处理HTTP请求的功能,可以用于文件上传和下载的服务端和客户端实现。
  • 第三方库 github.com/gin-gonic/gin 提供了一个高性能的HTTP框架,可以用于快速搭建RESTful API服务,支持文件上传和下载。
    以下是一个简单的示例,展示了如何使用Go语言编写一个HTTP服务器,使其能够接收文件上传,并且如何使用Go语言编写一个HTTP客户端,实现文件下载功能。
bash 复制代码
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	// 解析表单
	err := r.ParseMultipartForm(10 << 20) // 限制上传文件大小为 10MB
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// 获取上传的文件
	file, handler, err := r.FormFile("file")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer file.Close()

	// 创建目标文件
	dst, err := os.Create(handler.Filename)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer dst.Close()

	// 将上传的文件内容复制到目标文件
	_, err = io.Copy(dst, file)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "File %s uploaded successfully!", handler.Filename)
}

func main() {
	http.HandleFunc("/upload", uploadHandler)
	fmt.Println("Server is listening on port 8080...")
	http.ListenAndServe(":8080", nil)
}
bash 复制代码
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func downloadFile(url, filePath string) error {
	// 发送HTTP GET请求
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// 创建目标文件
	out, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer out.Close()

	// 将HTTP响应体复制到目标文件
	_, err = io.Copy(out, resp.Body)
	if err != nil {
		return err
	}

	fmt.Println("File downloaded successfully!")
	return nil
}

func main() {
	url := "http://example.com/file.zip" // 替换为要下载的文件的URL
	filePath := "downloaded_file.zip"     // 下载后的文件路径

	err := downloadFile(url, filePath)
	if err != nil {
		fmt.Println("Error downloading file:", err)
	}
}

大文件分片传输

大文件分片传输通常用于在网络上传输大文件时,将文件分成多个较小的片段进行传输,以减少单个请求的负载,并允许在传输过程中进行断点续传。

可以使用标准库或第三方库实现大文件的分片上传和下载,通过多个HTTP请求分别传输文件的不同部分,然后在服务端和客户端进行合并。

bash 复制代码
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

const chunkSize = 1 << 20 // 每个分片的大小为 1MB

func uploadHandler(w http.ResponseWriter, r *http.Request) {
	// 解析表单
	err := r.ParseMultipartForm(10 << 20) // 限制上传文件大小为 10MB
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// 获取上传的文件
	file, handler, err := r.FormFile("file")
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer file.Close()

	// 创建目标文件
	dst, err := os.Create(handler.Filename)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	defer dst.Close()

	// 逐个分片写入文件
	for {
		chunk := make([]byte, chunkSize)
		n, err := file.Read(chunk)
		if err != nil && err != io.EOF {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if n == 0 {
			break
		}
		dst.Write(chunk[:n])
	}

	fmt.Fprintf(w, "File %s uploaded successfully!", handler.Filename)
}

func main() {
	http.HandleFunc("/upload", uploadHandler)
	fmt.Println("Server is listening on port 8080...")
	http.ListenAndServe(":8080", nil)
}

文件移动

  • 标准库 os 提供了文件操作相关的功能,包括文件的移动、复制、删除等操作。
  • 第三方库 github.com/spf13/afero 提供了一个抽象文件系统的接口,可以方便地对文件进行操作,包括移动、复制、删除等。

文件移动在Go语言中可以通过os.Rename函数实现。这个函数可以原子地将一个文件从一个位置移动到另一个位置。

bash 复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	// 源文件路径
	src := "source/file.txt"

	// 目标文件路径
	dest := "destination/file.txt"

	// 移动文件
	err := os.Rename(src, dest)
	if err != nil {
		fmt.Println("Error moving file:", err)
		return
	}

	fmt.Println("File moved successfully!")
}

使用os.Rename函数将source/file.txt移动到destination/file.txt。如果移动成功,就会输出File moved successfully!。否则,将输出移动文件时遇到的错误信息。
文件内容按行获取

  • 标准库 bufio 提供了一个缓冲读取器,可以方便地按行读取文件内容。
  • 第三方库 github.com/segmentio/ksuid 提供了一个KSUID生成器,可以用于生成全局唯一的ID。
bash 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	// 打开文件
	file, err := os.Open("example.txt")
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer file.Close()

	// 创建一个 Scanner 对象
	scanner := bufio.NewScanner(file)

	// 逐行读取文件内容
	for scanner.Scan() {
		line := scanner.Text() // 获取当前行的文本
		fmt.Println(line)      // 处理当前行的文本
	}

	// 检查是否有错误发生
	if err := scanner.Err(); err != nil {
		fmt.Println("Error reading file:", err)
	}
}

首先打开了一个名为example.txt的文件。然后,我们创建了一个Scanner对象来逐行扫描文件内容。通过scanner.Scan()方法来迭代扫描文件的每一行,scanner.Text()方法用于获取当前行的文本。最后,我们检查是否有错误发生,以确保文件读取过程中没有出现问题。

文件读写

文件复制

在Go语言中,可以使用io包来实现文件复制操作。

go 复制代码
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	// 打开源文件
	srcFile, err := os.Open("source.txt")
	if err != nil {
		log.Fatalf("Failed to open source file: %v", err)
	}
	defer srcFile.Close()

	// 创建目标文件
	destFile, err := os.Create("destination.txt")
	if err != nil {
		log.Fatalf("Failed to create destination file: %v", err)
	}
	defer destFile.Close()

	// 使用 io.Copy 函数复制文件内容
	_, err = io.Copy(destFile, srcFile)
	if err != nil {
		log.Fatalf("Failed to copy file content: %v", err)
	}

	log.Println("File copied successfully!")
}

首先打开了一个名为source.txt的源文件,并创建了一个名为destination.txt的目标文件。然后,我们使用io.Copy函数将源文件的内容复制到目标文件中。最后,我们检查是否有错误发生,并输出相应的日志信息。
一次性读取文件内容并写入新文件

使用ioutil包中的ReadFile函数一次性读取文件的内容,然后使用WriteFile函数将读取的内容写入新文件。下面是一个示例代码:

go 复制代码
package main

import (
	"io/ioutil"
	"log"
)

func main() {
	// 读取源文件内容
	content, err := ioutil.ReadFile("source.txt")
	if err != nil {
		log.Fatalf("Failed to read file: %v", err)
	}

	// 将内容写入目标文件
	err = ioutil.WriteFile("destination.txt", content, 0644)
	if err != nil {
		log.Fatalf("Failed to write file: %v", err)
	}

	log.Println("File copied successfully!")
}

使用ReadFile函数一次性读取了source.txt文件的内容,并将其保存在content变量中。然后,我们使用WriteFile函数将content中的内容写入到名为destination.txt的新文件中。
分片读取文件内容分步写入新文件

使用循环从源文件中读取数据,并将每次读取的数据写入目标文件中。读取和写入的数据大小由缓冲区的大小决定。

go 复制代码
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	// 打开源文件
	sourceFile, err := os.Open("source.txt")
	if err != nil {
		log.Fatalf("Failed to open source file: %v", err)
	}
	defer sourceFile.Close()

	// 创建目标文件
	destFile, err := os.Create("dest.txt")
	if err != nil {
		log.Fatalf("Failed to create dest file: %v", err)
	}
	defer destFile.Close()

	// 设置每个分片的大小(字节)
	chunkSize := 1024

	// 创建一个缓冲区,用于存储读取的数据
	buffer := make([]byte, chunkSize)

	// 循环读取文件内容,直到文件末尾
	for {
		// 从源文件读取一个分片的数据
		n, err := sourceFile.Read(buffer)
		if err != nil && err != io.EOF {
			log.Fatalf("Failed to read from source file: %v", err)
		}

		// 将读取的分片数据写入到目标文件
		if n > 0 {
			_, err := destFile.Write(buffer[:n])
			if err != nil {
				log.Fatalf("Failed to write to dest file: %v", err)
			}
		}

		// 如果已到达文件末尾,则退出循环
		if err == io.EOF {
			break
		}
	}
}

打开源文件和目标文件,并设置了每个分片的大小为 1024 字节。然后,循环读取源文件的内容,每次读取一个分片的数据,并将其写入到目标文件中。

实现步骤:

  1. 打开要读取的文件。
  2. 创建一个固定大小的缓冲区,用于存储每次读取的文件内容。
  3. 循环读取文件内容,直到文件末尾。
  4. 在每次循环中,使用Read 方法从文件中读取固定大小的数据块,并将其存储到缓冲区中。
  5. 将缓冲区中的数据块写入新文件中。
  6. 检查是否出现了读取或写入错误,如果有错误则进行处理。 关闭原始文件和新文件。

文件按行读取

文件按行读取是通过使用 bufio 包中的 Scanner 类型来实现的。这个 Scanner 类型提供了方便的方法,可以逐行扫描输入,而不需要过多的手动操作。

go 复制代码
package main

import (
	"bufio"
	"log"
	"os"
)

func main() {
	// 打开文件
	file, err := os.Open("source.txt")
	if err != nil {
		log.Fatalf("Failed to open file: %v", err)
	}
	defer file.Close()

	// 创建一个 scanner,用于按行读取文件内容
	scanner := bufio.NewScanner(file)

	// 逐行读取文件内容
	for scanner.Scan() {
		// 获取当前行的内容
		line := scanner.Text()

		// 在这里可以对每一行的内容进行处理
		// 这里只是简单地打印每一行的内容
		log.Println(line)
	}

	// 检查扫描过程中是否出现错误
	if err := scanner.Err(); err != nil {
		log.Fatalf("Scanner error: %v", err)
	}
}

具体实现步骤如下:

  • 使用 os 包中的 Open 函数打开文件,得到一个文件句柄。
  • 将文件句柄传递给 bufio.NewScanner 函数,创建一个 Scanner 对象,该对象可以逐行扫描文件内容。
  • 使用 Scanner 对象的 Scan 方法,可以逐行读取文件内容。每次调用 Scan
    方法,它会将文件指针移动到下一行,并返回一个布尔值,指示是否成功读取了下一行。如果成功读取下一行,则可以使用 Text
    方法获取该行的内容。
  • 在循环中反复调用 Scan 方法,直到文件的末尾。在每次循环中,我们可以处理当前行的内容,比如打印、解析等。
  • 最后,检查 Scan 方法是否返回了错误,如果有错误发生,可以根据需要进行处理。
相关推荐
WaaTong5 分钟前
Java反射
java·开发语言·反射
Troc_wangpeng6 分钟前
R language 关于二维平面直角坐标系的制作
开发语言·机器学习
努力的家伙是不讨厌的8 分钟前
解析json导出csv或者直接入库
开发语言·python·json
Envyᥫᩣ21 分钟前
C#语言:从入门到精通
开发语言·c#
齐 飞29 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
童先生42 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu44 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
LunarCod1 小时前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
Re.不晚1 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
老秦包你会1 小时前
Qt第三课 ----------容器类控件
开发语言·qt