串行化(Serialization)

【excel+vba】一表拆多表+不同收件人附带不同附件 快捷处理:拆分多个不同表 给不同人发送不同内容且附带附件 阅读详情

串行化(Serialization)

作者:阿荣


下载例子源代码


串行化是微软提供的用于对对象进行文件I/O的一种机制,该机制在框架(Frame)/文档(Document)/视图(View) 模式中得到了很好的应用。很多人对什么是串行化、怎么使对象具有串行化能力和如何使用串行化功能等问题都 不甚明了。本文试图对串行化做一个简单的解释。由于本人对串行化功能使用的也不多,不足之处敬请谅解。

MFC 框架/文档/视图结构中的文件读写

CFile是MFC类库中所有文件类的基类。所有MFC提供的文件I/O功能都和这个类有关。很多情况下,大家都喜欢直接 调用CFile::Write/WriteHuge来写文件,调用CFile::Read/ReadHuge来读文件。这样的文件I/O其实和不使用MFC的文件 I/O没有什么区别,甚至和以前的ANSI C的文件I/O也没有多少差别,所差别的不外乎是调用的API不同而已。

在开始学习C++的时候,大家一定对cin/cout非常熟悉,这两个对象使用非常明了的<<和>>运算符进行 I/O,其使用格式为:

        
//示例代码1
int i;
cin >> i;
//here do something to object i
cout << i;

使用这种方式进行I/O的好处时,利用运算符重载功能,可以用一个语句完成对一系列的对象的读写,而不需要 区分对象具体的类型。MFC提供了类CArchive,实现了运算符<<和>>的重载,希望按照前面cin和cout 的方式进行文件I/O。通过和CFile类的配合,不仅仅实现了对简单类型如int/float等的文件读写,而且实现了对可 序列化对象(Serializable Objects,这个概念后面描述)的文件读写。

一般情况下,使用CArchive对对象进行读操作的过程如下:

        
//示例代码2
//定义文件对象和文件异常对象
CFile file;
CFileException fe;
//以读方式打开文件
if(!file.Open(filename,CFile::modeRead,&fe))
{
fe.ReportError();
return;
}

//构建CArchive 对象
CArchive ar(&file,CArchive::load);
ar >> obj1>>obj2>>obj3...>>objn;
ar.Flush();
//读完毕,关闭文件流
ar.Close();
file.Close();

使用CArchive对对象进行写操作的过程如下:

        
//示例代码3
//定义文件对象和文件异常对象
CFile file;
CFileException fe;
//以读方式打开文件
if(!file.Open(filename,CFile::modeWrite|CFile::modeCreate,&fe))
{
fe.ReportError();
return;
}

//构建CArchive 对象
CArchive ar(&file,CArchive::load);
ar << obj1<<obj2<<obj3...<<objn;
ar.Flush();
//写完毕,关闭文件流
ar.Close();
file.Close();

可见,对于一个文件而言,如果文件内对象的排列顺序是固定的,那么对于文件读和写从形式上只有使用的运算符的不同。 在MFC的框架/文档/视图结构中,一个文档的内部对象的构成往往是固定的,这种情况下,写到文件中时对象在文件中的布局 也是固定的。因此CDocument利用其基类CObject提供的Serilize虚函数,实现自动文档的读写。

当用户在界面上选择文件菜单/打开文件(ID_FILE_OPEN)时,CWinApp派生类的OnFileOpen函数被自动调用,它通过文档模板 创建(MDI)/重用(SDI)框架、文档和视图对象,并最终调用CDocument::OnOpenDocument来读文件,CDocument::OnOpenDocument 的处理流程如下:

        
//示例代码4
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
if (IsModified())
TRACE0("Warning: OnOpenDocument replaces an unsaved document./n");

CFileException fe;
CFile* pFile = GetFile(lpszPathName,
CFile::modeRead|CFile::shareDenyWrite, &fe);
if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
return FALSE;
}

DeleteContents();
SetModifiedFlag(); // dirty during de-serialize

CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive); // load me
loadArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);
DeleteContents(); // remove failed contents

