数据库编程总结2.docx

上传人:H****o 文档编号:13053877 上传时间:2022-04-27 格式:DOCX 页数:24 大小:63.26KB
返回 下载 相关 举报
数据库编程总结2.docx_第1页
第1页 / 共24页
数据库编程总结2.docx_第2页
第2页 / 共24页
点击查看更多>>
资源描述

《数据库编程总结2.docx》由会员分享,可在线阅读,更多相关《数据库编程总结2.docx(24页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、精品名师归纳总结当前各种主流数据库有许多,包括Oracle,MSSQLServer,Sybase, Informix,MySQL,DB2, Interbase/ Firebird, PostgreSQL, SQLite, SAP/DB, TimesTen, MS ACCESS等等。数据库编程是对数据库的创建、读写等一列的操作。数据库编程分为数据库客户端编程与数据库服务器端编程。数据库客户端编程主要使用 ODBC API、ADO、ADO.NET、OCI、OTL等方法。数据库服务端编程主要使用OLE DB等方法。数据库编程需要把握一些拜访数据库技术方法,仍需要留意怎么设计高效的数据库、数据库治理与

2、运行的优化、数据库语句的优化。一、拜访数据库技术方法数据库编程分为数据库客户端编程与数据库服务器端编程。数据库客户端编程主要使用ODBCAPI 、ADO、ADO.NET、OCI、OTL等方法。数据库服务端编程主要使用 OLE DB等方法。1、几种是数据库拜访方法比较ODBC API是一种适合数据库底层开发的编程方法,ODBC API 供应大量对数据源的操作,ODBC API 能够敏捷的操作游标 , 支持各种帮定选项, 在全部 ODBC相关编程中 ,API 编程具有最高的执行速度。DAO供应了很好的数据库编程的对象模型. 但是 , 对数据库的全部调用以及输出的数据都必需通过Access/Jet数

3、据库引擎 , 这对于使用数据库应用程序, 是严峻的瓶颈。OLEDB供应了 COM接口,与传统的数据库接口相比,有更好的健壮性和敏捷性,具有很强的错误处理才能, 能够同非关系数据源进行通信。ADO最主要的优点在于易于使用、速度快、内存支出少和磁盘遗迹小。ADO.NET是利用数据集的概念将数据库数据读入内存中,然后在内存中对数据进行操作,最终将数据集数据回写到源数据库中。OTL 是 Oracle, Odbc and DB2-CLI Template Library的缩写,是一个C+编译中操控关系数据库的模 板库, OTL 中直接操作Oracle 主要是通过Oracle 供应的 OCI 接口进行,进

4、行操作 DB2数据库就是通过CLI 接口来进行,至于MS的数据库和其它一些数据库,就OTL只供应了 ODBC来操作的方式。当然Oracle 和DB2也可以由 OTL间接使用 ODBC的方式来进行操纵。具有以下优点:跨平台。运行效率高,与 C 语言直接调用 API 相当。开发效率高,起码比 ADO.net 使用起来更简洁,更简洁。部署简洁,不需要 ADO组件,不需要 .net framework 等。2、VC数据库编程几种方法VC数据库编程几种方法,包括ODBC连接、 MFCODBC连接、 DAO连接、 OLEDB、OLEDB Templates 连接、ADO、Oracle 专用方法 OCIOr

5、acle Call Interface拜访、 Oracle Object OLE C+ Class Library 。 通用方法1. ODBC连接ODBCOpen DataBase Connectivity是 MSOA的一部分 , 是一个标准数据库接口。它供应对关系数据库拜访的统一接口 , 实现对异构数据源的一样拜访。可编辑资料 - - - 欢迎下载精品名师归纳总结ODBC数据拜访由以下部分组成:句柄 Handles:ODBC 使用句柄来标识ODBC环境、连接、语句和描述器.缓存区 Buffers:数据类型 Data types一样性级别 Conformance levels用 ODBC设计客

6、户端的一般步骤:安排 ODBC环境安排连接句柄连接数据源构造和执行SQL语句获得查询结果断开数据源的连接释放 ODBC环境ODBC API是一种适合数据库底层开发的编程方法 ,ODBC API 供应大量对数据源的操作 ,ODBC API 能够敏捷的操作游标 , 支持各种帮定选项 , 在全部 ODBC相关编程中 ,API 编程具有最高的执行速度 . 因此 ,ODBC API 编程属于底层编程。2. MFC ODBC连接MFCODBC是 MFC对 ODBC进行的封装 , 以简化对ODBCAPI 的 调用 , 从而实现面对对象的数据库编程接口.MFC ODBC的封装主要开发了CDatabase 类和

7、 CRecordSet 类(1) CDatabase类CDatabase 类用于应用程序建立同数据源的连接。 CDatabase 类中包含一个 m_hdbc变量 , 它代表了数据源的连接句柄。假如要建立 CDatabase 类的实例 , 应先调用该类的构造函数 , 再调用 Open 函数, 通过调用 , 初始化环境变量 , 并执行与数据源的连接。在通过 Close 函数关闭数据源。CDatabase 类供应了对数据库进行操作的函数及事务操作。(2) CRecordSet类CRecordSet 类定义了从数据库接收或者发送数据到数据库的成员变量, 以实现对数据集的数据操作。可编辑资料 - - -

8、 欢迎下载精品名师归纳总结CRecordSet 类的成员变量m_hstmt 代表了定义该记录集的SQL语句句柄 ,m_nFields为记录集中字段的个数 ,m_nParams 为记录集所使用的参数个数。CRecordSet 的记录集通过CDatabase 实例的指针实现同数据源的连接, 即 CRecordSet 的成员变量m_pDatabase.MFCODBC编程更适合于界面型数据库应用程序的开发, 但由于 CDatabase 类和 CRecordSet 类供应的数据库操作函数有限 , 支持的游标类型也有限, 限制了高效的数据库开发。在编程层次上属于高级编程。应用实例:1. 打开数据库CDat

9、abase database;database.OpenEx _T DSN=zhuxue ,CDatabase:noOdbcDialog;/zhuxue为数据源名称2. 关联记录集CRecordset recset&database;3. 查询记录CString sSql1=;sSql1 = SELECT * FROM tablename ; recset.OpenCRecordset:forwardOnly, sSql1, CRecordset:readOnly;int ti=0;CDBVariant var;/var可以转换为其他类型的值while .recset.IsEOF/ 读取 Ex

10、cel 内部数值recset.GetFieldValueid,var; jiangxiangti.id=var.m_iVal; recset.GetFieldValuename, jiangxiangti.name; ti+;recset.MoveNext;recset.Close;/关闭记录集4. 执行 sql 语句可编辑资料 - - - 欢迎下载精品名师归纳总结CString sSql=;sSql+=delete * from院系审核 ;/清空表database.ExecuteSQLsSql;sSql 也可以为 Insert ,Update等语句5. 读取字段名sSql = SELECT

11、* FROM Sheet1 ; /读取的文件有Sheet1 表的定义 , 或为本程序生成的表./执行查询语句recset.OpenCRecordset:forwardOnly, sSql, CRecordset:readOnly; int excelColCount=recset.GetODBCFieldCount;/列数 CString excelfield30;/ 得到记录集的字段集合中的字段的总个数for i=0;iexcelColCount;i+CODBCFieldInfo fieldinfo; recset.GetODBCFieldInfoi,fieldinfo;excelfield

12、i.name =fieldinfo.m_strName;/字段名6. 打开 excel文件CString sDriver = MICROSOFT EXCEL DRIVER *.XLS; / Excel安装驱动CString sSql,sExcelFile; /sExcelFile为 excel 的文件路径TRY/创建进行存取的字符串sSql.FormatDRIVER=%s;DSN=;FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=%s;DBQ=%s,sDriver, sExcelFile, sExcelFile;/创建数据库 既 Excel 表格文件 i

13、f database.OpenExsSql,CDatabase:noOdbcDialog / 可以把 excel 作为一个数据库操作catcheTRACE1Excel 驱动没有安装 : %s,sDriver;可编辑资料 - - - 欢迎下载精品名师归纳总结AfxMessageBox 读取失败 , 请检查是否定义数据区Sheet1;3. DAO 连接DAOData Access Object是一组 Microsoft Access/Jet数据库引擎的COM自动化接口 .DAO直接与Access/Jet数据库通信 . 通过 Jet 数据库引擎 ,DAO 也可以同其他数据库进行通信。DAO仍封装了

14、Access 数据库的结构单元 , 通过 DAO可以直接修改Access 数据库的结构 , 而不必使用SQL的数据定义语言 DDL 。DAO的体系结构如下:DAO封装的类:(1) CdaoWorkspace: 对 DAO工作区 数据库处理事务治理器 的封装(2) CdaoDatabase: 对 DAO数据库对象的封装, 负责数据库连接 .(3) CdaoRecordset:对 DAO记录集对象的封装, 代表所选的一组记录.(4) CdaoTableDef:对表定义对象的封装, 代表基本表或附加表定义.(5) CdaoQueryDef: 对查询对象的封装, 包含全部查询的定义.(6) CdaoE

15、xception:DAO用于接收数据库操作反常的类. 7CDaoFieldExchangeDAO供应了很好的数据库编程的对象模型. 但是 , 对数据库的全部调用以及输出的数据都必需通过Access/Jet数据库引擎 , 这对于使用数据库应用程序, 是严峻的瓶颈。DAO相对于 ODBC来说,属于高层的数据库接口.4. OLE DB 连接OLEDB对 ODBC进行了两方面的扩展: 一是供应了数据库编程的OLE接口即 COM,二是供应了一个可用于关系型和非关系型数据源的接口。OLEDB供应了 COM接口,与传统的数据库接口相比,有更好的健壮性和敏捷性,具有很强的错误处理才能, 能够同非关系数据源进行

16、通信。与 ODBC API一样 ,OLE DB 也属于底层的数据库编程接口,OLE DB 结合了 ODBC对关系数据库的操作功能,并进行扩展,可以拜访非关系数据库。OLE DB拜访数据库的原理如下: OLE DB程序结构 :可编辑资料 - - - 欢迎下载精品名师归纳总结OLE DB由客户 Consumer 和服务器 Provider。客户是使用数据的应用程序,它通过OLE DB接口对数据供应者的数据进行拜访和掌握。OLE DB服务器是供应OLE DB 接口的软件组件。依据供应的内容可以分 为数据供应程序 Data Provider和服务供应程序 Service Provider。程序结构原理

17、图如下:数据供应程序数据供应程序拥有自己的数据并把数据以表格的形式出现给使用者使用.服务供应程序服务供应程序是数据供应程序和使用者的结合。它是OLE DB体系结构中的中间件, 它是 OLE DB数据源的使用者和数据使用程序的供应者数据使用程序数据使用程序对储备在数据供应程序中的数据进行使用和掌握. OLE DB开发程序的一般步骤:初始化 COM环境连接数据源打开对话执行命令处理结果清除对象应用实例:使用 OLEDB编写数据库应用程序1 概述OLE DB的存在为用户供应了一种统一的方法来拜访全部不同种类的数据源。OLE DB可以在不同的数据源中进行转换。利用OLE DB,客户端的开发人员在进行数

18、据拜访时只需把精力集中在很少的一些细节上,而不必弄懂大量不同数据库的拜访协议。OLE DB是一套通过 COM接口拜访数据的 ActiveX 接口。这个 OLE DB接口相当通用,足以供应一种拜访数据的统一手段,而不管储备数据所使用的方法如何。同时, OLE DB仍答应开发人员连续利用基础数据库技术的优点,而不必为了利用这些优点而把数据移出来。可编辑资料 - - - 欢迎下载精品名师归纳总结2 使用 ATL 使用 OLE DB数据使用程序由于直接使用OLE DB的对象和接口设计数据库应用程序需要书写大量的代码。为了简化程序设计, Visual C+ 供应了 ATL 模板用于设计OLE DB数据应

19、用程序和数据供应程序。利用 ATL 模板可以很简洁的将OLE DB与 MFC结合起来,使数据库的参数查询等复杂的编程得到简化。 MFC供应的数据库类使OLE DB的编程更具有面对对象的特性。Viual C+ 所供应用于OLE DB的 ATL 模板可分为数据供应程序的模板和数据使用程序的模板。使用 ATL 模板创建数据应用程序一般有以下几步骤:1)、创建应用框架2)、加入 ATL 产生的模板类3)、在应用中使用产生的数据拜访对象3 不用 ATL 使用 OLE DB数据使用程序利用 ATL 模板产生数据使用程序较为简洁,但适用性不广,不能动态适应数据库的变化。下面我们介绍直接使用 MFC OLE

