热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang基础protobuf使用

golang基础-protobuf使用,Go语言社区,Golang程序员人脉社


      • Mac安装

      • 摘自谷歌protobuf官网案例

      • go语言中的另一个练习protobuf的例子




前些日子了解过python中protobuf,今天主要是来学习下如何使用golang来使用protobuf

python基础–protobuf的使用(一)
python基础—protobuf的使用(还未完成)


参考资料:
https://github.com/google/protobuf

以下的需要VPN翻墙

pythontutorial
https://developers.google.com/protocol-buffers/docs/pythontutorial

python-generated
https://developers.google.com/protocol-buffers/docs/reference/python-generated#extension

语言指南
https://developers.google.com/protocol-buffers/docs/proto3

API文档
https://developers.google.com/protocol-buffers/docs/reference/python/?hl=zh-cn


Mac安装

Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言,并于2008年对外开源。Protobuf刚开源时的定位类似于XML、JSON等数据描述语言,通过附带工具生成代码并实现将结构化数据序列化的功能。但是我们更关注的是Protobuf作为接口规范的描述语言,可以作为设计安全的跨语言PRC接口的基础工具。

Protobuf核心的工具集是C++语言开发的,在官方的protoc编译器中并不支持Go语言。要想基于上面的hello.proto文件生成相应的Go代码,需要安装相应的插件。首先是安装官方的protoc工具

Mac通过brew install protobuf安装即可

然后是安装针对Go语言的代码生成插件,可以通过go get github.com/golang/protobuf/protoc-gen-go命令安装

然后通过以下命令生成相应的Go代码:protoc ./hello.proto --go_out=./


摘自谷歌protobuf官网案例

参考链接https://github.com/iyongfei/protobuf/tree/master/examples

链接包含java、python、go等多种语言来实现的protobuf的例子,我今天就把go语言中的例子摘出来

首先看我的项目目录结构:
这里写图片描述

首先看下dressbook.proto

syntax = "proto3";
package go_protoc;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phOnes= 4;
}
message AddressBook {
repeated Person people = 1;
}

然后通过 protoc ./dressbook.proto --go_out=./ 进行编译

zhiliaodeMBP:go_protoc zhiliao$ protoc ./dressbook.proto --go_out=./
zhiliaodeMBP:go_protoc zhiliao$ pwd
/Users/zhiliao/zhiliao/go/src/go_protoc
zhiliaodeMBP:go_protoc zhiliao$

我们来看下添加的功能add_person.go

package main
import (
"bufio"
"fmt"
"go_protoc"
"io"
"io/ioutil"
"log"
"os"
"strings"
"github.com/golang/protobuf/proto"
)
func promptForAddress(r io.Reader) (*go_protoc.Person, error) {
p := &go_protoc.Person{}
rd := bufio.NewReader(r)
fmt.Print("Enter person ID number: ")
if _, err := fmt.Fscanf(rd, "%dn", &p.Id); err != nil {
return p, err
}
fmt.Print("Enter name: ")
name, err := rd.ReadString('n')
if err != nil {
return p, err
}
p.Name = strings.TrimSpace(name)
fmt.Print("Enter email address (blank for none): ")
email, err := rd.ReadString('n')
if err != nil {
return p, err
}
p.Email = strings.TrimSpace(email)
for {
fmt.Print("Enter a phone number (or leave blank to finish): ")
phone, err := rd.ReadString('n')
if err != nil {
return p, err
}
phOne= strings.TrimSpace(phone)
if phOne== "" {
break
}
pn := &go_protoc.Person_PhoneNumber{
Number: phone,
}
fmt.Print("Is this a mobile, home, or work phone? ")
ptype, err := rd.ReadString('n')
if err != nil {
return p, err
}
ptype = strings.TrimSpace(ptype)
switch ptype {
case "mobile":
pn.Type = go_protoc.Person_MOBILE
case "home":
pn.Type = go_protoc.Person_HOME
case "work":
pn.Type = go_protoc.Person_WORK
default:
fmt.Printf("Unknown phone type %q. Using default.n", ptype)
}
p.Phones = append(p.Phones, pn)
}
return p, nil
}
func main() {
if len(os.Args) != 2 {
log.Fatalf("Usage: %s ADDRESS_BOOK_FILEn", os.Args[0])
}
fname := os.Args[1]
fmt.Println("osArgs-->>",os.Args[0],"-->>",os.Args[1])
in, err := ioutil.ReadFile(fname)
if err != nil {
if os.IsNotExist(err) {
fmt.Printf("%s: File not found. Creating new file.n", fname)
} else {
log.Fatalln("Error reading file:", err)
}
}
fmt.Println("osArgs after-->>")
book := &go_protoc.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
addr, err := promptForAddress(os.Stdin)
if err != nil {
log.Fatalln("Error with address:", err)
}
book.People = append(book.People, addr)
out, err := proto.Marshal(book)
if err != nil {
log.Fatalln("Failed to encode address book:", err)
}
if err := ioutil.WriteFile(fname, out, 0644); err != nil {
log.Fatalln("Failed to write address book:", err)
}
}