TRY
{
ReportSaveLoadException(lpszPathName, e,
FALSE, AFX_IDP_FAILED_TO_OPEN_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL

SetModifiedFlag(FALSE); // start off with unmodified

return TRUE;
}

同样,当用户选择菜单文件/文件保存(ID_FILE_SAVE)或者文件/另存为...(ID_FILE_SAVEAS)时,通过CWinApp::OnFileSave和CWinApp::OnFileSaveAs 最终调用CDocument::OnSaveDocument,这个函数处理如下:

        
//示例代码5
BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName)
{
CFileException fe;
CFile* pFile = NULL;
pFile = GetFile(lpszPathName, CFile::modeCreate |
CFile::modeReadWrite | CFile::shareExclusive, &fe);

if (pFile == NULL)
{
ReportSaveLoadException(lpszPathName, &fe,
TRUE, AFX_IDP_INVALID_FILENAME);
return FALSE;
}

CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete);
saveArchive.m_pDocument = this;
saveArchive.m_bForceFlat = FALSE;
TRY
{
CWaitCursor wait;
Serialize(saveArchive); // save me
saveArchive.Close();
ReleaseFile(pFile, FALSE);
}
CATCH_ALL(e)
{
ReleaseFile(pFile, TRUE);

TRY
{
ReportSaveLoadException(lpszPathName, e,
TRUE, AFX_IDP_FAILED_TO_SAVE_DOC);
}
END_TRY
DELETE_EXCEPTION(e);
return FALSE;
}
END_CATCH_ALL

SetModifiedFlag(FALSE); // back to unmodified

return TRUE; // success
}

从前面两段代码可以看出,文件读和文件写的结构基本相同,并且最终都调用了CObject::Serialize函数完成对文档自己的读和写(参见 注释中的save me和load me)。对于用AppWizard自动生成的MDI和SDI,系统自动生成了这个函数的重载实现,缺省的实现为:

        
//示例代码6
void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}

如果一个对VC非常熟悉的人,喜欢手工生成所有的代码(当然这是非常浪费时间也是没有必要的),那么他提供的CDocument派生类 也应该实现这个缺省的Serialize函数,否则,系统在文件读写时只能调用CObject::Serialize,这个函数什么都不做,当然也无法完成 对特定对象的文件保存/载入工作。当然,用户也可以截获ID_FILE_OPEN等菜单,实现自己的文件读写功能,但是这样的代码将变得非常烦琐, 也不容易阅读。

回到CMyDoc::Serialize函数。这个函数通过对ar对象的判断,决定当前是在读还是在写文件。由于AppWizard不知道你的文档是干 什么的,所以它不会给你添加实际的文件读写代码。假设你的文档中有三个对象m_Obj_a,m_Obj_b,m_Obj_c,那么实际的代码应该为:

        
//示例代码7
void CMyDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_Obj_a << m_Obj_b << m_Obj_c;
}
else
{
ar >> m_Obj_a >> m_Obj_b >> m_Obj_c;
}
}

可串行化对象(Serializable Object)

要利用示例代码7 中的方式进行文件I/O的一个基本条件是:m_Obj_a等对象必须是可串行化的对象。一个 可串行化对象的条件为:

  • 这个类从CObject派生)
  • 该类实现了Serialize函数
  • 该类在定义时使用了DECLARE_SERIAL宏
  • 在类的实现文件中使用了IMPLEMENT_SERIAL宏
  • 这个类有一个不带参数的构造函数,或者某一个带参数的构造函数所有的参数都提供了缺省参数

这里,可串行化对象条件中没有包括简单类型,对于简单类型,CArchive基本都实现了运算符<<和>>的重载,所以可以直接使用 串行化方式进行读写。

从CObject类派生

串行化要求对象从CObject派生,或者从一个CObject的派生类派生。这个要求比较简单,因为几乎所有的类(不包括CString)都是从CObject 派生的,因此对于从MFC类继承的类都满足这个要求。对于自己的数据类,可以指定它的基类为CObject来满足这个要求。

实现Serialize函数

Serialize函数是对象真正保存数据的函数,是整个串行化的核心。其实现方法和CMyDoc::Serialize一样,利用CArchive::IsStoring和CArchive::IsLoading 判断当前的操作,并选择<<和>>来保存和读取对象。

使用DECLARE_SERIAL宏

DECLARE_SERIAL宏包括了DECLARE_DYNAMIC和DECLARE_DYNCREATE功能,它定义了一个类的CRuntimeClass相关信息,并实现了缺省的operator >> 重载。实现了该宏以后,CArchive就可以利用ReadObject和WriteObject来进行对象I/O,并能够在事先不知道类型的情况下从文件中读对象。

使用IMPLEMENT_SERIAL

DECLARE_SERIAL宏和IMPLEMENT_SERIAL宏必须成对出现,否则DECLARE_SERIAL宏定义的实体将无法实现,最终导致连接错误。

缺省构造函数