20、DB类来生成数据使用程序。模板的使用OLE DB数据使用者模板是由一些模板组成的,包括如下一些模板,下面对一些常用类作一些介绍。1)、会话类CDataSource 类CDataSource 类与 OLE DB的数据源对象相对应。这个类代表了OLE DB数据供应程序和数据源之间的连接。只有当数据源的连接被建立之后,才能产生会话对象,可以调用Open 来打开数据源的连接。CSession 类CSession 所创建的对象代表了一个单独的数据库拜访的会话。一个用 CDataSource 类产生的数据源对象可以创建一个或者多个会话,要在数据源对象上产生一个会话对象,需要调用函数Open 来打开。同时,

21、会话对象仍可用于创建事务操作。CEnumeratorAccessor 类CEnumeratorAccessor 类是用来拜访枚举器查询后所产生的行集中可用数据供应程序的信息的拜访器, 可供应当前可用的数据供应程序和可见的拜访器。2)、拜访器类可编辑资料 - - - 欢迎下载精品名师归纳总结CAcessor 类CAccessor 类代表与拜访器的类型。当用户知道数据库的类型和结构时,可以使用此类。它支持对一个行集采纳多个拜访器,并且,存放数据的缓冲区是由用户安排的。CDynamicAccessor 类CDynamicAccessor 类用来在程序运行时动态的创建拜访器。当系统运行时, 可以动态的

