Go语言fmt包深度探索:格式化输入输出的利器

news2024/11/27 8:35:39

在这里插入图片描述

🔥 个人主页:空白诗

在这里插入图片描述

文章目录

    • 🎭 引言
    • 一、基础输出函数`fmt.Print`与`fmt.Println`
      • 📌 `fmt.Print`:纯粹输出,不带换行
      • 📌 `fmt.Println`:输出后自动添加换行符
    • 二、格式化输出`fmt.Printf`
      • 📌 基础格式化参数
      • 📌 对齐与宽度
      • 📌 特殊格式
      • 📌 实际应用示例
    • 三、错误处理与`fmt.Errorf`
    • 四、自定义类型与`fmt.Stringer`接口
    • 五、格式化标志
      • 📌 填充与对齐
      • 📌 符号控制
      • 📌 数值格式
      • 📌 浮点数与精度
      • 📌 特殊类型与行为
      • 📌 示例整合
    • 六、结构体与切片的格式化输出
      • 📌 结构体输出
      • 📌 切片输出
      • 📌 进阶技巧
    • 七、自定义格式化器 `fmt.Formatter`
    • 八、总结


在这里插入图片描述

🎭 引言

在 Go 语言的编程世界里,fmt 包扮演着举足轻重的角色,它是格式化输入输出的强大工具箱,让你能够以清晰、美观的方式展示程序中的数据。接下来,我们将一起深入了解 fmt 包的几个核心函数,并通过实际代码示例来巩固学习成果。✨

一、基础输出函数fmt.Printfmt.Println

📌 fmt.Print:纯粹输出,不带换行

fmt.Print是一个在Go语言中广泛使用的函数,用于将一个或多个值格式化输出到标准输出(通常是终端),并且重要的一点是它不会自动在输出结束后添加换行符。这使得fmt.Print非常适合于连续输出多条信息而不需要每次输出后都换行的场景。

package main
import "fmt"

func main() {
    // 直接输出,不换行
    fmt.Print("Hello, ")
    fmt.Print("world!")
    // 输出: Hello, world!
}

📌 fmt.Println:输出后自动添加换行符

fmt.PrintlnGo语言标准库中的另一个常用函数,与fmt.Print相似,但它在输出一系列值之后会自动添加一个换行符(\n),这对于希望每条输出信息独占一行的场景尤为方便。

package main
import "fmt"

func main() {
    // 输出并自动换行
    fmt.Println("Greetings,")
    fmt.Println("Earthlings!")
    // 输出:
    // Greetings,
    // Earthlings!
}

二、格式化输出fmt.Printf

fmt.Printf在Go语言中提供了丰富的格式化选项,允许你精确地控制输出的文本样式、对齐方式、数值精度等。下面将列举一些常用的格式化参数及其例子,帮助你更好地理解和运用fmt.Printf

📌 基础格式化参数

  1. %v: 默认格式输出值。对于结构体,会按字段输出。

    fmt.Printf("%v\n", 42)       // 输出: 42
    
  2. %T: 输出值的类型。

    fmt.Printf("%T\n", 42)       // 输出: int
    
  3. %d: 有符号十进制整数。

    fmt.Printf("%d\n", 123)      // 输出: 123
    
  4. %b: 二进制表示。

    fmt.Printf("%b\n", 10)       // 输出: 1010
    
  5. %x, %X: 十六进制表示,%x小写,%X大写。

    fmt.Printf("%x %X\n", 255, 255) // 输出: ff FF
    
  6. %o: 八进制表示。

    fmt.Printf("%o\n", 8)         // 输出: 10
    
  7. %f: 浮点数,默认六位小数。

    fmt.Printf("%f\n", 3.14)      // 输出: 3.140000
    
  8. %.nf: 浮点数,限制小数点后有n位。

    fmt.Printf("%.2f\n", 3.14159) // 输出: 3.14
    
  9. %e, %E: 科学计数法,%e小写e,%E大写E。

    fmt.Printf("%e\n", 1000000)   // 输出: 1.000000e+06
    
  10. %s: 字符串。

    fmt.Printf("%s\n", "Hello")  // 输出: Hello
    

