关闭

Symbian OS上的文件操作和UNICODE转换

2273人阅读 评论(1) 收藏 举报
         本文整理总结了一下在Symbian系统上进行文件操作的一些体会,实现了通过文件保存、读取TBuf和TInt变量的功能,其中涉及到UNICODE和ANSI之间字符的转换。

       最近研究了一下在Symbian操作系统上的文件操作,做一下整理,以做回顾交流。
       实现的功能如下:将一个class里面的成员变量TBuf16<KMaxServerNameLen>  m_iSevrName 和 TInt  m_iPort,通过一个文件Server.txt保存和读取操作。因为Symbian中的TBuf16必须读取unicode字符,故有两种方法实现,一是将文件保存为UNICODE文件然后读取,另外一种就是读取
ANSI文件到buffer,由程序实现将buffer转为UNICODE字符。
1.
写文件保存变量
       TBuf(TBufC)是Symbian系统中表示字符的一种方式,缓冲描述符,包含数据本身和数据的长度,注意此长度是unicode字符的长度,即是以short为单位的。可以通过TBuf的Ptr()成员函数得到该变量字符的地址指针,然后再逐一操作。
FILE* fp=fopen("c://Server.txt","w");
if(fp)
{
     char chBufServ[20];   
     char chBufPort[8];             
     m_iSevrName.Trim();
     int i = 0;
     for(i=0; i<m_iSevrName.Length(); i++)
         chBufServ[i] = *(m_iSevrName.Ptr()+i);
     chBufServ[i] = '/r';
     chBufServ[i+1] = '/n';
     sprintf(chBufPort,"%d/r/n",m_iPort);
     fwrite(chBufServ,strlen(chBufServ),1,fp);
     fwrite(chBufPort,strlen(chBufPort),1,fp);
     fclose(fp);
}
2.从文件读取字符并给变量赋值
      文件的保存很简单,主要是在文件读取赋值时把我搞的昏头转向^_^。
      先说一下怎么区分unicode文件和ANSI文件:所有Unicode编码的文本文件,其文件头2个字节一定是"0xff","0xfe",只要先读出这两个字节,就可以判断是不是Unicode编码的文件了
char cFirst[2];
fread(iFileHandle, cFirst, 2);  

if( psFirst[0] == '/xff' && psFirst[1] == '/xfe' )用这条语句就可以判断了。
首先以第一种方式实现,直接读取UNICODE文件赋值:
1).
FILE* fp=fopen("c://Server.txt","rb");    //Server.txt是UNICODE格式文件
if(fp)  {
     fseek(fp,0,2);//2即SEEK_SET表示Beginning of file
     int nLen=ftell(fp);                                                                                                                                    
if(nLen<1)
{
     fclose(fp);
     return;
}
fseek(fp,2,0); //注意此处跳过2字节,即表示UNICODE文件的符号"0xff","0xfe"
nLen-=2;
wchar_t *wstr=new wchar_t[nLen+1]; 
fread(wstr, nLen, 1, fp);
wstr[nLen]=0;              //加入结束符
fclose(fp);
short * psip=(short*)wstr;
short* token = GetLine(psip);
int i = 0;
while( token != NULL )
{
switch(i)
    {
    case 0:

    {
                m_iSevrName.Append((TUint16*)token,wcslen((wchar_t*)token));
    }
    break;
    case 1:
    {
         int nLen = wcslen((wchar_t*)token);
         char pTmpBuf[5];
         int i = 0;
         for(i=0; i<wcslen((wchar_t*)token); i++)
             pTmpBuf[i] = *(token+i);                
         pTmpBuf[i] = 0;                   //加入结束符
         m_iPort = atoi(pTmpBuf);
    }
    break;      
    }
    /* Get next token: */
    token = GetLine(psip);
    i++;
}
}
注意case 0的情况,如果token是short* 类型,则m_iSevrName调用Append后,其length()返回的是UNICODE的字符个数,而如果是wchar_t*类型的wstr ,则iSevrName的length()函数返回的是ANSi字符的个数,必须调用用SetLength()设置,即:m_iSevrName.Append((TUint16*) wstr,wcslen(wstr));
m_iSevrName.SetLength(m_iSevrName.Length()/2);
(在这个问题上浪费了我不少时间)。
其中上面读取一行字符的函数GetLine实现如下:
short* GetLine(LPSHORT& pBuf)
{
short* pRet=pBuf;
while(*pBuf && *pBuf!='/r' && *pBuf!='/n') pBuf++;
    *pBuf=0;
     pBuf++;
while(*pBuf &&(*pBuf=='/r' || *pBuf=='/n')) pBuf++;
    if(pRet==pBuf||*pRet==0)
     return NULL;
     return pRet;
}
2)以上是直接读取UNICODE文件实现,下面说一下第二种方法,即读取ANSI文件到缓存,然后转换为UNICODE字符。Windows系统中比较简单,调用其API函数WideCharToMultiByte、MultiByteToWideChar可以在两种字符间互相转换,而在Symbian系统中就没有那么简单了:
FILE* fp=fopen("c://Server.txt","rb");
if(fp)  {
fseek(fp,0,2);
     int nLen=ftell(fp);                                                                                                                                   
if(nLen<1)
     {
     fclose(fp);
     return;
     }
unsigned char* pBuf1=new unsigned char[nLen+1];
fseek(fp,0,0);
fread(pBuf1,nLen,1,fp);
pBuf1[nLen]=0;                           //结束符
fclose(fp);
fp=NULL;
//convert to unicode
TPtrC8 aForeign;
aForeign.Set(pBuf1,nLen);
CCnvCharacterSetConverter* pcc= CCnvCharacterSetConverter::NewLC();
if (pcc->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk, iEikonEnv->FsSession()) != CCnvCharacterSetConverter::EAvailable)
     {
     CleanupStack::PopAndDestroy();
     delete pBuf1;
     return;
     }