22、从行集中获得列的信息,可依据此信息动态的创建拜访器。CManualAccessor 类CManualAccessor 类中以在程序运行时将列与变量绑定或者是将参数与变量捆定。3)、行集类CRowSet类CRowSet类封装了行集对象和相应的接口,并且供应了一些方法用于查询、设置数据等。 可以用 Move()等函数进行记录移动,用GetData 函数读取数据,用Insert、Delete、SetData 来更新数据。CBulkRowset 类CBulkRowset 类用于在一次调用中取回多个行句柄或者对多个行进行操作。CArrayRowset 类CArrayRowset 类供应用数组下标进行数据

23、拜访。4)、命令类CTable 类CTable 类用于对数据库的简洁拜访,用数据源的名称得到行集,从而得到数据。CComman类dCComman类d 用于支持命令的数据源。可以用Open 函数来执行SQL命令,也可以 Prepare ()函数先对命令进行预备,对于支持命令的数据源,可以提高程序的敏捷性和健壮性。在 stdafx.h头文件里,加入如下代码。#include extern CComModule _Module;#include #include #include / if you are using schema templates可编辑资料 - - - 欢迎下载精品名师归纳总结在

24、 stdafx.cpp文件里,加入如下代码。#include CComModule _Module;打算使用何种类型的存取程序和行集。猎取数据在打开数据源,会话,行集对象后就可以猎取数据了。所猎取的数据类型取决于所用的存取程序,可能需要绑定列。按以下步骤。1、 用正确的命令打开行集对象。2、 假如使用 CManualAccessor ,在使用之前与相应列进行绑定。要绑定列, 可以用函数GetColumnInfo,如下所示:/ Get the column information ULONG ulColumns = 0;DBCOLUMNINFO* pColumnInfo = NULL; LPOL