📌 对齐与宽度

  • 宽度: 在格式说明符前加数字指定输出的最小宽度。

    fmt.Printf("|%5d|\n", 42)     // 输出: |   42|
    
  • 左对齐: 在宽度前加减号-使内容左对齐。

    fmt.Printf("|%-5d|\n", 42)    // 输出: |42   |
    
  • 精度: 对于字符串,可以限制输出的字符数;对于浮点数,限制小数点后的位数。

    fmt.Printf("%.5s\n", "Hello") // 输出: Hello
    fmt.Printf("%5.2f\n", 3.14159)// 输出:  3.14
    

📌 特殊格式

  • %p: 输出指针地址。

    var x int = 42
    fmt.Printf("%p\n", &x)       // 输出类似: 0x12345678
    
  • %q: 用于字符串,输出带引号的字符串,对特殊字符进行转义。

    fmt.Printf("%q\n", "Hello\nWorld") // 输出: "Hello\nWorld"
    
  • %U: Unicode字符的编码。

    fmt.Printf("%U\n", '世')        // 输出: U+4E16
    

📌 实际应用示例

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	fmt.Printf("当前时间: %02d:%02d:%02d\n", now.Hour(), now.Minute(), now.Second())
	fmt.Printf("浮点数保留两位小数: %.2f\n", 3.14159)
	fmt.Printf("字符串右对齐, 宽度10: |%10s|\n", "Go")
	fmt.Printf("字符串左对齐, 宽度10: |%-10s|\n", "Go")
	fmt.Printf("布尔值输出: %t\n", true)
	fmt.Printf("指针地址: %p\n", &now)
}

通过上述例子,你可以看到fmt.Printf的强大灵活性,能够满足各种场景下的格式化输出需求。


三、错误处理与fmt.Errorf

在Go语言中,错误处理是一种核心机制,用于处理程序执行过程中可能遇到的问题。fmt.Errorf是一个非常实用的工具,它允许你创建携带丰富上下文信息的错误对象,这对于调试和理解错误发生的原因至关重要。特别是从Go 1.13版本开始,fmt.Errorf支持%w动词,该动词用于包裹(wrap)原始错误,保留错误链,这对于进行错误传递和分析特别有用。

package main

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("file.txt")
	if err != nil {
		// 使用%w动词包裹原始错误,添加上下文描述
		err = fmt.Errorf("error opening file: %w", err)
		fmt.Println(err)
		return // 遇到错误后应优雅地终止或恢复
	}
	defer file.Close()

	// 此处继续其他操作...
}
  • 创建错误: 当尝试打开文件失败时,os.Open会返回一个非nil的错误。通过fmt.Errorf,我们将这个错误进行了“包装”,添加了额外的上下文信息——“error opening file”,这样在查看错误信息时,不仅可以知道“发生了错误”,还能了解错误发生的上下文,即尝试打开文件时出现问题。

  • %w动词: 这是关键所在,它确保了原始错误(即os.Open返回的错误)的详细信息不会丢失,并且在后续的错误处理中可以通过类型断言(errors.Iserrors.As)来检查特定的错误类型或展开错误链,这对于进行精细的错误处理非常重要。

  • defer file.Close(): 即使在打开文件时发生错误,也确保通过defer语句在函数退出前关闭文件,这是良好的资源管理实践。

通过这种方式,fmt.Errorf不仅增强了错误信息的可读性和调试便利性,还保持了错误的透明性和可追溯性,使得错误处理逻辑更加健壮和易于维护。


四、自定义类型与fmt.Stringer接口

在Go语言中,fmt.Stringer是一个内建接口,它定义了一个String()方法,用于将值转换成字符串表示形式。任何实现了这个接口的类型都可以通过fmt包的函数(如Print, Printf, Println等)以一种自定义的、易于阅读的方式输出。这对于自定义类型来说尤为重要,因为它允许你控制该类型实例如何被格式化输出。

package main

import "fmt"

// 自定义类型 Person
type Person struct {
	Name string
	Age  int
}

