游戏开发论坛

 找回密码
 立即注册
搜索
查看: 3091|回复: 4

直接读取xls文件, 转换成ini

[复制链接]

13

主题

66

帖子

85

积分

注册会员

Rank: 2

积分
85
发表于 2006-8-7 18:52:00 | 显示全部楼层 |阅读模式
// 设计目的: 直接读取xls文件, 替代ini
// Open与Close必须成对出现,否则将不能再次读取数据
// 打开一个xls文件的消耗非常大,所以不要在游戏循环里做Open

#pragma once

#ifndef _WINDOWS_
#include <afxdisp.h>
#include <afxdb.h>
#endif

#include <odbcinst.h>

#include <string>
#include <vector>
#include <map>

class YXLSReader
{
public:
        YXLSReader();

        virtual ~YXLSReader();

        // 装载xls文件
        // pFile:        xls文件名
        // pTable:        表头名
        BOOL                        Open(const LPSTR pFile, const LPSTR pTable);

        // 清除内存中所有表单数据
        VOID                        Close();

        // 得到一个浮点数
        // nRowID:                excel表中第一列的数字ID号
        // lpKey:                excel表中自定义的第一排的属性项
        // fDefault:        如果读取失败返回一个默认值
        FLOAT                        GetFloat(size_t nRowID, LPSTR lpKey, FLOAT fDefault);

        // 得到一个整数
        // nRowID:                excel表中第一列的数字ID号
        // lpKey:                excel表中自定义的第一排的属性项
        // nDefault:        如果读取失败返回一个默认值
        UINT                        GetInt(size_t nRowID, LPSTR lpKey, UINT nDefault);

        // 得到一个字符串
        // nRowID:                excel表中第一列的数字ID号
        // lpKey:                excel表中自定义的第一排的属性项
        // lpDefault:        如果读取失败返回一个默认值
        // lpOut:                输出缓冲
        // dwSize:                输出缓冲大小
        VOID                        GetString(size_t nRowID, LPSTR lpKey, LPSTR lpDefault, LPSTR lpOut, DWORD dwSize);

        // 得到一个字符串
        // nRowID:                excel表中第一列的数字ID号
        // lpKey:                excel表中自定义的第一排的属性项
        VOID                        GetString(size_t nRowID, LPSTR lpKey, LPSTR lpDefault, std::string& strOut);

        // 得到第 nRowID 行所有key 对应的字符串形式值
        // pair-first: key
        // pair-second: value
        BOOL                        GetStringRow(size_t nRowID, std::vector<std::pair<std::string, std::string> >& vOut);


        // 得到一共有多少行
        size_t                        GetTotalRow() { return m_vIniFormat.size(); }

        // 分析一个字符串的类型
        // 返回 1 整形                例如        -1                0                100
        //                2 浮点                例如        0.1                1.93        -10.2
        //                3 字符串        例如        aa                bbs                ddees
        int                                GetType(const std::string& strIn);

        int                                GetType(const LPSTR pIn);

private:

        BOOL                        GetDriver(std::string& strDriver);

        BOOL                        GetValue(size_t nRowID, LPSTR lpKey, std::map<std::string, std::string>::iterator& iter);

private:

        std::vector<std::map<std::string, std::string> >        m_vIniFormat;

        BOOL                        m_bOpen;
};

//------------------------------------------------------------------------------------------------


#include "xlsReader.h"
#include <algorithm>


YXLSReader::~YXLSReader()
{
        m_vIniFormat.clear();
}

YXLSReader::YXLSReader()
{
        m_bOpen = FALSE;
}


BOOL YXLSReader::GetDriver(std::string& strDriver)
{
        CHAR cBuf[2000];
        WORD wBufOut;

        if( !SQLGetInstalledDrivers( cBuf, 2000, &wBufOut) )
                return FALSE;
       
        PCHAR pBuf = cBuf;
        do
        {
                if( strstr( pBuf, "Excel" ) != 0 )
                {
                        strDriver = pBuf;
                        return TRUE;
                }
                pBuf = strchr( pBuf, '\0' ) + 1;

        }while( pBuf[1] != '\0' );

        return FALSE;
}