25、ESTR pStrings = NULL;if rs.GetColumnInfo&ulColumns, &pColumnInfo, &pStrings .= S_OK AfxThrowOLEDBExceptionrs.m_pRowset, IID_IColumnsInfo;struct MYBIND* pBind = new MYBINDulColumns; rs.CreateAccessorulColumns, &pBind0, sizeofMYBIND*ulColumns; for ULONG l=0; lulColumns; l+rs.AddBindEntryl+1, DBTYPE_ST

26、R, sizeofTCHAR*40, &pBindl.szValue, NULL, &pBindl.dwStatus;rs.Bind;3、 用 while循环来取数据。在循环中,调用MoveNext 来测试光标的返回值是否为S_OK,如下所示: while rs.MoveNext = S_OK/ Add code to fetch data here/ If you are not using an auto accessor, call rs.GetData4 、 在 while循环内,可以通过不同的存取程序猎取数据。1) 假如使用的是CAccessor 类,可以通过使用它们的数据成员进行直

27、接拜访。如下所示:2) 假如使用的是CDynamicAccessor 或 CDynamicParameterAccessor类,可以通过GetValue 或GetColumn 函数来猎取数据。可以用GetType 来猎取所用数据类型。如下所示:while rs.MoveNext = S_OK/ Use the dynamic accessor functions to retrieve your/ data可编辑资料 - - - 欢迎下载精品名师归纳总结ULONG ulColumns = rs.GetColumnCount; for ULONG i=0; iulColumns; i+rs.Ge