// 实现 fmt.Stringer 接口
// String 方法返回该类型的字符串表示形式
func (p Person) String() string {
	return fmt.Sprintf("Person{Name: \"%s\", Age: %d}", p.Name, p.Age)
}

func main() {
	// 创建 Person 类型的实例
	p := Person{"Alice", 30}

	// 使用 fmt.Println 输出 Person 实例
	// 由于 Person 类型实现了 Stringer 接口,
	// fmt.Println 会自动调用 String 方法来格式化输出
	fmt.Println(p) // 输出: Person{Name: "Alice", Age: 30}
}
  • 自定义类型 Person: 定义了一个包含姓名(Name)和年龄(Age)字段的结构体类型。

  • 实现 fmt.Stringer 接口: 通过在 Person 类型上定义一个 String() 方法,实现了 fmt.Stringer 接口。此方法负责返回一个表示该 Person 实例的字符串,格式为 "Person{Name: \"...\", Age: ...}"

  • fmt.Println 自动调用: 当使用 fmt.Println 打印 Person 类型的变量时,因为 Person 实现了 Stringer 接口,Go 会智能地调用 String() 方法来获取该变量的字符串表示,而不是简单地打印出结构体的内存地址或其他默认格式。

通过实现 fmt.Stringer 接口,你能够为自定义类型提供一个清晰、可读性强的字符串表示,这对于日志记录、调试信息输出以及用户界面展示等方面都非常有用。这体现了Go语言在设计上的灵活性和面向接口的编程思想。

五、格式化标志

在Go语言的格式化输出中,格式化标志是附加在%之后的特殊字符,它们用来控制输出的格式和外观,包括对齐、填充、数值基底、精度控制等。以下是一些重要的格式化标志及其应用示例:

📌 填充与对齐

  • -(减号): 左对齐。在宽度指示符之前使用,表示输出内容将在指定宽度内左对齐,右侧填充空白字符。

    fmt.Printf("|%-10s|\n", "Hello") // 输出: |Hello     |
    
  • 0: 前导零填充。用于数值类型,指定以零填充至指定宽度。

    fmt.Printf("|%010d|\n", 42) // 输出: |0000000042|
    
  • 空格: 对于数值,正数前默认填充空格(与+标志结合时除外)。

📌 符号控制

  • +: 显示数值的符号,无论正负。

    fmt.Printf("|%+d|\n", 42) // 输出: |+42|
    fmt.Printf("|%+d|\n", -42) // 输出: |-42|
    
  • 空格: 对于正数,在符号位置填充空格(与+不同,只影响正数)。

📌 数值格式

  • %d: 十进制整数。
  • %b: 二进制表示。
  • %o: 八进制表示。
  • %x/%X: 十六进制表示,%x是小写,%X是大写。

📌 浮点数与精度

  • .n: 指定浮点数的小数位数。

    fmt.Printf("|%8.2f|\n", 3.14159) // 输出: |  3.14|
    
  • e/E: 科学记数法,e表示小写e,E表示大写E。

    fmt.Printf("|%e|\n", 123456789.0) // 输出: |1.234568e+08|
    

📌 特殊类型与行为

  • %s: 字符串。
  • %q: 带引号的字符串,适合输出代码片段或需要转义的字符串。
  • %p: 指针的地址。
  • %v: 默认格式,根据值的类型选择合适的表示。
  • %#v: Go语法格式的值,对于结构体等复合类型特别有用,显示类型信息。
  • %T: 输出值的类型。

📌 示例整合

package main

import "fmt"

func main() {
	fmt.Printf("|%10d|\n", 42)       // 右对齐,宽度10
	fmt.Printf("|%-10d|\n", 42)      // 左对齐,宽度10
	fmt.Printf("|%010d|\n", 42)      // 前导零填充至10位
	fmt.Printf("|%+10d|\n", 42)      // 正数前加正号,右对齐,宽度10
	fmt.Printf("|%10.2f|\n", 3.1415) // 浮点数,总宽度10,保留2位小数
	fmt.Printf("|%10s|\n", "Hello")  // 字符串右对齐,宽度10
}

这些标志的灵活组合使得Go的格式化输出功能强大而高效,能够满足各种复杂的格式需求。