接下来通过命令行进行增加操作:

zhiliaodeMBP:src zhiliao$ ls
github.com go_demo go_protoc other
zhiliaodeMBP:src zhiliao$ cd go_demo/
zhiliaodeMBP:go_demo zhiliao$ go run add_person.go txt
osArgs-->> /var/folders/6x/58xzg4n5681_429nfm1d7c0h0000gn/T/go-build149370200/b001/exe/add_person -->> txt
txt: File not found. Creating new file.
osArgs after-->>
Enter person ID number: 111
Enter name: wyf
Enter email address (blank for none): 1@qq.com
Enter a phone number (or leave blank to finish): 123456
Is this a mobile, home, or work phone? mobile
Enter a phone number (or leave blank to finish):
zhiliaodeMBP:go_demo zhiliao$

然后会序列化到txt文件中

我们来看下列出的功能list_people.go

package main
import (
"fmt"
"go_protoc"
"io"
"io/ioutil"
"log"
"os"
"github.com/golang/protobuf/proto"
)
func writePerson(w io.Writer, p *go_protoc.Person) {
fmt.Fprintln(w, "Person ID:", p.Id)
fmt.Fprintln(w, " Name:", p.Name)
if p.Email != "" {
fmt.Fprintln(w, " E-mail address:", p.Email)
}
for _, pn := range p.Phones {
switch pn.Type {
case go_protoc.Person_MOBILE:
fmt.Fprint(w, " Mobile phone #: ")
case go_protoc.Person_HOME:
fmt.Fprint(w, " Home phone #: ")
case go_protoc.Person_WORK:
fmt.Fprint(w, " Work phone #: ")
}
fmt.Fprintln(w, pn.Number)
}
}
func listPeople(w io.Writer, book *go_protoc.AddressBook) {
for _, p := range book.People {
writePerson(w, p)
}
}
func main() {
if len(os.Args) != 2 {
log.Fatalf("Usage: %s ADDRESS_BOOK_FILEn", os.Args[0])
}
fname := os.Args[1]
in, err := ioutil.ReadFile(fname)
if err != nil {
log.Fatalln("Error reading file:", err)
}
book := &go_protoc.AddressBook{}
if err := proto.Unmarshal(in, book); err != nil {
log.Fatalln("Failed to parse address book:", err)
}
listPeople(os.Stdout, book)
}

依然通过控制台进行输出查看txt的信息

zhiliaodeMBP:go_demo zhiliao$
zhiliaodeMBP:go_demo zhiliao$ ls
add_person.go list_people.go txt
zhiliaodeMBP:go_demo zhiliao$ go run list_people.go txt
Person ID: 111
Name: wyf
E-mail address: 1@qq.com
Mobile phone #: 123456
zhiliaodeMBP:go_demo zhiliao$

go语言中的另一个练习protobuf的例子

接下来我们通过一个例子来了解下在go中是如何使用protobuf的数据格式的

以下是这个demo的项目结构
这里写图片描述

首先看下hello.proto

syntax = "proto3";
//包名,通过protoc生成时go文件时
package go_protoc;
//手机类型
//枚举类型第一个字段必须为0
enum PhoneType {
HOME = 0;
WORK = 1;
}
//手机
message Phone {
PhoneType type = 1;
string number = 2;
}
//人
message Person {
//后面的数字表示标识号
int32 id = 1;
string name = 2;
//repeated表示可重复
//可以有多个手机
repeated Phone phOnes= 3;
}
//联系簿
message ContactBook {
repeated Person persOns= 1;
}

然后从hello.proto编译为hello.pb.go

zhiliaodeMBP:go_protoc zhiliao$ protoc ./hello.proto --go_out=./
zhiliaodeMBP:go_protoc zhiliao$ pwd
/Users/zhiliao/zhiliao/go/src/go_protoc
zhiliaodeMBP:go_protoc zhiliao$ ls
hello.pb.go hello.proto
zhiliaodeMBP:go_protoc zhiliao$

然后看下go语言的代码safly.go