28、tValuei;3) 假如使用的是CManualAccessor, 可以指定自己的数据成员,绑定它们。 就可以直接存取。 如下所示:while rs.MoveNext = S_OK/ Use the data members you specified in the calls to/ AddBindEntry. wsprintf%s, szFoo;打算行集的数据类型在运行时打算数据类型,要用动态或手工的存取程序。假如用的是手工存取程序,可以用 GetColumnInfo函数得到行集的列信息。从这里可以得到数据类型。4 总结由于现在有多种数据源,想要对这些数据进行拜访治理的唯独途径就是通过一些

29、同类机制来实现,如OLE DB。高级 OLE DB结构分成两部分:客户和供应者。客户使用由供应者生成的数据。就像其它基于COM的多数结构一样,OLE DB的开发人员需要实现许多的接口,其中大部分是模板文件。 当生成一个客户对象时,可以通过ATL 对象向导指向一个数据源而创建一个简洁的客户。ATL 对象向导将会检查数据源并创建数据库的客户端代理。从那里,可以通过OLE DB客户模板使用标准的浏览函数。当生成一个供应者时,向导供应了一个很好的开端,它们仅仅是生成了一个简洁的供应者来列举某一目录下的文件。然后,供应者模板包含了OLEDB支持的完全补充内容。在这种支持下,用户可以创建OLEDB供应者,

30、来实现行集定位策略、数据的读写以及建立书签。应用案例:Visual C+ 中使用 OLE DB读写 SQL Server在需要对数据库进行操作时,OLEDB总是被认为是一种效率最高但最难的方法。但是以我最近使用OLEDB的体会看来, OLEDB的效率高就高矣, 但却一点都不难。 说它难唯恐主要是由于可参考的中文资料太少, 为了帮忙以后需要接触OLE DB的同行,我撰写了这篇文章。本文包含如下内容:1. OLE DB 写数据库。2. OLE DB 读数据库。可编辑资料 - - - 欢迎下载精品名师归纳总结3. OLE DB 对二进制数据 text、ntext 、image 等 的处理。第一来看看

31、对SQL Server 进行写操作的代码,有肯定VC基础的读者应当可以很顺当的看懂。OLE DB写数据库,就是这么简洁!注:1. 以下代码中使用的模板类EAutoReleasePtr 与 ATL 中的 CComPtr类似,是一个在析构时自动调用 Release 的类。 CComPtr的代码在 ATLBASE.H中定义。2. 以下代码均在UNICODE环境下编译,由于执行的SQL语句必需是 UNICODE的。设置工程为UNICODE的方法是 : 第一在 project-settings-C/C+的属性页中的Preprocessor中,删除 _MBCS写入UNICODE,_UNICOD。E然后在

32、link属性页中 Category 中挑选 output ,在 Entry-Point symbol中添加wWinMainCRTStartup 。EAutoReleasePtr pIDBInitialize;HRESULThResult= ConnectDatabase&pIDBInitialize,_T127.0.0.1,_T“sa ”,_Tpassword; if FAILED hResult / 失败,可能是由于数据库没有启动、用户名密码错等等return;EAutoReleasePtr pIOpenRowset; hResult = CreateSession pIDBInitiali