BOOL YXLSReader::Open(const LPSTR pFile, const LPSTR pTable)
{
        if( m_bOpen )
                return FALSE;

        CString sDsn;
        std::string strDriver;
        if( !GetDriver( strDriver ) )
                return FALSE;

        CHAR cDsn[1024];
        sprintf( cDsn, "DRIVER={%s};DSN='''';FIRSTROWHASNAMES=1;READONLY=TRUE;DBQ=%s", strDriver.c_str(), pFile );

        CDatabase* pDatabase = new CDatabase;

        try
        {
                if( !pDatabase->OpenEx( cDsn, CDatabase:penReadOnly | CDatabase::noOdbcDialog ) )
                {
                        pDatabase->Close();
                        return FALSE;
                }
        }

        catch(...)
        {
                pDatabase->Close();
                return FALSE;
        }

        CRecordset* pSheet = new CRecordset( pDatabase );
        CHAR cSQL[1024];

        sprintf( cSQL, "SELECT * FROM [%s$A1:IV65536]", pTable );

        try
        {
                if( !pSheet->Open( AFX_DB_USE_DEFAULT_TYPE, cSQL, CRecordset::readOnly ) )
                {
                        pSheet->Close();
                        pDatabase->Close();
                        return FALSE;
                }
        }

        catch(...)
        {
                pSheet->Close();
                pDatabase->Close();

                return FALSE;
        }

        std::vector<std::string> vRowKey;
        if( pSheet->m_nResultCols )
        {
                // 读出所有key
                for( SWORD i = 0; i < pSheet->m_nResultCols; ++i )
                {
                        if( find( vRowKey.begin(), vRowKey.end(), pSheet->m_rgODBCFieldInfos.m_strName.GetBuffer() ) != vRowKey.end() )
                        {
                                // 有重复key输出警告
                                printf( "warning: same key %s\n", pSheet->m_rgODBCFieldInfos.m_strName.GetBuffer() );
                                continue;
                        }

                        vRowKey.push_back( /*strlwr(*/ pSheet->m_rgODBCFieldInfos.m_strName.GetBuffer() /*)*/ );
                }
        }

        std::map<std::string, std::string> mTemp;

        int nCount(0);
        while( !pSheet->IsEOF() )
        {
                mTemp.clear();
                for( SWORD i = 0; i < pSheet->m_nResultCols; ++i )
                {
                        CString strValue;
                        pSheet->GetFieldValue( i, strValue );

                        // 去除整数后面的"."如6在excel中表示为6.0
                        std::string strTemp( strValue );

                        std::string::size_type nPos = strTemp.find( "." );
                        std::string::size_type nPosBak(nPos++);
                        bool bDelete(true);
                        if( nPos != std::string::npos )
                        {
                                for( ; nPos < strTemp.size(); ++nPos )
                                {
                                        if( strTemp[nPos] != '0' )
                                        {
                                                bDelete = false;
                                                break;
                                        }
                                }
                        }

                        if( bDelete && nPosBak != std::string::npos )
                                strTemp.erase( strTemp.begin() + nPosBak, strTemp.end() );

                        std::string strKey = vRowKey;
                        mTemp[vRowKey] = strTemp/*strlwr( strValue.GetBuffer() )*/;
                }

                m_vIniFormat.push_back( mTemp );
                pSheet->MoveNext();
        }               

        pSheet->Close();
        pDatabase->Close();
        m_bOpen = TRUE;
        delete pSheet;
        delete pDatabase;

        return TRUE;
}


VOID YXLSReader::Close()
{
        m_bOpen = FALSE;
        m_vIniFormat.clear();
}

BOOL YXLSReader::GetValue(size_t nRowID, LPSTR lpKey, std::map<std::string, std::string>::iterator& iter)
{
        if( nRowID > m_vIniFormat.size() + 1 || nRowID <= 1 )
                return FALSE;

        iter = m_vIniFormat[nRowID-2].find( lpKey );
        if( iter == m_vIniFormat[nRowID-2].end() )
                return FALSE;

        return TRUE;
}

FLOAT YXLSReader::GetFloat(size_t nRowID, LPSTR lpKey, FLOAT fDefault)
{
        std::map<std::string, std::string>::iterator iter;
        if( !GetValue( nRowID, lpKey, iter ) )
                return fDefault;

       
        return float( atof( iter->second.c_str() ) );
}

UINT YXLSReader::GetInt(size_t nRowID, LPSTR lpKey, UINT nDefault)
{
        std::map<std::string, std::string>::iterator iter;
        if( !GetValue( nRowID, lpKey, iter ) )
                return nDefault;

        return UINT( atol( iter->second.c_str() ) );
}


VOID YXLSReader::GetString(size_t nRowID, LPSTR lpKey, LPSTR lpDefault, LPSTR lpOut, DWORD dwSize)
{
        std::map<std::string, std::string>::iterator iter;
        if( !GetValue( nRowID, lpKey, iter ) )
        {
                strncpy( lpOut, lpDefault, dwSize );
                return;
        }

        strncpy( lpOut, iter->second.c_str(), dwSize );
}