package main;
import (
"github.com/golang/protobuf/proto"
"go_protoc"
"io/ioutil"
"os"
"fmt"
)
func write() {
p1 := &go_protoc.Person{
Id: 1,
Name: "小张",
Phones: []*go_protoc.Phone{
{Type:go_protoc.PhoneType_HOME, Number:"111111111"},
{Type:go_protoc.PhoneType_WORK, Number:"222222222"},
},
};
p2 := &go_protoc.Person{
Id: 2,
Name: "小王",
Phones: []*go_protoc.Phone{
{Type:go_protoc.PhoneType_HOME, Number:"333333333"},
{Type:go_protoc.PhoneType_WORK, Number:"444444444"},
},
};
//创建地址簿
book := &go_protoc.ContactBook{};
book.Persons = append(book.Persons, p1);
book.Persons = append(book.Persons, p2);
//编码数据
data, _ := proto.Marshal(book);
//把数据写入文件
ioutil.WriteFile("./txt", data, os.ModePerm);
}
func read() {
//读取文件数据
data, _ := ioutil.ReadFile("./txt");
book := &go_protoc.ContactBook{};
//解码数据
proto.Unmarshal(data , book);
for _, v := range book.Persons {
fmt.Println(v.Id, v.Name);
for _, vv := range v.Phones {
fmt.Println(vv.Type, vv.Number);
}
}
}
func main() {
write();
read();
}

结果输出如下:

1 小张
HOME 111111111
WORK 222222222
2 小王
HOME 333333333
WORK 444444444

保存至文件内容如下:


&小张 111111111
222222222
&小王 333333333
444444444

最后看下编译生成的hello.pb.go的代码

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: hello.proto
package go_protoc
/*
包名,通过protoc生成时go文件时
*/