33、ze, &pIOpenRowset ; if FAILED hResult / 出错return;EAutoReleasePtr pICommand; EAutoReleasePtr pICommandText;hResult = CreateCommand pIOpenRowset, &pICommand, &pICommandText ; if FAILED hResult / 出错return;可编辑资料 - - - 欢迎下载精品名师归纳总结hResult = ExecuteSQL pICommand, pICommandText, _TUSE PBDATA ;if FAILED hRe

34、sult / 假如这里失败,那就是SQL语句执行失败。在此处,就是PBDATA仍未创建return;/创建表ExecuteSQL pICommand, pICommandText, _TCREATE TABLE 2005_1Volume real NOT NULL,ID int NOT NULL IDENTITY ;/添加记录ExecuteSQL pICommand, pICommandText, _TINSERT INTO 2005_1 VALUES100.0 ;/.其中几个函数的代码如下:HRESULT ConnectDatabase IDBInitialize* ppIDBInitial

35、ize, LPCTSTR pszDataSource, LPCTSTR pszUserID, LPCTSTR pszPassword ASSERT ppIDBInitialize .= NULL & pszDataSource .= NULL & pszUserID .= NULL & pszPassword .= NULL ;UINT uTimeout 15U; /连接数据库超时(秒)TCHAR szInitStr1024;VERIFY 1023 = wsprintf szInitStr, _TProvider=SQLOLEDB;Data Source=%s;Initial Catalog=

36、master;User Id=%s;Password=%s;Connect Timeout=%u, pszDataSource, pszUserID, pszPassword, uTimeout ;/Initial Catalog=master指明连接胜利后,USE master 。EAutoReleasePtr pIDataInitialize;HRESULT hResult = :CoCreateInstance CLSID_MSDAINITIALIZE, NULL, CLSCTX_INPROC_SERVER,IID_IDataInitialize, void* &pIDataInitia

37、lize ;if FAILED hResult return hResult;可编辑资料 - - - 欢迎下载精品名师归纳总结EAutoReleasePtr pIDBInitialize;hResult= pIDataInitialize-GetDataSourceNULL, CLSCTX_INPROC_SERVER, LPCOLESsTzRInitStr, IID_IDBInitialize, IUnknown* &pIDBInitialize ;if FAILED hResult return hResult;hResult = pIDBInitialize-Initialize ; if

38、 FAILED hResult return hResult;* ppIDBInitialize = pIDBInitialize.Detach ; return S_OK;HRESULT CreateSession IDBInitialize* pIDBInitialize, IOpenRowset* ppIOpenRowset ASSERT pIDBInitialize .= NULL & ppIOpenRowset .= NULL ;EAutoReleasePtr pSession;HRESULT hResult = pIDBInitialize-QueryInterface IID_I

39、DBCreateSession, void* &pSession ; if FAILED hResult return hResult;EAutoReleasePtr pIOpenRowset;hResult = pSession-CreateSession NULL, IID_IOpenRowset, IUnknown* &pIOpenRowset ; if FAILED hResult return hResult;* ppIOpenRowset = pIOpenRowset.Detach ; return S_OK;HRESULT CreateCommand IOpenRowset* p

40、IOpenRowset, ICommand* ppICommand, ICommandText* ppICommandText ASSERT pIOpenRowset .= NULL & ppICommand .= NULL & ppICommandText .= NULL ;可编辑资料 - - - 欢迎下载精品名师归纳总结HRESULT hResult; EAutoReleasePtr pICommand;EAutoReleasePtr pICreateCommand;hResult = pIOpenRowset-QueryInterface IID_IDBCreateCommand, vo

41、id* &pICreateCommand ; if FAILED hResult return hResult;hResult = pICreateCommand-CreateCommand NULL, IID_ICommand, IUnknown*&pICommand ; if FAILED hResult return hResult;EAutoReleasePtr pICommandText; hResult = pICommand-QueryInterface &pICommandText ; if FAILED hResult return hResult;* ppICommand = pICommand.Detach ;* ppICommandText = pICommandText.Detach ;return S_OK;HRESULT Execute

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 技术总结

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