六、结构体与切片的格式化输出

在Go语言中,结构体和切片是两种常用的数据结构,它们在fmt包的格式化输出中扮演着重要角色。通过灵活运用格式化标志和方法,我们可以以多种方式展示结构体和切片的信息。

📌 结构体输出

结构体可以使用%v(默认值)、%+v(包含字段名)等格式化字符串进行输出。%+v尤其有用,因为它会显示结构体每个字段的名字和值,便于调试。

type Student struct {
	Name string
	Age  int
}

func main() {
	stu := Student{Name: "Alice", Age: 20}
	fmt.Printf("%v\n", stu)   // 输出简洁形式 {Alice 20}
	fmt.Printf("%+v\n", stu)  // 输出带字段名的详细形式{Name:Alice Age:20}
}

📌 切片输出

切片可以直接通过%v格式化输出,它会显示切片内的元素序列。你也可以使用循环遍历切片,自定义输出格式。

func main() {
	nums := []int{1, 2, 3, 4, 5}
	fmt.Println(nums)       // 直接打印切片 [1 2 3 4 5]
	for i, v := range nums {
		fmt.Printf("Index: %d, Value: %d\n", i, v) // 循环遍历打印
	}
}

📌 进阶技巧

  • 自定义格式化: 结构体可以通过实现fmt.Stringer接口来自定义其字符串表示形式。
func (s Student) String() string {
	return fmt.Sprintf("Student(Name: %q, Age: %d)", s.Name, s.Age)
}
  • 切片格式化控制: 虽然直接使用%v可以输出切片,但在某些情况下,你可能需要控制元素间的分隔符、缩进等,这时可以手动循环并使用特定格式输出。

  • 切片的深度输出: 对于包含切片的结构体,使用%+v可以递归地显示内部切片的结构,这对调试复杂数据结构特别有用。

通过掌握这些技巧,你可以更有效地在Go程序中管理和展示结构体和切片数据,提升代码的可读性和维护性。

七、自定义格式化器 fmt.Formatter

在Go语言中,通过实现fmt.Formatter接口,你可以为自定义类型设计极其灵活和精细的格式化逻辑。这允许你在使用fmt包的函数(如PrintfSprintf等)时,针对特定的格式化动词定制输出方式,极大地提升了输出的多样性和可控性。

package main

import (
	"fmt"
)

// 自定义类型 MyType
type MyType int

// 实现 Formatter 接口
// Format 方法根据传入的格式化动词(c)决定输出格式
func (m MyType) Format(f fmt.State, c rune) {
	// 检查格式化动词
	switch c {
	case 'x': // 当请求十六进制输出时
		// 使用f.Write直接写入格式化的字符串到输出流,这里转换m为int后格式化为十六进制
		f.Write([]byte(fmt.Sprintf("0x%x", int(m))))
	default: // 如果没有指定特殊格式,采用默认的十进制输出
		// 同样使用f.Write输出十进制表示
		f.Write([]byte(fmt.Sprintf("%d", int(m))))
	}
}

func main() {
	var mt MyType = 100
	// 自定义格式化输出演示
	// 默认情况下(%v或未指定),MyType实例将按十进制输出
	// 使用%x动词时,触发自定义的十六进制输出逻辑
	fmt.Printf("Default: %v, Hex: %x\n", mt, mt) // 输出: Default: 100, Hex: 0x64
}
  • fmt.Formatter接口: 要实现自定义格式化,需要定义一个类型并为其添加一个名为Format的方法,接收两个参数:一个fmt.State(代表格式化状态,包含输出流和格式化选项)和一个rune(表示格式化动词,如'v''x'等)。
  • 格式化逻辑: 在Format方法内部,你可以根据传入的动词(c)来决定如何格式化和输出你的类型。这为你提供了极高的灵活性,可以支持多种输出风格。
  • 直接写入输出: 使用f.Write([]byte(...))直接将格式化好的字符串写入到输出流,这种方式比直接返回字符串更为底层,但也提供了更多的控制权。

通过实现fmt.Formatter接口,你的类型就能像内置类型一样,响应各种格式化动词,从而在日志记录、调试信息输出等场景下展现出强大的定制能力。