import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// 手机类型
// 枚举类型第一个字段必须为0
type PhoneType int32
const (
PhoneType_HOME PhOneType= 0
PhoneType_WORK PhOneType= 1
)
var PhoneType_name = map[int32]string{
0: "HOME",
1: "WORK",
}
var PhoneType_value = map[string]int32{
"HOME": 0,
"WORK": 1,
}
func (x PhoneType) String() string {
return proto.EnumName(PhoneType_name, int32(x))
}
func (PhoneType) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{0}
}
// 手机
type Phone struct {
Type PhoneType `protobuf:"varint,1,opt,name=type,proto3,enum=go_protoc.PhoneType" json:"type,omitempty"`
Number string `protobuf:"bytes,2,opt,name=number,proto3" json:"number,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Phone) Reset() { *m = Phone{} }
func (m *Phone) String() string { return proto.CompactTextString(m) }
func (*Phone) ProtoMessage() {}
func (*Phone) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{0}
}
func (m *Phone) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Phone.Unmarshal(m, b)
}
func (m *Phone) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Phone.Marshal(b, m, deterministic)
}
func (dst *Phone) XXX_Merge(src proto.Message) {
xxx_messageInfo_Phone.Merge(dst, src)
}
func (m *Phone) XXX_Size() int {
return xxx_messageInfo_Phone.Size(m)
}
func (m *Phone) XXX_DiscardUnknown() {
xxx_messageInfo_Phone.DiscardUnknown(m)
}
var xxx_messageInfo_Phone proto.InternalMessageInfo
func (m *Phone) GetType() PhoneType {
if m != nil {
return m.Type
}
return PhoneType_HOME
}
func (m *Phone) GetNumber() string {
if m != nil {
return m.Number
}
return ""
}
// 人
type Person struct {
// 后面的数字表示标识号
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
// repeated表示可重复
// 可以有多个手机
Phones []*Phone `protobuf:"bytes,3,rep,name=phones,proto3" json:"phones,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Person) Reset() { *m = Person{} }
func (m *Person) String() string { return proto.CompactTextString(m) }
func (*Person) ProtoMessage() {}
func (*Person) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{1}
}
func (m *Person) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Person.Unmarshal(m, b)
}
func (m *Person) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Person.Marshal(b, m, deterministic)
}
func (dst *Person) XXX_Merge(src proto.Message) {
xxx_messageInfo_Person.Merge(dst, src)
}
func (m *Person) XXX_Size() int {
return xxx_messageInfo_Person.Size(m)
}
func (m *Person) XXX_DiscardUnknown() {
xxx_messageInfo_Person.DiscardUnknown(m)
}
var xxx_messageInfo_Person proto.InternalMessageInfo
func (m *Person) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *Person) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Person) GetPhones() []*Phone {
if m != nil {
return m.Phones
}
return nil
}
// 联系簿
type ContactBook struct {
Persons []*Person `protobuf:"bytes,1,rep,name=persons,proto3" json:"persons,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContactBook) Reset() { *m = ContactBook{} }
func (m *ContactBook) String() string { return proto.CompactTextString(m) }
func (*ContactBook) ProtoMessage() {}
func (*ContactBook) Descriptor() ([]byte, []int) {
return fileDescriptor_61ef911816e0a8ce, []int{2}
}
func (m *ContactBook) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContactBook.Unmarshal(m, b)
}
func (m *ContactBook) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContactBook.Marshal(b, m, deterministic)
}
func (dst *ContactBook) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContactBook.Merge(dst, src)
}
func (m *ContactBook) XXX_Size() int {
return xxx_messageInfo_ContactBook.Size(m)
}
func (m *ContactBook) XXX_DiscardUnknown() {
xxx_messageInfo_ContactBook.DiscardUnknown(m)
}
var xxx_messageInfo_ContactBook proto.InternalMessageInfo
func (m *ContactBook) GetPersons() []*Person {
if m != nil {
return m.Persons
}
return nil
}
func init() {
proto.RegisterType((*Phone)(nil), "go_protoc.Phone")
proto.RegisterType((*Person)(nil), "go_protoc.Person")
proto.RegisterType((*ContactBook)(nil), "go_protoc.ContactBook")
proto.RegisterEnum("go_protoc.PhoneType", PhoneType_name, PhoneType_value)
}
func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) }
var fileDescriptor_61ef911816e0a8ce = []byte{
// 221 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x8e, 0x4f, 0x4b, 0xc3, 0x40,
0x10, 0xc5, 0xdd, 0x34, 0x5d, 0xcd, 0x04, 0x4a, 0x1c, 0x44, 0xf6, 0x66, 0xc8, 0x69, 0x51, 0xc8,
0xa1, 0xde, 0x3c, 0x2a, 0x82, 0x22, 0xd2, 0xb2, 0x88, 0x1e, 0xa5, 0x7f, 0x16, 0x1b, 0x4c, 0x76,
0x96, 0x64, 0x3d, 0xe4, 0xdb, 0x4b, 0x86, 0x18, 0xa4, 0xb7, 0x37, 0xbc, 0xdf, 0x7b, 0x6f, 0x20,
0x3d, 0xd8, 0xba, 0xa6, 0xd2, 0xb7, 0x14, 0x08, 0x93, 0x2f, 0xfa, 0x64, 0xb5, 0x2b, 0x9e, 0x61,
0xbe, 0x3e, 0x90, 0xb3, 0xa8, 0x21, 0x0e, 0xbd, 0xb7, 0x4a, 0xe4, 0x42, 0x2f, 0x96, 0x17, 0xe5,
0x84, 0x94, 0xec, 0xbf, 0xf5, 0xde, 0x1a, 0x26, 0xf0, 0x12, 0xa4, 0xfb, 0x69, 0xb6, 0xb6, 0x55,
0x51, 0x2e, 0x74, 0x62, 0xc6, 0xab, 0x78, 0x07, 0xb9, 0xb6, 0x6d, 0x47, 0x0e, 0x17, 0x10, 0x55,
0x7b, 0x6e, 0x9a, 0x9b, 0xa8, 0xda, 0x23, 0x42, 0xec, 0x36, 0x8d, 0x1d, 0x79, 0xd6, 0xa8, 0x41,
0xfa, 0xa1, 0xb8, 0x53, 0xb3, 0x7c, 0xa6, 0xd3, 0x65, 0x76, 0xbc, 0x68, 0x46, 0xbf, 0xb8, 0x83,
0xf4, 0x81, 0x5c, 0xd8, 0xec, 0xc2, 0x3d, 0xd1, 0x37, 0xde, 0xc0, 0xa9, 0xe7, 0x99, 0x4e, 0x09,
0x4e, 0x9e, 0xff, 0x4f, 0xb2, 0x63, 0xfe, 0x88, 0xeb, 0x2b, 0x48, 0xa6, 0xf7, 0xf1, 0x0c, 0xe2,
0xa7, 0xd5, 0xeb, 0x63, 0x76, 0x32, 0xa8, 0x8f, 0x95, 0x79, 0xc9, 0xc4, 0x56, 0x72, 0xf0, 0xf6,
0x37, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x4b, 0xbd, 0x93, 0x20, 0x01, 0x00, 0x00,
}


推荐阅读
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
author-avatar
我是王健值得信赖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有