这是CRuntimeClass::CreateObject对对象的要求。

特殊情况

  • 只通过Serialize函数对对象读写,而不使用ReadObject/WriteObject和运算符重载时,前面的可串行化条件不需要,只要实现Serialize 函数即可。
  • 对于现存的类,如果它没有提供串行化功能,可以通过使用重载友元operator <<和operator >>来实现。

例子

假设需要实现一个几何图形显示、编辑程序,支持可扩展的图形功能。这里不想讨论具体图形系统的实现,只讨论图像对象的保存和 载入。

基类CPicture

每个图形对象都从CPicture派生,这个类实现了串行化功能,其实现代码为:

        //头文件picture.h

#if !defined(__PICTURE_H__)
#define __PICTURE_H__

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

const int TYPE_UNKNOWN = -1;
class CPicture:public CObject
{
int m_nType;//图形类别
DECLARE_SERIAL(CPicture)
public:
CPicture(int m_nType=TYPE_UNKNOWN):m_nType(m_nType){};
int GetType()const {return m_nType;};
virtual void Draw(CDC * pDC);
void Serialize(CArchive & ar);
};
#endif

//cpp文件picture.cpp
#include "stdafx.h"
#include "picture.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

void CPicture::Draw(CDC * pDC)
{
//基类不实现绘图功能,由派生类实现
}

void CPicture::Serialize(CArchive & ar)
{
if(ar.IsLoading())
{
ar << m_nType;
}else{
ar >> m_nType;

}
}

注意:由于CRuntimeClass要求这个对象必须能够被实例化,因此虽然Draw函数没有任何绘图操作,这个类还是没有把它定义成 纯虚函数。

对象在CDocument派生类中的保存和文件I/O过程

为了简化设计,在CDocument类派生类中,采用MFC提供的模板类CPtrList来保存对象。该对象定义为:

        protected:
CTypedPtrList m_listPictures;

由于CTypedPtrList和CPtrList都没有实现Serialize函数,因此不能够通过ar << m_listPictures和ar >> m_listPictures 来序列化对象,因此CPictureDoc的Serialize函数需要如下实现:

        void CTsDoc::Serialize(CArchive& ar)
{
POSITION pos;
if (ar.IsStoring())
{
// TODO: add storing code here
pos = m_listPictures.GetHeadPosition();
while(pos != NULL)
{
ar << m_listPictures.GetNext (pos);
}
}
else
{
// TODO: add loading code here
RemoveAll();
CPicture * pPicture;
do{
try
{
ar >> pPicture;
TRACE("Read Object %d/n",pPicture->GetType ());
m_listPictures.AddTail(pPicture);
}
catch(CException * e)
{
e->Delete ();
break;
}
}while(pPicture != NULL);
}
m_pCurrent = NULL;
SetModifiedFlag(FALSE);
}

实现派生类的串行化功能

几何图形程序支持直线、矩形、三角形、椭圆等图形,分别以类CLine、CRectangle、CTriangle和CEllipse实现。以类CLine为例,实现 串行化功能:

  1. 从CPicture派生CLine,在CLine类定义中增加如下成员变量:
        CPoint m_ptStart,m_ptEnd;
  2. 在该行下一行增加如下宏:
        DECLARE_SERIAL(CLine)
  3. 实现Serialize函数
        void CLine::Serialize(CArchive & ar)
    {
    CPicture::Serialize(ar);
    if(ar.IsLoading())
    {
    ar>>m_ptStart.x>>m_ptStart.y>>m_ptEnd.x>>m_ptEnd.y;
    }else{
    ar<<m_ptStart.x<<m_ptStart.y<<m_ptEnd.x<<m_ptEnd.y;
    }
    }
  4. 在CPP文件中增加
        IMPLEMENT_SERIAL(CLine,CPicture,TYPE_LINE);

这样定义的CLine就具有串行化功能,其他图形类可以类似定义。

附注

本文仓促草就,不足之处在所难免。请发现谬误者给我 来信说明,谢谢。

Apollo 9.0 速度非线性规划算法 – piecewise jerk speed nonlinear optimizer Ⅰ 二次规划的速度规划算法(PiecewiseJerkSpeedOptimizer)的存在两个问题: 这里以一张图来说明上面的问题,假设存在一个实际限速区间(或曲率很大需要降速的区间)[S1, S2],PiecewiseJerkSpeedOptimizer的做法是根据动态规划的st曲线(黑色),找到具体的时间区间[T1, T2],然后对区间[T1, T2]内所有的点施加约束或惩罚。但是二次规划平滑后的曲线(黄色)发生了变化,那么限速区间[S1, S2]对应的时间区间[T1, T2]也发生了变化,所以实际应该是对 阅读详情