VOID YXLSReader::GetString(size_t nRowID, LPSTR lpKey, LPSTR lpDefault, std::string& strOut)
{
        std::map<std::string, std::string>::iterator iter;
        if( !GetValue( nRowID, lpKey, iter ) )
        {
                strOut = lpDefault;
                return;
        }

        strOut = iter->second;
}

BOOL YXLSReader::GetStringRow(size_t nRowID, std::vector<std::pair<std::string, std::string> >& vOut)
{
        if( nRowID > m_vIniFormat.size() + 1 || nRowID <= 1 )
                return FALSE;

        for( std::map<std::string, std::string>::iterator iter = m_vIniFormat[nRowID-2].begin(); iter != m_vIniFormat[nRowID-2].end(); ++iter )
        {
                //if( iter->second != "" )
                //        vOut.push_back( *iter );
                std::string strFirst = iter->first;
                std::string strSecond = iter->second;
                vOut.push_back( *iter );
        }

        return TRUE;
}


int YXLSReader::GetType(const std::string& strIn)
{
        // 查看是否有"."
        std::string::size_type nPos = strIn.find( "." );
        // 有可能是个整数或者字符串
        if( nPos == std::string::npos )
        {
                // 判断是否为整数
                for( size_t i = 0; i < strIn.size(); ++i )
                {
                        if( !i && strIn[0] == '-' )
                                continue;

                        if( strIn != '\0' && strIn < '0' || strIn > '9' )
                                return 3;
                }

                return 1;
        }
        else
        {
                // '.'两边都有数字才认为是浮点数
                if( !nPos )
                        return 3;

                if( strIn[nPos-1] < '0'        ||
                        strIn[nPos-1] > '9'        ||
                        strIn[nPos+1] < '0' ||
                        strIn[nPos+1] > '9' )
                        return 3;

                // 判断是否为浮点数
                for( size_t i = 0; i < strIn.size(); ++i )
                {
                        if( !i && strIn[0] == '-' )
                                continue;

                        if( strIn == '.' )
                        {
                                if( i != nPos )
                                        return 3;
                                else
                                        continue;
                        }

                        if( strIn != '\0' && strIn < '0' || strIn > '9' )
                                return 3;
                }

                return 2;
        }
}


int YXLSReader::GetType(const LPSTR pIn)
{
        std::string strIn( pIn );
        return GetType( strIn );
}


//--------------------------------------------------------------------------------------------------------------
#include "xlsReader.h"
#include <hash_map>

#pragma warning( disable: 4996 )

class CTimer
{
public:
        CTimer() { QueryPerformanceFrequency( &m_LargeInt ); m_dfFreq = (double)m_LargeInt.QuadPart; }

        inline void SetBeginPerformace() { QueryPerformanceCounter( &m_LargeInt ); m_nBeginTimes = m_LargeInt.QuadPart; }

        inline void SetEndPerformace() { QueryPerformanceCounter( &m_LargeInt ); m_nEndTimes = m_LargeInt.QuadPart; }

        inline double GetLapseTime() { return (m_nEndTimes - m_nBeginTimes) / m_dfFreq; }

private:

        LONGLONG                        m_nBeginTimes;

        LONGLONG                        m_nEndTimes;

        LARGE_INTEGER                m_LargeInt;

        double                                m_dfFreq;
};


// ------------------------Sec--------------------------------Key----------Value-----------------
typedef std::hash_map<std::string, std::vector<std::pair<std::string, std::string> > > INIFORMAT;

BOOL GetSectionKey(const std::string& strIn, std::string& strSec, std::string& strKey)
{
        std::string::size_type nPos = strIn.find( "@@" );
        if( nPos == std::string::npos )
                return FALSE;

        strSec.clear();
        strKey.clear();

        strSec.insert( strSec.begin(), strIn.begin(), strIn.begin() + nPos );
        strKey.insert( strKey.begin(), strIn.begin() + nPos + 2, strIn.end() );

        return TRUE;
}