八、总结

本篇文章引领我们深入探索了Go语言标准库中的fmt包,从基础到高级,系统地揭示了其在格式化输出、错误处理以及自定义类型表示方面的强大功能与灵活性。以下是核心知识点的总结回顾:

  1. 基础输出函数fmt.Printfmt.Println提供了简洁的输出方式,前者不添加换行,后者自动添加,适配不同的输出需求。

  2. 格式化输出fmt.Printf通过丰富的格式化标志,如宽度控制、对齐方式、数值与字符串的格式化,以及特殊类型输出(如指针、带引号字符串等),使得输出格式化既强大又精细。

  3. 错误处理fmt.Errorf结合%w动词,允许创建携带上下文信息的错误,不仅增强了错误的可读性,还通过错误链维护了错误的原始信息,优化了错误处理的逻辑和效率。

  4. 自定义类型表示:通过实现fmt.Stringer接口,自定义类型可以拥有清晰、定制化的字符串表示,这对于日志记录、调试信息输出等场景极为重要。

  5. 结构体与切片格式化:展示了如何直接和高效地打印结构体与切片,以及如何通过循环遍历等技巧自定义输出格式,提高了数据展示的灵活性和可读性。

  6. 高级格式化器:实现fmt.Formatter接口,让自定义类型能够响应特定的格式化动词,实现高度定制化的输出逻辑,进一步扩展了fmt包的适用范围和能力。

通过本文的学习,我们不仅掌握了如何在Go中进行基本和高级的格式化输出,还学会了如何有效处理错误信息以及提升自定义类型的表现力,这些技能对于编写高质量、易于维护的Go程序至关重要。无论是进行日常开发、性能优化还是错误排查,深入理解并熟练运用fmt包都是每位Go程序员的必备技能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1650634.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python实验代码定时调起

Python代码实验调参需要等待1小时运行完成,自动将提前设置的5组参数(每组参数有8个)间隔1小时之后让Python代码再次自动依次调起运行其中的一组参数,每次跑完将实验结果写一个文件在本地存储通过邮件发送运行结果到指定QQ邮箱 im…

《QT实用小工具·五十三》会跑走的按钮

1、概述 源码放在文章末尾 该项目实现了会逃跑的按钮: 两个按钮,一个为普通按钮,另一个为会跑走的按钮 鼠标移到上面时,立刻跑掉 针对鼠标、键盘、触屏进行优化 随机交换两个按钮的文字、偶尔钻到另一个按钮下面、鼠标移开自…

cmake进阶:目录属性说明一

一. 简介 接下来简单学习一下 cmake 中的属性相关的概念。 属性大概可以分为多种:全局属性、目录属性(源码属性)、目标属性以及其它一些分类。 二. cmake进阶:目录属性 cmake中的属性可以 在如下网址查询到: http…

Jsoncpp介绍

1.简介 Jsoncpp 是一个 C 库,用于解析和生成 JSON 数据。它提供了一个易于使用的 DOM(Document Object Model)风格的 API,允许开发者以树形结构的方式操作 JSON 数据。 Jsoncpp 是一个C库,允许操作JSON值,…

PG WAL日志理解

类似于oracle的redo log,用于数据库恢复,当一条SQL语句执行,PG会把对应的块放到缓冲区执行,,会写进WAL缓冲区会进行写操作,commit后,WAL writer进程进行写操作,把日志缓冲区WAL buff…

【linux】初步认识文件系统