相关推荐

openEuler 欧拉 安装Oracle19c数据库RPM包安装

欧拉系统安装部署oracle 19c rpm方式

陈苏漾的IT生涯 6894

什么是串行化

如果你处在计算机行业,肯定听说过串行化这个词。串行化是计算机行业的一个术语,我之前的文章中也提到过,术语是为了方便大家沟通交流的。不要害怕陌生的术语。下面我们从宏观上介绍串行化。浅显的理解是把处于内存中的类,保存到硬盘上。当下次软件启动时,可以进行反串行化,还原类现场。这样听一起来是不是有些熟悉,这不就类似保存配置文件嘛,将软件的设置保存成XML或者INI文件,下次根据配置文件设置软件配置。其实意思是一样的。串行化除了保存配置文件外,还可以将串行化的结果,通过总线传输,在总线的另一端还原类现场。

qq_28096563的博客 997

测绘无人船避坑指南:云卓H12Pro遥控器接海康摄像头,从网络设置到RTSP流延迟优化全流程

本文详细解析了测绘无人船视频子系统的优化方案,重点介绍海康威视摄像头与云卓H12Pro遥控器的深度适配流程。从网络设置到RTSP流延迟优化,提供了一套经过实测的低延迟(<200ms)解决方案,适用于复杂水域环境下的测绘任务。

weixin_30415113的博客 627

java串行化_Java 对象的串行化(Serialization)

1.什么是串行化对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的串行化(Serialization)。串行化的主要任务是写出对象实例变量的数值。如果变量是另一对象的引用,则引用的对象也要...

weixin_30908131的博客 811

解决VM 与 Device/Credential Guard 不兼容。在禁用 Device/Credential Guard 后,可以运行 VM 的方法

在启用了Credential Guard或Device Guard的Windows 10主机上启动12.5版之前的VMware Workstation中的虚拟机时,将显示蓝色诊断屏幕(BSOD)。 会看到类似于以下内容的错误: VMware Workstation和Device / Credential Guard不兼容。禁用Device / Credential Guard后,可以运行VMwar...

Hern(宋兆恒) 39万+

基于Pixhawk与OpenMV的无人机视觉引导精准降落系统设计与实现

本文详细介绍了基于Pixhawk飞控与OpenMV视觉模块的无人机精准降落系统设计与实现。系统通过OpenMV识别Apriltag标签,结合MAVLink通信将视觉数据发送给Pixhawk,实现厘米级精准降落。文章涵盖硬件连接、软件配置、核心代码逻辑解析及实战调试技巧,为无人机自动充电、物流配送等场景提供可靠解决方案。

weixin_29189377的博客 320

串行化和反串行化

串行化是指存储和获取磁盘文件、内存或其他地方中的对象。在串行化时,所有的实例数据都保存到存储介质上, 在取消串行化时,对象会被还原,且不能与其原实例区别开来。只需给类添加Serializable属性,就可以实现串行化实 的成员。 反串行化是串行化的逆过程,数据从存储介质中读取出来,并赋给类的实例变量。 串行化/序列化:将java对象转换成某种格式(JVM定义的)的字节数组 串行化使用场景: 将对...

weixin_45822638的博客 3451

uniapp实战:mui-player插件如何完美适配m3u8/flv直播流(附完整代码)

本文详细介绍了如何在Uniapp中使用mui-player插件完美适配m3u8和flv直播流,提供从基础配置到高级优化的全流程解决方案。通过动态加载策略、响应式布局和内存管理,实现跨平台稳定播放,适用于企业级直播应用开发。

weixin_29001655的博客 237

数据库事务隔离级别“串行化(Serializable)”代码演示

串行化(Serializable)(行读作xing)是事务隔离级别的最高级别,它确保事务按照顺序依次执行,避免了并发事务之间的相互干扰。在这种隔离级别下,系统会强制所有事务以一种完全串行的方式执行,即一个事务必须在另一个事务完成之后才能开始。这种方式可以彻底避免脏读、不可重复读和幻读等问题,从而保证数据的一致性和可靠性。

跟佟格湾一起学习计算机知识吧~ 1170

推荐系统召回总结(持续更新)