int main()
{
        CTimer timer;

        UINT unTotal = GetPrivateProfileInt( "total_export", "count", -1, ".\\config.ini" );
        if( unTotal == -1 )
        {
                printf( "无法获取需要导出的表单总数,请检查config.ini:[total_export]\n" );
                printf( "按Enter键退出\n" );
                getchar();
                return 0;
        }
        else if( !unTotal )
        {
                printf( "没有需要导出的表单, 请检查config.ini:[total_export]\n" );
                printf( "按Enter键退出\n" );
                getchar();
                return 0;
        }

        std::vector<std::pair<std::string, std::string> > vFileSheet;

        for( UINT i = 1; i <= unTotal; ++i )
        {
                char cSec[MAX_PATH], cFile[MAX_PATH], cSheet[MAX_PATH];
                sprintf( cSec, "export_%d", i );
                GetPrivateProfileString( cSec, "file", "", cFile, MAX_PATH, ".\\config.ini" );
                GetPrivateProfileString( cSec, "sheet", "", cSheet, MAX_PATH, ".\\config.ini" );
                vFileSheet.push_back( std::make_pair( cFile, cSheet ) );
        }

        YXLSReader xlsReader;
        for( size_t i = 0; i < vFileSheet.size(); ++i )
        {
                timer.SetBeginPerformace();
                if( !xlsReader.Open( (LPSTR)vFileSheet.first.c_str(), (LPSTR)vFileSheet.second.c_str() ) )
                {
                        printf( "不能打开文件%s的%s表单,此表将被忽略\n", vFileSheet.first.c_str(), vFileSheet.second.c_str() );
                        continue;
                }
                timer.SetEndPerformace();

                printf( "装载%s-%s...用时:%f(ms)\n", vFileSheet.first.c_str(), vFileSheet.second.c_str(), timer.GetLapseTime() * 1000.0f );
                std::vector<std::vector<std::pair<std::string, std::string> > > vTable;
                vTable.resize( xlsReader.GetTotalRow() );
                for( size_t j = 1; j <= xlsReader.GetTotalRow(); ++j )
                {
                        if( !xlsReader.GetStringRow( j + 1, vTable[j-1] ) )
                                DebugBreak();
                }

               
                printf( "数据处理...\n" );
                INIFORMAT hmIniFormat;
                std::string strSaveFile;
                for( size_t j = 0; j < vTable.size(); ++j )
                {
                        for( size_t k = 0; k < vTable[j].size(); ++k )
                        {
                                // 整理具有相同sec的属性项
                                std::string strSec, strKey;
                                if( GetSectionKey( vTable[j][k].first, strSec, strKey ) )
                                {
                                        INIFORMAT::iterator iter = hmIniFormat.find( strSec );
                                        if( iter != hmIniFormat.end() )
                                                iter->second.push_back( std::make_pair( strKey, vTable[j][k].second ) );
                                        else
                                                hmIniFormat[strSec].push_back( std::make_pair( strKey, vTable[j][k].second ) );
                                }
                                else if( vTable[j][k].first == "SaveFile" )
                                {
                                        strSaveFile.clear();
                                        strSaveFile += ".\\\\export\\\\";
                                        strSaveFile += vTable[j][k].second;
                                }
                                else
                                {
                                        if( vTable[j][k].first == "resid" )
                                                continue;

                                        for( size_t x = 0; x < vTable[j].size(); ++x )
                                        {
                                                if( vTable[j][x].first == "resid" )
                                                {
                                                        strSec = "resfile_";
                                                        strSec += vTable[j][x].second;
                                                }
                                        }

                                        INIFORMAT::iterator iter = hmIniFormat.find( strSec );
                                        if( iter != hmIniFormat.end() )
                                                iter->second.push_back( std::make_pair( vTable[j][k].first, vTable[j][k].second ) );
                                        else
                                                hmIniFormat[strSec].push_back( std::make_pair( vTable[j][k].first, vTable[j][k].second ) );
                                }
                        }

                        if( !strSaveFile.empty() )
                        {
                                for( INIFORMAT::iterator iter = hmIniFormat.begin(); iter != hmIniFormat.end(); ++iter )
                                {
                                        for( size_t i = 0; i < iter->second.size(); ++i )
                                                WritePrivateProfileString( iter->first.c_str(), iter->second.first.c_str(), iter->second.second.c_str(), strSaveFile.c_str() );
                                }
                        }

                        hmIniFormat.clear();
                }

                xlsReader.Close();
        }
        printf( "完成,按Enter键退出\n" );
        getchar();
        return 0;
}

33

主题

669

帖子

669

积分

高级会员

Rank: 4

积分
669
QQ
发表于 2006-8-7 20:20:00 | 显示全部楼层

Re:直接读取xls文件, 转换成ini

有意思

30

主题

357

帖子

388

积分

中级会员

Rank: 3Rank: 3

积分
388
QQ
发表于 2006-8-7 22:32:00 | 显示全部楼层

Re:直接读取xls文件, 转换成ini

晕,这样也行啊

8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2006-8-9 10:22:00 | 显示全部楼层

Re:直接读取xls文件, 转换成ini

无法了解这样做的目的何在
为什么不直接用ini
标准的过度设计
请保持KISS原则

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2006-8-9 16:01:00 | 显示全部楼层

Re:直接读取xls文件, 转换成ini

。。。excel可以直接存成.xml。。。
貌似解析xml非常简单的说
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 02:30

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表