HBufC* iInfoText = HBufC::NewL(aForeign.Length());
TPtr16 ptr = iInfoText->Des();
     TInt aState=CCnvCharacterSetConverter::KStateDefault;
pcc->ConvertToUnicode(ptr, aForeign, aState);
CleanupStack::PopAndDestroy();
nLen*=2;
short* pBuf=(short*)ptr.Ptr();
     short * psip=pBuf;
short* token = GetLine(psip);
     int i = 0;
while( token != NULL )
{ ......                    //下面实现同第一种方法


      注意此转换方法在Symbian的模拟器上不能运行和调试,只能在real device上运行,不能调试对我们程序员来说比较难受,如果你选择了这种方法,那么就祈祷上帝让它能够正确运行吧^_^。

TBuf<MaxLen> m_iSevrName;

void SetDefaultChnl(const TDesC& aServName, TInt nRoom)
{

  //   m_iServName = aServName;                                        //这种写法是错误的
       m_iSevrName.Delete(0,m_iSevrName.Length());    //必须先清除原来的内容
       m_iSevrName.Append(aServName);
       m_iRoom = nRoom;
}

利用TDesC为TBuf变量赋值时,必须首先调用TBuf的Delete()函数清空内容,否则如果用第一种方法,该TBuf变量不会正确赋值,尽管调试时跟踪TBuf变量的Length和iBuf指针内容都显示是正确的。

1. 简介

  当我刚开始学习Symbian时,我遇到的第一件事情就是Symbian OS字符串的处理和使用问题。要学习Symbian字符串的使用,必须费一定脑筋才行。但是一旦你掌握了其中的要领,它就变得容易多了。

  因此,下面我将解释我是怎样学习基本的Symbian OS字符串处理并对之加以记忆的。

  注意,理解本文的前提是对Symbian操作系统的工作机理有一定了解。

  2. 背景

  你要做的第一件事情是记住字符串描述符层次结构图。这是很重要的,因为以后所有你要使用的五个描述符都派生于某些类,你必须了解它们分别是从哪些类派生的,以便确定应该使用哪些特别描述符及其使用场所。本文中我不准备解释什么是缓冲描述符及堆描述符的含义,以及可修改的描述符和不可修改的描述符是什么含义。但是,我相信你必须对上面的术语有足够的了解才行。Symbian描述符层次结构看起来相当绝妙。你可以参考下图,该图来源于newlc。

  3. TPtrC<n>用法

  其字面含义是"一个指向不可被操作的数据的指针"。关于TPtrC<n>,首先要记住,它不包含对自己的一些操作函数,而只含有构造器和设置方法。另外,既然它派生于TDesC,它就包含了TDesC的所有功能。

  指针指向数据的方式有下面两种:

  ·先创建一个空的TPtrC<N>,然后用Set(...)函数把它指向一些数据。

  ·通过使用任何一个重载的构造函数,在构造过程中传递数据。

  让我们通过下面几个例子来看一下上面的描述:

  实例1:-从TBuf和TbufC中取得TPtrC:

LIT(KText , "Test Code");
TBufC<10> Buf ( KText ); OR(/) TBuf<10> Buf ( KText );
// 使用构造器创建TPtr
TPtrC Ptr (Buf);
//使用成员函数创建TPtr
TPtrC Ptr1;
Ptr1.Set(Buf);

  实例2:-从TText*中取得TPtrC:

  下面的实例使用了TText16:

TText * text = _S("Hello World/n");
TPtrC ptr(text);
// 或
TPtrC Ptr1;
Ptr1.Set(text);
//要只存储Ttext的一部分,我们可以使用下面的语句
//这个描述符指针将只存储Hello
TPtrC ptr4(text,5);

  实例3:-从另外一个TPtrC取得TPtrC:

  你可以容易地把一个TPtrC赋值给另一个TPtrC。

TText * text = _S("Hello World/n");
TPtrC ptr(text);
//从另外一个TPtrC取得TPtrC
TPtrC p1(ptr);
//或
TPtrC p2;
p2.Set(ptr);

  实例4:-从TPtrC中取得TText *:

  我们可以通过Ptr()成员使用来从TPtrC中取得TText *。

//设置TPtrC
_LIT(KText,"Test Code");
TBufC<10> Buf ( KText );
TPtrC Ptr1 (Buf);
//取得TText*
TText* Text1 = (TText *)Ptr1.Ptr();

4. TBufC<n>的用法

  上面关于TPtrC的使用举例,有助于理解TBufC<n>的用法,不过下面有几个例子是关于如何创建TBufC<n>。

  实例5:-实例化TBufC<N>:

//用文字实例化
_LIT(Ktext, "TestText");
TBufC<10> Buf (Ktext);
//或
TBufC<10> Buf2;
Buf2 = Ktext;
//用现有的TBufC来创建一个新的TBufC
TBufC<10> Buf3(Buf2);

  TBufC<n>一般用于文本数据。对于二进制数据,应显示地使用TBufC8<n>。尽管TBufC<n>意味着数据不能被修改(’C’代表Constant:不变的),但是还有两种方法可以改变数据:

  ·数据可以使用赋值运算符进行替换。

  ·通过使用Des()函数来为缓冲区数据构建一个TPtr可修改的指针描述符。

  让我们看改变TBufC<N>的上下文的第一步。

  实例6:-改变TBufC<N>的上下文:

//测试用的一些文字
_LIT(Ktext , "Test Text");
_LIT(Ktext1 , "Test1Text");
//生成TPtrC
TBufC<10> Buf1 ( Ktext );
TBufC<10> Buf2 ( Ktext1 );
//改变Buf2的上下文
Buf2 = Buf1;
//创建一个空的TbufC并把它赋给Buf1
TBufC<10> Buf3;
Buf3 = Buf1;

  另一种改变TBufC<n>的上下文内容的方式是使用Des()成员函数。这个成员函数使用TPtr成员返回一个TPtr可修改的指针描述符。TPtr的最大长度是TBufC<n>模板参数的值。所有的操作函数都来源于基类TdesC。

  实例7:-使用Des()来改变TBufC<N>的上下文:

_LIT(Ktext , "Test Text");
_LIT(KXtraText , "New:");
TBufC<10> Buf1 ( Ktext );
TPtr Pointer = Buf1.Des();
// 删除最后4个字符
Pointer.Delete(Pointer.Length()-4, 4 );
//现在作相应的长度改变
TInt Len = Pointer.Length();
// 添加一个新串
Pointer.Append(KXtraText);
Len = Pointer.Length();
//要完全改变上面的缓冲区,我们可以使用下面的语句:
_LIT(NewText , "New1");
_LIT(NewText1 , "New2");
TBufC<10> Buf2(NewText);
//改变上下文
Pointer.Copy(Buf2);
//或者直接进行字面复制
Pointer.Copy(NewText1);
//所有上面所做的变化实际上改变了Buf1的上下文

  5. 使用堆描述符HBufC

  当我们不知道描述符中数据的大小时,HBufC是可选用的描述符。这里的’C’代表不变的(constant),这意味着数据是不可改变的,但是它在两种情况下也可以改变,就象对于TBufC<n>的情况所做的改变一样。第一种情况是使用赋值运算符,第二种情况是使用可修改的指针描述符,如使用成员函数时的TPtr。在使用HbufC时,要记住两种情况:

  ·如果你需要把HbufC传递给一个用TDesC&作为参数的函数,你只须简单地取消对HBufC指针的参照即可。

  ·可以通过使用ReAlloc函数来改变堆描述符缓冲区的大小,就象对于TBufC<N>的情况一样.

  实例8:-HbufC的用法:

//创建一个堆描述符,有两种方法
//第一种方法使用New(),NewL()或NewLC()之一
//让我们看一个例子.这里将构建一个HbufC:所用数据空间为15,但是当前大小是0
HBufC * Buf = HBufC::NewL(15);
// 第二种方法使用
// 现有描述符的Alloc(), AllocL(), 或AllocLC()方法。这个新的堆描述符用描述符的内容自动初始化
_LIT (KText , "Test Text");
TBufC<10> CBuf = KText;
HBufC * Buf1 = CBuf.AllocL();
// 我们检查一下大小和长度。这里大小是18,而长度是9
TInt BufSize = Buf->Size();
TInt BufLength = Buf->Length();
// 改变HbufC的指向
_LIT ( KText1 , "Text1");
//使用赋值运算符来改变指向KText1的缓冲区
*Buf1 = KText1;
// 下面通过可修改的指针描述符来改变 数据
TPtr Pointer = Buf1->Des();
Pointer.Delete( Pointer.Length() - 2, 2 );
// 所有能对 TBufC<n> 进行的操作在些都可用
//下面是一个这样的操作
_LIT ( KNew, "New:");
Pointer.Append( KNew );

  6. TPtr的用法

  我们使用它来取代TBufC<N>和HBufC,因为我最了解它。因此,让我们先记住如何创建TPtr。

  ·用另一个TPtr。

  ·从TBufC<N>,或者通过成员函数Des()使用HbufC来创建。

  ·从一个指向内存的外部指针并指定最大长度。

  ·从一个指向内存的外部指针并指定数据及其最大长度。

  实例9:-TPtr的用法:

//先让我们看一下两种取得TPtr的方法
_LIT(KText, "Test Data");
TBufC<10> NBuf ( KText );
TPtr Pointer = NBuf.Des();
//第一种方法
TPtr Pointer2 ( Pointer );
//第二种方法使用一个内存区段,用于存储数据和最大长度
TText * Text = _S("Test Second");
TPtr Pointer3 ( Text ,11, 12);
// 现在我们看一下,怎么用TPtr 替换数据,这完全可以通过
//赋值运算符或拷贝函数来实现
_LIT(K1, "Text1");
_LIT(K2, "Text2");
Pointer2 = K1; // 数据是Text1
Pointer.Copy(K2); // 数据是Text2;
// 我们还可以改变数据的长度或把它设置为0
Pointer2.SetLength(2); // 只剩下 Te两个字符
Pointer2.Zero(); // 把长度设置为0
//可以使用delete 函数来更改数据,如前面的例中所示

  7. TBuf<n>的用法

  在这个数据结构中,其中的数据并不是固定不变的。运算、实例化和赋值都与TBufC<n>一致;对于它的修改操作,与TPtr一致,象复制、删除、赋值等等。我想这一部分就不用再给出例子了。
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:827806次
    • 积分:9625
    • 等级:
    • 排名:第1914名
    • 原创:120篇
    • 转载:35篇
    • 译文:3篇
    • 评论:1121条
    新浪微博
    最新评论