推荐系统架构 候选池:可供推荐的物料候选池,对于图文、短视频、新闻等来说通常是最近N天的新物料组成的集合,定期进行物料更新。 召回:从候选池中选出和用户相关的物料,交给后面的排序模块进行打分。召回面对的候选集通常是数十万或者百万甚至千万的量级,检索过程必须轻量快速。通常由多路召回组成,保证不遗漏且相关性、多样性尽量好,可以分为非个性化召回和个性化召回。 粗排:对召回选择的几千或者几百候选物料进行排序,快速打分选出topN,减少精排的压力,兼顾精准与效率。 精排:对粗排的结果进行精准排序,这个环节需要特征尽可

whgyxy的博客 2515

MuJoCo柔性体仿真实战:从FlexComp建模到自定义模型导入

柔性体仿真是机器人交互研究中不可或缺的一环,MuJoCo作为高精度物理求解器,凭借高效的求解速度与批量并行能力,成为强化学习与软体抓取任务的热门选择。其FlexComp机制将连续材料离散为粒子-约束系统,以较低建模成本模拟布料、软组织等形变行为,相比Gazebo等平台更具实时性与可扩展性。技术价值体现在自定义柔性体建模与导入流程中:通过XML配置网格密度、间距与材料参数,即可生成贴合任务需求的软体垫子或硅胶抓手。在柔性抓取、颗粒抓手、医疗仿真等场景中,该方法能快速构建可训练的环境。围绕环境搭建、FlexCo

weixin_29045585的博客 161

VC++串行化(Serialization)

串行化(Serialization)http://www.vckbase.com/document/viewdoc/?id=918

梦的归宿 1108

2026.2.11:ollama api推理GLM-OCR模型识别图片

本文介绍了使用Ollama API调用GLM-OCR模型进行图片文字识别的过程。首先通过ollama pull glm-ocr:latest命令拉取模型,然后使用Python脚本调用API接口。代码示例展示了如何发送包含图片路径的请求,并处理返回的识别结果,支持文本、公式和表格三种识别模式。运行结果展示了模型对输入图片的识别效果,为开发者提供了便捷的OCR解决方案。

拥抱具身智能,昇腾Ascend C 368

对象的串行化(Serialization)和反串行化(deserialization)

串行化(serialization)是指将一个对象的当前状态转换成字节流(a stream of bytes)的过程,而反串行化(deserialization)则指串行化过程的逆过程,将字节流转换成一个对象,[color=red]打回原形[/color]。 一、串行化的意义: 1:解决Web应用程序的无状态弊端 一旦将某一对象串行化,得到的字节可以存储在文件、数据库,或内存中—— 只要是可...

xinking520的专栏 1654

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java中串行化什么意思_Java中对象的串行化(serialization)和transient关键字

原标题:Java中对象的串行化(serialization)和transient关键字本文摘自《Java程序员面试宝典》(电子工业出版社2017年4月版)串行化的概念和目的什么是串行化对象寿命随着生成该对象的程序终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。对象的这种能记录自己的状态以便将来再生的能力叫做对象的持续性(persistence)。对象通过描述自己状态的数值来...

weixin_28937395的博客 755

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

对象的串行化(Serialization)

一、串行化的概念和目的  1.什么是串行化              对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的串行化(Serialization) 。串行化

蚂蚁的专栏 4618

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Java中对象的串行化(Serialization)和transient关键字

Java中对象的串行化(Serialization)和transient关键字前言:该篇文章参考自网上资料,但是部分内容经过笔者更改,因此算作原创吧,原文地址:http://www.goldenbg.com/article.asp?id=710一、串行化的概念和目的1.什么是串行化对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下

hbcui1984的专栏 1万+

MFC 串行化(Serialization)

串行化是微软提供的用于对对象进行文件I/O的一种机制,该机制在框架(Frame)/文档(Document)/视图(View) 模式中得到了很好的应用。很多人对什么是串行化、怎么使对象具有串行化能力和如何使用串行化功能等问题都不甚明了。本文试图对串行化做一个简单的解释。由于本人对串行化功能使用的也不多,不足之处敬请谅解。 MFC 框架/文档/视图结构中的文件读写 CFile是MFC类库中所

u010628991的专栏 751

java对象串行化_Java中对象的串行化(Serialization)和transient关键字

Java中对象的串行化(Serialization)和transient关键字一、串行化的概念和目的1.什么是串行化对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的串行化(Serial...

weixin_32258691的博客 709
上一篇: 系列化入门读物-PART 3
下一篇: MFC浅析(1) 文档视图结构中,缺省的命令处理
metasearch
博客等级 码龄21年 158粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值