初步认识文件系统 前置知识的简单了解简单回顾C语言的文件操作stdin&stdout&stderr 系统文件IOopen函数的返回值文件描述符fd打开文件背后的操作文件描述符的分配规则 前置知识的简单了解 文件包括了文件内容和文件属性两个部分(文件内容顾名思义就是文件里面的数据等…

【Hugging Face】编写 shell 脚本在 huggingface 镜像站快速下载模型文件

前言 我们使用 Git LFS 和 wget 结合的方法,小文件使用 Git 下载,大文件使用 wget 下载 Git 下载的优缺点: 优点:相当简单 缺点:不支持断点续传 直接 wegt 下载比较稳定,但是欠缺优雅 我们可以将这两…

城市二手房数据分析与房价预测

实现功能 数据分析 二手房价格-时间分析 二手房数量-时间分析 二手房分布-区域分析 二手房户型分析 二手房朝向分析 二手房价格-区域分析 二手房热词词云 房价预测 采用合适的算法模型,对模型进行评估。通过输入影响因素输出预测价格。 采用技术与框架 M…

暗区突围服务器连接失败/网络异常/无法连接下载解决方法

暗区突围是一款仿真战场的模拟,首要介绍的自然是游戏中基本都会参与的模式,叫做战术行动,大家参与其中是会作为特遣队员的身份来做任务,面临的是一个全面自给自足的战场环境,这种模式要求玩家在进入暗区之前自行筹备所…

Springboot+Vue项目-基于Java+MySQL的影院订票系统(附源码+演示视频+LW)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…

uni-app+vue3 +uni.connectSocket 使用websocket

前言 最近在uni-appvue3websocket实现聊天功能,在使用websocket还是遇到很多问题 这次因为是app手机应用,就没有使用websocket对象,使用的是uni-app的uni.connectSocket 为了方便测试这次用的是node.js一个简单的dom,来联调模拟…

网络基础——路由

网络基础——路由 要想网络畅通,应让网络中的路由器知道如何转发数据包到各个网段。路由器根据路由表来转发数据包,而路由表是通过直连网络、静态路由以及动态路由来构建的。 route命令,底层是使用ioctl实现;ip命令,…

洛谷 P3391:文艺平衡树 ← Splay树模板题

【题目来源】https://www.luogu.com.cn/problem/P3391【题目描述】 您需要写一种数据结构(可参考题目标题),来维护一个有序数列。 其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间…

大模型爱好者的福音,有了它个人电脑也可以运行大模型了

GPT4ALL是一款可以运行在个人电脑上的大模型系统,不需要GPU即可运行,目前支持mac,linux和windows系统。 什么是GPT4ALL? 不论学习任何东西,首先要明白它是个什么东西。 Open-source large language models that run …

【C 数据结构-图】2. 图的存储结构

文章目录 【 1. 图的顺序存储结构 】1.1 基本原理1.2 顺序存储结构的 C 实现 【 2. 图的链式存储结构 】2.1 图的临接表存储结构2.1.1 临接表的 基本原理2.1.2 临接表的 链表节点2.1.3 邻接表 各结构体的C实现2.1.4 临接表 计算顶点的出度和入度邻接表计算 无向图的出度和入度邻…

IT项目管理【太原理工大学】前置知识点精简总结

根据上次考试以及其他方向考试的经验,这届考试可能偏向出题更灵活,能死记硬背或套公式的题减少,多做准备呀各位大三苦逼人,挂了补考还得回来补考凸^-^凸共勉 (另外,别作弊,今天人工智能考试逮住…

mib browser读取mib文件的oid(飞塔防火墙为例)

在配置zabbix监控的时候,配置监控项最为麻烦,一般我们都会套用模板,这种方式比较简单,但是有些设备就是没有现成的zabbix模板,怎么办? 今天我们使用MIB Browser来获取设备SNMP的OID,然后加入zabbix 。 1.什么是MIB Browser SNMP客户端工具MIB Browser, 全名iReasonin…

牛客网刷题 | BC78 KiKi说祝福语

目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 描述 2020年来到了&#…

synchronized与volatile关键字

1.synchronized的特性 1.1互斥 synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到 同一个对象 synchronized 就会阻塞等待. 进入 synchronized 修饰的代码块, 相当于 加锁 退出 synchronized 修饰的代码块, 相当于 解锁 syn…

【Linux网络】PXE批量网络装机

目录 一、系统装机 1.1 三种引导方式 1.2 系统安装过程 1.3 四大重要文件 二、PXE 2.1 PXE实现原理 2.2 PXE手动搭建过程 2.3 kickstart配合pxe完成批量自动安装 一、系统装机 1.1 三种引导方式 硬盘光驱(U盘)网络启动 1.2 系统安装过程 加载boot loader加载启动安…