Go语言文件处理:自定义数据文件与JSON格式操作详解
在编程中,文件处理是一项基础且重要的技能。它涉及到对不同格式文件的读写操作,以实现数据的存储、交换和处理。在实际应用中,我们经常需要将程序内部的数据结构以特定格式保存到文件中,或者从文件中读取数据并转换为程序可处理的结构。不同的文件格式具有各自的特点和适用场景,例如JSON格式适合数据交换,XML格式常用于数据存储和传输,而二进制格式则在存储效率和读写速度上具有优势。
1. 自定义数据文件概述
在处理文件时,我们通常会遇到标准格式和自定义格式的文件。为了便于比较不同文件格式的性能,我们使用了相同的数据集进行测试。这些数据以发票信息为例,包含了发票的基本信息和明细项。
以下是相关的数据结构定义:
type Invoice struct {
Id int
CustomerId int
Raised time.Time
Due time.Time
Paid bool
Note string
Items []*Item
}
type Item struct {
Id string
Price float64
Quantity int
Note string
}
同时,所有文件格式还共享一些常量:
const (
fileType = "INVOICES"
magicNumber = 0x125D
fileVersion = 100
dateFormat = "2006-01-02"
)
这些常量的作用分别是:
-
fileType
:用于标识文件类型,在文本格式中使用。
-
magicNumber
:用于唯一标识发票文件,在二进制格式中使用。
-
fileVersion
:表示发票文件的版本,方便后续对数据结构进行修改和兼容。
-
dateFormat
:指定日期在可读格式中的显示方式。
为了方便对不同格式文件进行读写操作,我们还定义了两个接口:
type InvoicesMarshaler interface {
MarshalInvoices(writer io.Writer, invoices []*Invoice) error
}
type InvoicesUnmarshaler interface {
UnmarshalInvoices(reader io.Reader) ([]*Invoice, error)
}
通过这两个接口,我们可以使用通用的方式来处理不同格式的文件读写。例如,以下是一个读取发票数据的函数:
func readInvoices(reader io.Reader, suffix string) ([]*Invoice, error) {
var unmarshaler InvoicesUnmarshaler
switch suffix {
case ".gob":
unmarshaler = GobMarshaler{}
case ".inv":
unmarshaler = InvMarshaler{}
case ".jsn", ".json":
unmarshaler = JSONMarshaler{}
case ".txt":
unmarshaler = TxtMarshaler{}
case ".xml":
unmarshaler = XMLMarshaler{}
}
if unmarshaler != nil {
return unmarshaler.UnmarshalInvoices(reader)
}
return nil, fmt.Errorf("unrecognized input suffix: %s", suffix)
}
2. 不同文件格式的性能比较
为了直观地了解不同文件格式的性能差异,我们对相同的50000条随机发票数据进行了读写测试,并记录了读写时间和文件大小。以下是测试结果:
| 后缀 | 读取时间(秒) | 写入时间(秒) | 文件大小(KiB) | 读写代码行数 | 格式 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| .gob | 0.3 | 0.2 | 7948 | 32 | Go二进制 |
| .gob.gz | 0.5 | 1.5 | 2589 | 32 | Go二进制(压缩) |
| .jsn | 4.5 | 2.2 | 16283 | 49 | JSON |
| .jsn.gz | 4.5 | 3.4 | 2678 | 49 | JSON(压缩) |
| .xml | 6.7 | 1.2 | 18917 | 75 | XML |
| .xml.gz | 6.9 | 2.7 | 2730 | 75 | XML(压缩) |
| .txt | 1.9 | 1.0 | 12375 | 139 | 纯文本(UTF - 8) |
| .txt.gz | 2.2 | 2.2 | 2514 | 139 | 纯文本(UTF - 8,压缩) |
| .inv | 1.7 | 3.5 | 7250 | 215 | 自定义二进制 |
| .inv.gz | 1.6 | 2.6 | 2400 | 215 | 自定义二进制(压缩) |
从表格中可以看出:
-
Go二进制格式
:读写速度快,文件大小相对较小,代码量少,是处理二进制数据的不错选择。但如果使用自定义类型且不支持gob编码,会降低读写速度并增大文件大小。
-
JSON格式
:读写速度适中,文件大小较大,代码量相对较少。它易于人类阅读和编写,适合数据交换,但在支持多版本格式时可能会有一些挑战。
-
XML格式
:读写速度较慢,文件大小较大,代码量较多。它是一种优秀的数据交换格式,特别适用于需要人类可读和数据交换的场景。
-
纯文本格式
:读写速度较快,文件大小适中,代码量较多。得益于
fmt
包的强大功能和自定义的易于解析的格式,它在读写性能上表现出色。
-
自定义二进制格式
:读写速度和文件大小表现较为均衡,但代码量较多。
3. JSON文件处理
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,具有易于人类阅读和编写、机器解析和生成的特点。在Go语言中,我们可以使用
encoding/json
包来处理JSON文件。
以下是一个JSON格式的发票数据示例:
{
"Id": 4461,
"CustomerId": 917,
"Raised": "2012-07-22",
"Due": "2012-08-21",
"Paid": true,
"Note": "Use trade entrance",
"Items": [
{
"Id": "AM2574",
"Price": 415.8,
"Quantity": 5,
"Note": ""
},
{
"Id": "MI7296",
...
}
]
}
3.1 写入JSON文件
为了实现JSON文件的写入操作,我们定义了一个
JSONMarshaler
类型,并实现了
InvoicesMarshaler
接口的
MarshalInvoices
方法。
type JSONMarshaler struct{}
func (JSONMarshaler) MarshalInvoices(writer io.Writer,
invoices []*Invoice) error {
encoder := json.NewEncoder(writer)
if err := encoder.Encode(fileType); err != nil {
return err
}
if err := encoder.Encode(fileVersion); err != nil {
return err
}
return encoder.Encode(invoices)
}
上述代码的操作步骤如下:
1. 创建一个
json.Encoder
对象,用于将数据编码为JSON格式并写入指定的
io.Writer
。
2. 依次写入文件类型和文件版本信息,这有助于后续对文件格式进行管理和升级。
3. 最后将发票数据写入文件。
为了更好地控制JSON输出格式,特别是对
time.Time
类型的处理,我们为
Invoice
类型实现了
MarshalJSON
方法。
type JSONInvoice struct {
Id int
CustomerId int
Raised string
Due string
Paid bool
Note string
Items []*Item
}
func (invoice Invoice) MarshalJSON() ([]byte, error) {
jsonInvoice := JSONInvoice{
invoice.Id,
invoice.CustomerId,
invoice.Raised.Format(dateFormat),
invoice.Due.Format(dateFormat),
invoice.Paid,
invoice.Note,
invoice.Items,
}
return json.Marshal(jsonInvoice)
}
此方法将
Invoice
对象转换为
JSONInvoice
对象,并将日期格式化为指定的字符串。
time.Time.Format
方法用于将时间对象转换为字符串,其格式字符串必须基于特定的日期
2006-01-02T15:04:05Z07:00
。
3.2 读取JSON文件
读取JSON文件的操作与写入类似,我们实现了
InvoicesUnmarshaler
接口的
UnmarshalInvoices
方法。
func (JSONMarshaler) UnmarshalInvoices(reader io.Reader) ([]*Invoice,
error) {
decoder := json.NewDecoder(reader)
var kind string
if err := decoder.Decode(&kind); err != nil {
return nil, err
}
if kind != fileType {
return nil, errors.New("cannot read non - invoices json file")
}
var version int
if err := decoder.Decode(&version); err != nil {
return nil, err
}
if version > fileVersion {
return nil, fmt.Errorf("version %d is too new to read", version)
}
var invoices []*Invoice
err := decoder.Decode(&invoices)
return invoices, err
}
操作步骤如下:
1. 创建一个
json.Decoder
对象,用于从
io.Reader
中读取JSON数据并解码。
2. 读取文件类型和文件版本信息,检查文件类型是否正确以及版本是否兼容。
3. 读取发票数据并存储到
invoices
切片中。
由于我们自定义了日期的存储格式,因此需要为
Invoice
类型实现
UnmarshalJSON
方法来处理日期的解析。
func (invoice *Invoice) UnmarshalJSON(data []byte) (err error) {
var jsonInvoice JSONInvoice
if err = json.Unmarshal(data, &jsonInvoice); err != nil {
return err
}
var raised, due time.Time
if raised, err = time.Parse(dateFormat, jsonInvoice.Raised);
err != nil {
return err
}
if due, err = time.Parse(dateFormat, jsonInvoice.Due); err != nil {
return err
}
*invoice = Invoice{
jsonInvoice.Id,
jsonInvoice.CustomerId,
raised,
due,
jsonInvoice.Paid,
jsonInvoice.Note,
jsonInvoice.Items,
}
return nil
}
此方法将JSON数据解析为
JSONInvoice
对象,然后将日期字符串转换为
time.Time
对象,并最终将数据赋值给
Invoice
对象。
4. 总结
通过对不同文件格式的比较和JSON文件处理的详细介绍,我们可以根据实际需求选择合适的文件格式。JSON格式在数据交换和处理方面具有一定的优势,但在处理多版本格式时需要注意兼容性问题。在实际应用中,我们还需要考虑文件的读写性能、大小和代码复杂度等因素。
以下是处理JSON文件的流程图:
graph TD;
A[开始] --> B[创建JSONMarshaler或JSONUnmarshaler];
B --> C{操作类型};
C -->|写入| D[调用MarshalInvoices方法];
D --> E[创建json.Encoder];
E --> F[写入文件类型和版本];
F --> G[写入发票数据];
G --> H[结束];
C -->|读取| I[调用UnmarshalInvoices方法];
I --> J[创建json.Decoder];
J --> K[读取文件类型和版本];
K --> L{版本是否兼容};
L -->|是| M[读取发票数据];
M --> N[解析日期];
N --> H;
L -->|否| O[返回错误];
O --> H;
在后续的开发中,我们可以进一步优化文件处理的性能,例如使用更高效的编码算法或并行处理技术。同时,我们还可以探索其他文件格式的应用场景,以满足不同的业务需求。
Go语言文件处理:自定义数据文件与JSON格式操作详解
5. XML文件处理
XML(eXtensible Markup Language)是一种广泛用于数据存储和传输的格式,具有良好的可读性和可扩展性。在处理XML文件时,由于Go 1没有
xml.Marshaler
接口,我们使用了并行数据类型
XMLInvoice
和
XMLItem
来帮助映射XML数据和发票数据。
以下是XML格式的发票数据示例:
<Invoice>
<Id>4461</Id>
<CustomerId>917</CustomerId>
<Raised>2012-07-22</Raised>
<Due>2012-08-21</Due>
<Paid>true</Paid>
<Note>Use trade entrance</Note>
<Items>
<Item>
<Id>AM2574</Id>
<Price>415.8</Price>
<Quantity>5</Quantity>
<Note></Note>
</Item>
<Item>
<Id>MI7296</Id>
...
</Item>
</Items>
</Invoice>
5.1 写入XML文件
为了实现XML文件的写入操作,我们定义了一个
XMLMarshaler
类型,并实现了
InvoicesMarshaler
接口的
MarshalInvoices
方法。
type XMLMarshaler struct{}
func (XMLMarshaler) MarshalInvoices(writer io.Writer, invoices []*Invoice) error {
// 写入XML声明
if _, err := writer.Write([]byte(xml.Header)); err != nil {
return err
}
// 写入文件类型和版本信息
if err := xml.NewEncoder(writer).Encode(struct {
FileType string `xml:"FileType"`
FileVersion int `xml:"FileVersion"`
}{fileType, fileVersion}); err != nil {
return err
}
// 写入发票数据
return xml.NewEncoder(writer).Encode(invoices)
}
操作步骤如下:
1. 向
io.Writer
写入XML声明,确保生成的XML文件符合规范。
2. 使用
xml.NewEncoder
将文件类型和版本信息编码并写入文件。
3. 最后将发票数据编码并写入文件。
5.2 读取XML文件
读取XML文件时,我们实现了
InvoicesUnmarshaler
接口的
UnmarshalInvoices
方法。
func (XMLMarshaler) UnmarshalInvoices(reader io.Reader) ([]*Invoice, error) {
decoder := xml.NewDecoder(reader)
// 跳过XML声明
_, err := decoder.Token()
if err != nil {
return nil, err
}
// 读取文件类型和版本信息
var info struct {
FileType string `xml:"FileType"`
FileVersion int `xml:"FileVersion"`
}
if err := decoder.Decode(&info); err != nil {
return nil, err
}
if info.FileType != fileType {
return nil, errors.New("cannot read non-invoices xml file")
}
if info.FileVersion > fileVersion {
return nil, fmt.Errorf("version %d is too new to read", info.FileVersion)
}
// 读取发票数据
var invoices []*Invoice
if err := decoder.Decode(&invoices); err != nil {
return nil, err
}
return invoices, nil
}
操作步骤如下:
1. 创建
xml.NewDecoder
用于从
io.Reader
读取XML数据。
2. 跳过XML声明,因为它不包含实际的数据信息。
3. 读取文件类型和版本信息,检查文件类型是否正确以及版本是否兼容。
4. 读取发票数据并存储到
invoices
切片中。
6. 纯文本文件处理
纯文本文件处理是一种简单直接的方式,我们可以使用
fmt
包的
Print
和
Scan
函数来实现读写操作。
6.1 写入纯文本文件
type TxtMarshaler struct{}
func (TxtMarshaler) MarshalInvoices(writer io.Writer, invoices []*Invoice) error {
// 写入文件类型和版本信息
if _, err := fmt.Fprintf(writer, "%s %d\n", fileType, fileVersion); err != nil {
return err
}
// 写入发票数据
for _, invoice := range invoices {
if _, err := fmt.Fprintf(writer, "%d %d %s %s %v %s\n",
invoice.Id, invoice.CustomerId,
invoice.Raised.Format(dateFormat),
invoice.Due.Format(dateFormat),
invoice.Paid, invoice.Note); err != nil {
return err
}
// 写入发票明细项
for _, item := range invoice.Items {
if _, err := fmt.Fprintf(writer, "%s %.2f %d %s\n",
item.Id, item.Price, item.Quantity, item.Note); err != nil {
return err
}
}
// 写入分隔符
if _, err := writer.Write([]byte("\n")); err != nil {
return err
}
}
return nil
}
操作步骤如下:
1. 向
io.Writer
写入文件类型和版本信息。
2. 遍历发票数据,将每张发票的基本信息写入文件。
3. 遍历每张发票的明细项,将其信息写入文件。
4. 每张发票之间使用空行分隔。
6.2读取纯文本文件
func (TxtMarshaler) UnmarshalInvoices(reader io.Reader) ([]*Invoice, error) {
scanner := bufio.NewScanner(reader)
// 读取文件类型和版本信息
if!scanner.Scan() {
return nil, errors.New("failed to read file type and version")
}
var kind string
var version int
if _, err := fmt.Sscanf(scanner.Text(), "%s %d", &kind, &version); err != nil {
return nil, err
}
if kind != fileType {
return nil, errors.New("cannot read non-invoices txt file")
}
if version > fileVersion {
return nil, fmt.Errorf("version %d is too new to read", version)
}
var invoices []*Invoice
var invoice *Invoice
for scanner.Scan() {
line := scanner.Text()
if line == "" {
if invoice != nil {
invoices = append(invoices, invoice)
invoice = nil
}
continue
}
if invoice == nil {
invoice = &Invoice{}
var raisedStr, dueStr string
var paid bool
if _, err := fmt.Sscanf(line, "%d %d %s %s %v %s",
&invoice.Id, &invoice.CustomerId,
&raisedStr, &dueStr, &paid, &invoice.Note); err != nil {
return nil, err
}
var err error
invoice.Raised, err = time.Parse(dateFormat, raisedStr)
if err != nil {
return nil, err
}
invoice.Due, err = time.Parse(dateFormat, dueStr)
if err != nil {
return nil, err
}
invoice.Paid = paid
invoice.Items = []*Item{}
} else {
item := &Item{}
if _, err := fmt.Sscanf(line, "%s %f %d %s",
&item.Id, &item.Price, &item.Quantity, &item.Note); err != nil {
return nil, err
}
invoice.Items = append(invoice.Items, item)
}
}
if invoice != nil {
invoices = append(invoices, invoice)
}
if err := scanner.Err(); err != nil {
return nil, err
}
return invoices, nil
}
操作步骤如下:
1. 使用
bufio.NewScanner
逐行读取文件内容。
2. 读取文件类型和版本信息,检查文件类型是否正确以及版本是否兼容。
3. 逐行解析文件内容,根据空行分隔不同的发票。
4. 解析每张发票的基本信息和明细项信息。
5. 将解析后的发票数据存储到
invoices
切片中。
7. 自定义二进制文件处理
自定义二进制文件处理可以通过使用
binary
包来实现,它可以将数据以二进制形式存储,提高存储效率。
7.1 写入自定义二进制文件
type InvMarshaler struct{}
func (InvMarshaler) MarshalInvoices(writer io.Writer) error {
// 写入魔数和文件版本
if err := binary.Write(writer, binary.BigEndian, uint16(magicNumber)); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, uint16(fileVersion)); err != nil {
return err
}
// 写入发票数量
if err := binary.Write(writer, binary.BigEndian, uint32(len(invoices))); err != nil {
return err
}
// 写入每张发票
for _, invoice := range invoices {
if err := binary.Write(writer, binary.BigEndian, uint32(invoice.Id)); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, uint32(invoice.CustomerId)); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, uint64(invoice.Raised.Unix())); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, uint64(invoice.Due.Unix())); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, invoice.Paid); err != nil {
return err
}
// 写入发票备注长度和内容
noteBytes := []byte(invoice.Note)
if err := binary.Write(writer, binary.BigEndian, uint32(len(noteBytes))); err != nil {
return err
}
if _, err := writer.Write(noteBytes); err != nil {
return err
}
// 写入发票明细项数量
if err := binary.Write(writer, binary.BigEndian, uint32(len(invoice.Items))); err != nil {
return err
}
// 写入每个明细项
for _, item := range invoice.Items {
idBytes := []byte(item.Id)
if err := binary.Write(writer, binary.BigEndian, uint32(len(idBytes))); err != nil {
return err
}
if _, err := writer.Write(idBytes); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, item.Price); err != nil {
return err
}
if err := binary.Write(writer, binary.BigEndian, uint32(item.Quantity)); err != nil {
return err
}
// 写入明细项备注长度和内容
itemNoteBytes := []byte(item.Note)
if err := binary.Write(writer, binary.BigEndian, uint32(len(itemNoteBytes))); err != nil {
return err
}
if _, err := writer.Write(itemNoteBytes); err != nil {
return err
}
}
}
return nil
}
操作步骤如下:
1. 写入魔数和文件版本,用于唯一标识发票文件和版本信息。
2. 写入发票数量,方便后续读取时确定循环次数。
3. 遍历每张发票,写入发票的基本信息,如ID、客户ID、日期等。
4. 写入发票备注的长度和内容。
5. 写入发票明细项的数量,然后遍历每个明细项,写入其信息。
7.2 读取自定义二进制文件
func (InvMarshaler) UnmarshalInvoices(reader io.Reader) ([]*Invoice, error) {
// 读取魔数和文件版本
var magic uint16
if err := binary.Read(reader, binary.BigEndian, &magic); err != nil {
return nil, err
}
if magic != magicNumber {
return nil, errors.New("invalid magic number")
}
var version uint16
if err := binary.Read(reader, binary.BigEndian, &version); err != nil {
return nil, err
}
if version > fileVersion {
return nil, fmt.Errorf("version %d is too new to read", version)
}
// 读取发票数量
var invoiceCount uint32
if err := binary.Read(reader, binary.BigEndian, &invoiceCount); err != nil {
return nil, err
}
invoices := make([]*Invoice, 0, invoiceCount)
// 读取每张发票
for i := 0; i < int(invoiceCount); i++ {
invoice := &Invoice{}
var id, customerId uint32
if err := binary.Read(reader, binary.BigEndian, &id); err != nil {
return nil, err
}
invoice.Id = int(id)
if err := binary.Read(reader, binary.BigEndian, &customerId); err != nil {
return nil, err
}
invoice.CustomerId = int(customerId)
var raisedUnix, dueUnix uint64
if err := binary.Read(reader, binary.BigEndian, &raisedUnix); err != nil {
return nil, err
}
invoice.Raised = time.Unix(int64(raisedUnix), 0)
if err := binary.Read(reader, binary.BigEndian, &dueUnix); err != nil {
return nil, err
}
invoice.Due = time.Unix(int64(dueUnix), 0)
if err := binary.Read(reader, binary.BigEndian, &invoice.Paid); err != nil {
return nil, err
}
// 读取发票备注长度和内容
var noteLen uint32
if err := binary.Read(reader, binary.BigEndian, ¬eLen); err != nil {
return nil, err
}
noteBytes := make([]byte, noteLen)
if _, err := io.ReadFull(reader, noteBytes); err != nil {
return nil, err
}
invoice.Note = string(noteBytes)
// 读取发票明细项数量
var itemCount uint32
if err := binary.Read(reader, binary.BigEndian, &itemCount); err != nil {
return nil, err
}
invoice.Items = make([]*Item, 0, itemCount)
// 读取每个明细项
for j := 0; j < int(itemCount); j++ {
item := &Item{}
var idLen uint32
if err := binary.Read(reader, binary.BigEndian, &idLen); err != nil {
return nil, err
}
idBytes := make([]byte, idLen)
if _, err := io.ReadFull(reader, idBytes); err != nil {
return nil, err
}
item.Id = string(idBytes)
if err := binary.Read(reader, binary.BigEndian, &item.Price); err != nil {
return nil, err
}
var quantity uint32
if err := binary.Read(reader, binary.BigEndian, &quantity); err != nil {
return nil, err
}
item.Quantity = int(quantity)
// 读取明细项备注长度和内容
var itemNoteLen uint32
if err := binary.Read(reader, binary.BigEndian, &itemNoteLen); err != nil {
return nil, err
}
itemNoteBytes := make([]byte, itemNoteLen)
if _, err := io.ReadFull(reader, itemNoteBytes); err != nil {
return nil, err
}
item.Note = string(itemNoteBytes)
invoice.Items = append(invoice.Items, item)
}
invoices = append(invoices, invoice)
}
return invoices, nil
}
操作步骤如下:
1. 读取魔数和文件版本,检查文件是否为合法的发票文件以及版本是否兼容。
2. 读取发票数量,确定后续需要读取的发票数量。
3. 遍历每张发票,读取其基本信息,如ID、客户ID、日期等。
4. 读取发票备注的长度和内容。
5. 读取发票明细项的数量,然后遍历每个明细项,读取其信息。
8. 总结与展望
通过对不同文件格式(JSON、XML、纯文本、自定义二进制)的详细介绍和处理示例,我们可以看到每种格式都有其优缺点和适用场景。
| 格式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| JSON | 易于人类阅读和编写,适合数据交换,代码量相对较少 | 支持多版本格式较复杂,文件大小较大 | 网络数据传输、前后端数据交互 |
| XML | 可读性好,可扩展性强,广泛用于数据存储和传输 | 读写速度较慢,文件大小较大,代码量较多 | 配置文件、数据交换标准 |
| 纯文本 | 简单直接,易于理解和处理 | 存储效率低,读写速度相对较慢,代码量较多 | 简单数据记录、日志文件 |
| 自定义二进制 | 存储效率高,读写速度快 | 可读性差,代码复杂度高 | 对存储效率和读写速度要求较高的场景 |
在实际开发中,我们应根据具体的业务需求和性能要求选择合适的文件格式。例如,如果需要与前端进行数据交互,JSON格式是一个不错的选择;如果需要处理复杂的配置信息,XML格式可能更合适;如果对存储效率有较高要求,自定义二进制格式可能是最佳选择。
未来,随着技术的不断发展,我们可以进一步探索更高效的文件处理方式,例如使用更先进的编码算法、并行处理技术或分布式存储系统,以满足不断增长的业务需求。同时,我们还可以关注新兴的文件格式和标准,为项目带来更多的可能性。
以下是不同文件格式处理的流程图:
graph LR;
A[开始] --> B{选择文件格式};
B -->|JSON| C[处理JSON文件];
B -->|XML| D[处理XML文件];
B -->|纯文本| E[处理纯文本文件];
B -->|自定义二进制| F[处理自定义二进制文件];
C --> G{操作类型};
G -->|写入| H[调用JSON写入方法];
G -->|读取| I[调用JSON读取方法];
D --> J{操作类型};
J -->|写入| K[调用XML写入方法];
J -->|读取| L[调用XML读取方法];
E --> M{操作类型};
M -->|写入| N[调用纯文本写入方法];
M -->|读取| O[调用纯文本读取方法];
F --> P{操作类型};
P -->|写入| Q[调用自定义二进制写入方法];
P -->|读取| R[调用自定义二进制读取方法];
H --> S[结束];
I --> S;
K --> S;
L --> S;
N --> S;
O --> S;
Q --> S;
R --> S;
在后续的开发中,我们可以根据这个流程图来选择合适的文件格式和操作方法,提高开发效率和代码质量。
超级会员免费看
2971

被折叠的 条评论
为什么被折叠?



