首先,我们要明白的是,VC是通过ODBC来访问Excel表格的,也就是说,VC将Excel表格,当作数据库来处理。当然了,也可以通过读以tab键隔开的文件来处理这样的文件,但是,我还是更加愿意用读取数据库的方式来访问Excel表格。
第二,既然是数据库,那么,就需要建立一个与该库对应的dsn,这个,而且,在建立dsn之前,首先要确定,已经安装了Excel的驱动。
第三,要访问数据库中的表格,就要先打开该表格,如此,就需要一个与之对应的RecordSet。如此,有如下代码:
void CRWExcel::ReadFromExcel()
{
      CDatabase database;
      CString sSql;
      CString sItem1, sItem2;
      CString sDriver;
      CString sDsn;
      CString sFile = "Demo.xls";// 将被读取的Excel文件名
                                     
    // 检索是否安装有Excel驱动 "Microsoft Excel Driver (*.xls)"
      sDriver = GetExcelDriver();
      if (sDriver.IsEmpty())
      {
          // 没有发现Excel驱动
          AfxMessageBox("没有安装Excel驱动!");
          return;
      }
      // 创建进行存取的字符串
      sDsn.Format("ODBC;DRIVER={%s};DSN='''';DBQ=%s", sDriver, sFile);

      TRY
      {
// 打开数据库,建立与这个Excel对应的Database
          database.Open(NULL, false, false, sDsn);
          CRecordset recset(&database);
// 设置读取的查询语句.demo.xls并非文件名,需要在excel中进行//设置,具体文章最后有讲
          sSql = "SELECT Age, Name FROM DEMO.XLS";
      // 执行查询语句,打开表格
          recset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
          // 获取查询结果
          while (!recset.IsEOF())
          {
              //读取Excel内部数值
              recset.GetFieldValue("Name ", sItem1);
              recset.GetFieldValue("Age", sItem2);
              // 移到下一行
              recset.MoveNext();
          }
          // 关闭数据库
          database.Close();
      }
      CATCH(CDBException, e)
      {
          // 数据库操作产生异常时...
          AfxMessageBox("数据库错误: " + e->m_strError);
      }
      END_CATCH;
}
需要注意的是,我们对我们的Excel表格需要进行一些处理,需要先选定我们要读取的数据,之后,选择插入>>名字>>之后,在输入框中输入我们在select语句中用到的表名。第二,需要设置列名,为我们选定部分的最前面的一行的数据。

posted @ 2010-10-11 11:15 wrh 阅读(8381) | 评论 (1)编辑 收藏

最近一个项目需要把报表的表格导入excel,在网上找了一些方法,比较研究了一下,记在这里,备忘。

表格例子如下:

<table id="tableExcel" width="100%" border="1" cellspacing="0" cellpadding="0">
<tr>
<td colspan="5" align="center">html 表格导出道Excel</td>
</tr>
<tr>
<td>列标题1</td>
<td>列标题2</td>
<td>类标题3</td>
<td>列标题4</td>
<td>列标题5</td>
</tr>
<tr>
<td>aaa</td>
<td>bbb</td>
<td>ccc</td>
<td>ddd</td>
<td>eee</td>
</tr>
<tr>
<td>AAA</td>
<td>BBB</td>
<td>CCC</td>
<td>DDD</td>
<td>EEE</td>
</tr>
<tr>
<td>FFF</td>
<td>GGG</td>
<td>HHH</td>
<td>III</td>
<td>JJJ</td>
</tr>
</table>

 

1、js的方法

A、将整个表格拷贝到EXCEL中

function method1(tableid) {
var curTbl = document.getElementById(tableid);
var oXL = new ActiveXObject("Excel.Application");
var oWB = oXL.Workbooks.Add();
var oSheet = oWB.ActiveSheet;
var sel = document.body.createTextRange();
sel.moveToElementText(curTbl);
sel.select();
sel.execCommand("Copy");
oSheet.Paste();
oXL.Visible = true;
}

 B、读取表格中每个单元到EXCEL中:

function method2(tableid)
{
var curTbl = document.getElementById(tableid);
var oXL = new ActiveXObject("Excel.Application");
var oWB = oXL.Workbooks.Add();
var oSheet = oWB.ActiveSheet;
var Lenr = curTbl.rows.length;
for (i = 0; i < Lenr; i++)
{
        var Lenc = curTbl.rows(i).cells.length;
for (j = 0; j < Lenc; j++)
{
oSheet.Cells(i + 1, j + 1).value = curTbl.rows(i).cells(j).innerText;
}
}
oXL.Visible = true;
}

 c、把表格输出到另一个页面,然后存成cvs格式

 

function getXlsFromTbl(inTblId, inWindow)
{
try {
var allStr = "";
var curStr = "";
if (inTblId != null && inTblId != "" && inTblId != "null") {
curStr = getTblData(inTblId, inWindow);
}
if (curStr != null) {
allStr += curStr;
}
else {
alert("你要导出的表不存在");
return;
}
var fileName = getExcelFileName();
doFileExport(fileName, allStr);
}
catch(e) {
alert("导出发生异常:" + e.name + "->" + e.description + "!");
}
}
function getTblData(inTbl, inWindow) {
var rows = 0;
var tblDocument = document;
if (!!inWindow && inWindow != "") {
if (!document.all(inWindow)) {
return null;
}
else {
tblDocument = eval(inWindow).document;
}
}
var curTbl = tblDocument.getElementById(inTbl);
var outStr = "";
if (curTbl != null) {
for (var j = 0; j < curTbl.rows.length; j++) {
for (var i = 0; i < curTbl.rows[j].cells.length; i++) {
if (i == 0 && rows > 0) {
outStr += " \t";
rows -= 1;
}
outStr += curTbl.rows[j].cells[i].innerText + "\t";
if (curTbl.rows[j].cells[i].colSpan > 1) {
for (var k = 0; k < curTbl.rows[j].cells[i].colSpan - 1; k++) {
outStr += " \t";
}
}
if (i == 0) {
if (rows == 0 && curTbl.rows[j].cells[i].rowSpan > 1) {
rows = curTbl.rows[j].cells[i].rowSpan - 1;
}
}
}
outStr += "\r\n";
}
}
else {
outStr = null;
alert(inTbl + "不存在 !");
}
return outStr;
}
function getExcelFileName() {
var d = new Date();
var curYear = d.getYear();
var curMonth = "" + (d.getMonth() + 1);
var curDate = "" + d.getDate();
var curHour = "" + d.getHours();
var curMinute = "" + d.getMinutes();
var curSecond = "" + d.getSeconds();
if (curMonth.length == 1) {
curMonth = "0" + curMonth;
}
if (curDate.length == 1) {
curDate = "0" + curDate;
}
if (curHour.length == 1) {
curHour = "0" + curHour;
}
if (curMinute.length == 1) {
curMinute = "0" + curMinute;
}
if (curSecond.length == 1) {
curSecond = "0" + curSecond;
}
var fileName = "table" + "_" + curYear + curMonth + curDate + "_"
+ curHour + curMinute + curSecond + ".csv";
return fileName;
}
function doFileExport(inName, inStr) {
var xlsWin = null;
if (!!document.all("glbHideFrm")) {
xlsWin = glbHideFrm;
}
else {
var width = 6;
var height = 4;
var openPara = "left=" + (window.screen.width / 2 - width / 2)
+ ",top=" + (window.screen.height / 2 - height / 2)
+ ",scrollbars=no,width=" + width + ",height=" + height;
xlsWin = window.open("", "_blank", openPara);
}
xlsWin.document.write(inStr);
xlsWin.document.close();
xlsWin.document.execCommand('Saveas', true, inName);
xlsWin.close();
}

 总结:比较上面3种方法,感觉第一种方法比较完美一些,因为这种方法比较完整的输出表格的格式。但,第一和第二种方法都用了ActiveX 对象,对客户端的安全有要求,而且最大的问题还有一个,就是excel 对象无法关闭。第3中方法虽然没有用ActiveX 对象,但是用了弹出窗口输出, 如果禁止了弹出窗口则无法使用。

对于execl 对象无法关闭的问题,下面的方法是一个权宜方法:

function Cleanup() {
window.clearInterval(idTmr);
CollectGarbage();
}

 调用方法:

idTmr = window.setInterval("Cleanup();",1);
2、Asp.net(c#)中的方法
这种方法其实类似上面的js的第3中方法(也可以在其他的web脚本来实现,比如asp中vbscript,或者php),把表格用文件流的方式
输出为excel。实例代码如下:
public void OutPutExcel(string title)
{
Response.Clear();
Response.Buffer = true;
Response.Charset = "utf-8";
Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(title + ".xls"));
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
Response.ContentType = "application/ms-excel";
Page.EnableViewState = false;
System.IO.StringWriter oStringWriter = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter oHtmlTextWriter = new System.Web.UI.HtmlTextWriter(oStringWriter);
this.Page.RenderControl(oHtmlTextWriter);
string temp = oStringWriter.ToString();
Response.Write(temp);
Response.End();
}
这种方法的从本质上说并非标准的excel格式,不过把html格式的文件另存为excel的格式,然后用excel打开罢了。
3、利用ExceL Application或者MSOWC 或者ado.net
这种方法都是利用服务器的组件来时实现,要求服务端要安装excel,具体的代码可以看下面的链接:
http://www.cnblogs.com/pucumt/archive/2006/09/13/503120.html
http://support.microsoft.com/default.aspx?scid=kb;zh-cn;306023#top
我不提倡用这种方法,因为需要占用服务器的资源。
posted @ 2010-10-11 11:02 wrh 阅读(2062) | 评论 (-1)编辑 收藏
简单明了比《Javascript之文件操作 (IE)》实用!


<script>
/*
object.OpenTextFile(filename[, iomode[, create[, format]]])
参数
object
必选项。object 应为 FileSystemObject 的名称。
filename
必选项。指明要打开文件的字符串表达式。
iomode
可选项。可以是三个常数之一:ForReading 、 ForWriting 或 ForAppending 。
create
可选项。Boolean 值,指明当指定的 filename 不存在时是否创建新文件。如果创建新文件则值为 True ,如果不创建则为 False 。如果忽略,则不创建新文件。
format
可选项。使用三态值中的一个来指明打开文件的格式。如果忽略,那么文件将以 ASCII 格式打开。
设置
iomode 参数可以是下列设置中的任一种:
常数 值         描述
ForReading 1 以只读方式打开文件。不能写这个文件。
ForWriting 2 以写方式打开文件
ForAppending 8 打开文件并从文件末尾开始写。

format 参数可以是下列设置中的任一种:
值              描述
TristateTrue 以 Unicode 格式打开文件。
TristateFalse 以 ASCII 格式打开文件。
TristateUseDefault 使用系统默认值打开文件。
*/

//读文件
function readFile(filename){
var fso = new ActiveXObject("Scripting.FileSystemObject");
var f = fso.OpenTextFile(filename,1);
var s = "";
while (!f.AtEndOfStream)
s += f.ReadLine()+"\n";
f.Close();
return s;
}

//写文件
function writeFile(filename,filecontent){
    var fso, f, s ;
    fso = new ActiveXObject("Scripting.FileSystemObject");   
    f = fso.OpenTextFile(filename,8,true);
    f.WriteLine(filecontent);  
    f.Close();
alert('ok');
}

</script>
<html>
<input type="text" id="in" name="in" />
<input type="button" value="Write!" onclick="writeFile('c:/12.txt',document.getElementById('in').value);"/><br><br>
<input type="button" value="Read!" onclick="document.getElementById('show').value=readFile('c:/12.txt');"/><br>
<textarea id="show" name="show" cols="50" rows="8" >
</textarea>
</html>
posted @ 2010-10-09 14:25 wrh 阅读(713) | 评论 (0)编辑 收藏
概述

在程序中经常要用到设置或者其他少量数据的存盘,以便程序在下一次执行的时候可以使用,比如说保存本次程序执行时窗口的位置、大小、一些用户设置的数据等等,在 Dos 下编程的时候,我们一般自己产生一个文件,由自己把这些数据写到文件中,然后在下一次执行的时候再读出来使用。在 Win32 编程中当然你也可以这样干,但 Windows 已经为我们提供了两种方便的办法,那就是使用注册表或者 ini 文件(Profile)来保存少量数据。本文中先介绍一下 .ini 文件的使用。

ini 文件是文本文件,中间的数据格式一般为:
[Section1 Name]
KeyName1=value1
KeyName2=value2
...

[Section2 Name]
KeyName1=value1
KeyName2=value2

ini 文件可以分为几个 Section,每个 Section 的名称用 [] 括起来,在一个 Section 中,可以有很多的 Key,每一个 Key 可以有一个值并占用一行,格式是 Key=value,Win32 对 ini 文件操作的 api 中,有一部分是对 win.ini 操作的,有一部分是对用户自定义的 ini 文件操作的。Win.in 和 system.ini 是Windows的两个非常重要的初始化文件,Windows将用户所作的选择以及各种变化的系统信息记录在这两个文件中。System.ini 描述了系统硬件的当前状态,Win.ini 文件则包含了Windows 系统运行环境的当前配置。由于 Win.ini 文件的重要性和常用性,Win32 中有专门对 Win.ini 进行操作的 api,它们是:

GetProfileInt - 从 Win.ini 文件的某个 Section 取得一个 key 的整数值,它的原形是:

GetProfileInt(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
INT nDefault // 如果 Key 值没有找到,则返回缺省的值是多少
);

如果 Key 值没有找到的话,返回值是 nDefault 指定的缺省值,如果 Key 中的值是负数,则返回 0,如果 Key 指定的是数字和字符串的混合,则返回数字部分的值,比如说 x=1234abcd,则返回 1234


GetProfileString - 从 Win.ini 文件的某个 Section 取得一个 key 的字符串,它的原形是:

GetProfileString(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
LPCTSTR lpDefault, // 如果 Key 值没有找到,则返回缺省的字符串的地址
LPTSTR lpReturnedString, // 返回字符串的缓冲区地址
DWORD nSize // 缓冲区的长度
);

返回的字符串在缓冲区内,返回的 eax 值是返回的字符串的长度(不包括尾部的0)


GetProfileSection - 从 Win.ini 文件中读出整个 Section 的内容,它的原形是:

GetProfileSection(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPTSTR lpReturnedString, // 返回数据的缓冲区地址
DWORD nSize // 返回数据的缓冲区长度
);


WriteProfileSection - 将一个整个 Section 的值 写入 Win.ini 文件的指定 Section 中,它的原形是:

WriteProfileSection(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpString // 要写入的数据的地址
);

如果 Win.ini 没有指定的 Section,API 会新建立一个并写入数据,如果已经存在,则先删除原来 Seciton 中所有的 Key 值然后写入新的。


WriteProfileString - 将一个 Key 值写入 Win.ini 文件的指定 Section 中,它的原形是:

WriteProfileString(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
LPCTSTR lpString // 要写的字符串地址
);

如果 Win.ini 没有指定的 Section,API 会新建 Section,如果没有指定的 Key 则新建一个 Key 并写入数据,如果已经存在,则用字符串代替原来的值。
以上的 Api 是对 Win.ini 操作的,当然对于我们来说,用的更多的是在程序运行的目录中建立自己的 ini 文件,如果需要对自己的 ini 文件操作,就要用到另一组 Api,这一组 api 和上面的很象,只要把上面一组的 Profile 换成 PrivateProfile(私有的)就可以了,参数中也相应的多了一个 ini 文件名的参数。例如 GetPrivateProfileInt、GetPrivateProfileSection、WritePrivateProfileString 等等, 下面分别介绍:

GetPrivateProfileInt - 从 ini 文件的某个 Section 取得一个 key 的整数值,它的原形是:

GetPrivateProfileInt(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
INT nDefault // 如果 Key 值没有找到,则返回缺省的值是多少
LPCTSTR lpFileName // ini 文件的文件名
);

中间参数和返回值的定义和 GetProfileInt 是一样的。


GetPrivateProfileString - 从 ini 文件的某个 Section 取得一个 key 的字符串,它的原形是:

GetPrivateProfileString(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
LPCTSTR lpDefault, // 如果 Key 值没有找到,则返回缺省的字符串的地址
LPTSTR lpReturnedString, // 返回字符串的缓冲区地址
DWORD nSize // 缓冲区的长度
LPCTSTR lpFileName // ini 文件的文件名
);


GetPrivateProfileSection - 从 ini 文件中读出整个 Section 的内容,它的原形是:

GetPrivateProfileSection(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPTSTR lpReturnedString, // 返回数据的缓冲区地址
DWORD nSize // 返回数据的缓冲区长度
LPCTSTR lpFileName // ini 文件的文件名
);

这个 api 可以读出整个 section 的内容,当你不知道 section 中有哪些 key 的时候,可以使用这个 api 将整个 section 读出后再处理。


GetPrivateProfileSectionNames - 从 ini 文件中获得 Section 的名称,它的原形是:

GetPrivateProfileSectionNames(
LPTSTR lpszReturnBuffer, // 返回数据的缓冲区地址
DWORD nSize // 返回数据的缓冲区长度
LPCTSTR lpFileName // ini 文件的文件名
);

如果 ini 中有两个 Section: [sec1] 和 [sec2],则返回的是 'sec1',0,'sec2',0,0 ,当你不知道 ini 中有哪些 section 的时候可以用这个 api 来获取名称


WritePrivateProfileSection - 将一个整个 Section 的内容入 ini 文件的指定 Section 中,它的原形是:

WritePrivateProfileSection(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpString // 要写入的数据的地址
LPCTSTR lpFileName // ini 文件的文件名
);


WritePrivateProfileString - 将一个 Key 值写入 ini 文件的指定 Section 中,它的原形是:

WritePrivateProfileString(
LPCTSTR lpAppName, // 指向包含 Section 名称的字符串地址
LPCTSTR lpKeyName, // 指向包含 Key 名称的字符串地址
LPCTSTR lpString // 要写的字符串地址
LPCTSTR lpFileName // ini 文件的文件名
);

如果 ini 中没有指定的 Section,API 会新建 Section,如果没有指定的 Key 则新建一个 Key 并写入数据,如果已经存在,则用字符串代替原来的值。当指定的 ini 也不存在的时候,API 会自动建立一个新的文件,所以使用 ini 的好处是我们不必为了保存少量的数据涉及到文件操作,就连查找文件是否存在的操作都不必要。

使用要点:

在我们实际使用的时候,用的最多的是 GetPrivateProfileString 和 WritePrivateProfileString,但在对自定义 ini 文件操作的时候要注意的是,如果 lpFileName 指定的文件没有路径的话,Api 会去 Windows 的安装目录去找而不会在当前目录找,但是每次用到 ini 函数要获取当前路径显然太麻烦了,这里有一个变通的办法,你只要在 ini 文件名前面加上 .\ 就可以了,比如说要对本目录下的 user.ini 操作,那么文件名就是 '.\user.ini' 这样显然比较方便。另外,当你要把一个 Key 清除的时候,可以使用把 lpString 指向一个空的字符串然后使用 WritePrivateProfileString。当你要把一个 section 的全部内容清空的时候,也不必把 key 一个个的清除,可以使用把 lpString 指向一个空的字符串然后使用 WritePrivateProfileSection。
posted @ 2010-09-03 09:27 wrh 阅读(353) | 评论 (0)编辑 收藏

得到运行程序所在路径:(其实得到的是当前执行程序存放路径)。

       TCHAR szFilePath[MAX_PATH + 1];

       GetModuleFileName(NULL, szFilePath, MAX_PATH);      

       (_tcsrchr(szFilePath, _T('\\')))[1] = 0;

       CString strtemp=szFilePath;

 

 

 

 

函数说明:

GetModuleFileName:The GetModuleFileName function retrieves the full path and filename for the executable file containing the specified module.

得到程序当前工作路径:(因为程序在运行过程中,会改变工作路径)

       char pBuf[MAX_PATH];                                 //存放路径的变量      

       GetCurrentDirectory(MAX_PATH,pBuf);                   //获取程序的当前目录

       strcat(pBuf,"\\");

       CString strtemp=pBuf;

 

 

函数说明:

GetCurrentDirectoryThe GetCurrentDirectory function retrieves the current directory for the current process

posted @ 2010-08-21 13:43 wrh 阅读(1763) | 评论 (0)编辑 收藏
VC 移动,复制,删除文件(SHFileOperation)

总结一下SHFileOperation的用法,希望对大家有用

//删除文件或者文件夹
bool DeleteFile(char * lpszPath)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_ALLOWUNDO |   //允许放回回收站
      FOF_NOCONFIRMATION; //不出现确认对话框
FileOp.pFrom = lpszPath;
FileOp.pTo = NULL;      //一定要是NULL
FileOp.wFunc = FO_DELETE;    //删除操作
return SHFileOperation(&FileOp) == 0;
}

//复制文件或文件夹
bool CopyFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION|   //不出现确认对话框
      FOF_NOCONFIRMMKDIR ; //需要时直接创建一个文件夹,不需用户确定
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_COPY;
return SHFileOperation(&FileOp) == 0;
}

//移动文件或文件夹
bool MoveFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION|   //不出现确认对话框
      FOF_NOCONFIRMMKDIR ; //需要时直接创建一个文件夹,不需用户确定
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_MOVE;
return SHFileOperation(&FileOp) == 0;   
}


//从命名文件或文件夹
bool ReNameFile(char *pTo,char *pFrom)
{
SHFILEOPSTRUCT FileOp={0};
FileOp.fFlags = FOF_NOCONFIRMATION;   //不出现确认对话框
FileOp.pFrom = pFrom;
FileOp.pTo = pTo;
FileOp.wFunc = FO_RENAME;
return SHFileOperation(&FileOp) == 0;   
}

应用举例:
DeleteFile("d:\\PID\0\0");    //删除一个文件夹
DeleteFile("d:\\PID.dsp\0d:\\PID.dsw\0\0"); //删除多个文件
CopyFile("d:\0\0","D:\\MyProjects\\临时程序\0\0");    //把"临时程序"文件夹放到d盘下面
CopyFile("d:\0\0","D:\\MyProjects\\临时程序\\PID.dsp\0D:\\MyProjects\\临时程序\\PID.dsw\0"); //把PID.dsp和PID.dsw俩个文件放到d盘下面
ReNameFile("d:\\NewName","d:\\PID\0\0"); \\把PID文件夹从命名为NewName
注意:,如果你想把"D:\\MyProjects\\临时程序\0\0"的文件夹复制到D盘下,并从命名为NewName,应该这样
CopyFile("d:\\NewName\0\0","D:\\MyProjects\\临时程序\\*.*\0\0"); //把"临时程序"文件夹复制到d盘下并从命名为"NewName"  

 

下面这个类方便你复制多个文件或文件夹,仅作参考
//连接多个路径的类
class JOINFILEPATH
{
private:
int pos;
char* MultipleFilePath;
public:
JOINFILEPATH()
{
   pos=0;
   MultipleFilePath=new char[MAX_PATH*10];
   memset(MultipleFilePath,0,MAX_PATH*10);
}
~JOINFILEPATH() { delete []MultipleFilePath; }
void join(char *FilePath)
{
   while(*FilePath!='\0')
    MultipleFilePath[pos++]=*FilePath++;
   pos++;
}
char * GetMultipleFilePath() {return MultipleFilePath;}
};

//应用举例:
JOINFILEPATH FilePath;
FilePath.join("D:\\MyProjects\\临时程序\\PID\\PID.dsp");
FilePath.join("D:\\MyProjects\\临时程序\\PID\\PID.dsw");
CopyFile("d:\0\0",FilePath.GetMultipleFilePath());

1 pFrom和pTo最好以\0\0结尾(把存放路径的字符串初始化为0),不然有可能会出错,中间的每一个路径用\0隔开
2 pFrom所指向的文件或文件夹(可以多个)会被复制或移动到pTo所指向的文件夹下面(假如文件夹不存在会询问是否创建,当然你也可以选择直接创建)

参数详解:

Typedef struct _ShFILEOPSTRUCT
{
HWND hWnd; //消息发送的窗口句柄;
UINT wFunc; //操作类型
LPCSTR pFrom; //源文件及路径
LPCSTR pTo; //目标文件及路径
FILEOP_FLAGS fFlags; //操作与确认标志
BOOL fAnyOperationsAborted; //操作选择位
LPVOID hNameMappings; //文件映射
LPCSTR lpszProgressTitle; //文件操作进度窗口标题
}SHFILEOPSTRUCT, FAR * LPSHFILEOPSTRUCT;

  在这个结构中,hWnd是指向发送消息的窗口句柄,pFrom与pTo是进行文件操作的源文件名和目标文件名,它包含文件的路径,对应单个文件的路径字符串,或对于多个文件,必须以NULL作为字符串的结尾或文件路径名之间的间隔,否则在程序运行的时候会发生错误。另外,pFrom和pTo都支持通配符*和?,这大大方便了开发人员的使用。例如,源文件或目录有两个,则应是:char pFrom[]="d:\\Test1\0d:\\Text.txt\0",它表示对要D:盘Test目录下的所有文件和D:盘上的Text.txt文件进行操作。字符串中的"\\"是C语言中的'\'的转义符,'\0'则是NULL。wFunc 是结构中的一个非常重要的成员,它代表着函数将要进行的操作类型,它的取值为如下:

  FO_COPY: 拷贝文件pFrom到pTo 的指定位置。

  FO_RENAME: 将pFrom的文件名更名为pTo的文件名。

  FO_MOVE: 将pFrom的文件移动到pTo的地方。

  FO_DELETE: 删除pFrom指定的文件。

  使用该函数进行文件拷贝、移动或删除时,如果需要的时间很长,则程序会自动在进行的过程中出现一个无模式的对话框(Windows操作系统提供的文件操作对话框),用来显示执行的进度和执行的时间,以及正在拷贝、移动或删除的文件名,此时结构中的成员lpszProgressTitle显示此对话框的标题。fFlags是在进行文件操作时的过程和状态控制标识。它主要有如下一些标识,也可以是其组合:

  FOF_FILESONLY:执行通配符,只执行文件;

  FOF_ALLOWUNDO:保存UNDO信息,以便在回收站中恢复文件;

  FOF_NOCONFIRMATION:在出现目标文件已存在的时候,如果不设置此项,则它会出现确认是否覆盖的对话框,设置此项则自动确认,进行覆盖,不出现对话框。

  FOF_NOERRORUI:设置此项后,当文件处理过程中出现错误时,不出现错误提示,否则会进行错误提示。

  FOF_RENAMEONCOLLISION:当已存在文件名时,对其进行更换文提示。

  FOF_SILENT:不显示进度对话框。

  FOF_WANTMAPPINGHANDLE:要求SHFileOperation()函数返回正处于操作状态的实际文件列表,文件列表名柄保存在hNameMappings成员中。

  SHFILEOPSTRUCT结构还包含一个SHNAMEMAPPING结构的数组,此数组保存由SHELL计算的每个处于操作状态的文件的新旧路径。

  在使用该函数删除文件时必须设置SHFILEOPSTRUCT结构中的神秘FOF_ALLOWUNDO标志,这样才能将待删除的文件拷到Recycle Bin,从而使用户可以撤销删除操作。需要注意的是,如果pFrom设置为某个文件名,用FO_DELETE标志删除这个文件并不会将它移到Recycle Bin,甚至设置FOF_ALLOWUNDO标志也不行,在这里你必须使用全路径名,这样SHFileOperation才会将删除的文件移到Recycle Bin。

转自http://blog.csdn.net/jhb92/archive/2007/04/13/1563452.aspx

Shell的文件操作函数
SHFileOperation
功能:
1.复制一个或多个文件
2.删除一个或多个
3.重命名文件
4.移动一个或多个文件

有一样的Win32API功能函数是:
CopyFile(),DeleteFile(),MoveFile()
MoveFile可以对文件重命名!
Win32 API 的层次比SHFileOperation低

SHFileOperation
的重要参数
1.wFunc //对pFrom pTo要执行的操作
2.fFlags //影响对wFunx的操作
3.hNameMappings   //有系统填充,和你也可以填充
4.lpszProgressTitle

pFrom pTo 在结尾是两个'\0\0'
通常用一个'\0',这样会失败的!!
当FOF_MULTIDESTFILES
szPFrom[lstrlen(szPFrom)+1]=0

szPFrom:必须先确定他所指定的文件存在!
可以是单个文件名,*.*,或包含统配符的文件名
注意必须是文件名,不是文件所在的文件夹名
szSource:可以是一个目录,如果不是目录,但又有
多个文件,那么必须和szPFrom的每一个文件对应,还要指定
FOF_MULTIDETFILES标志


Source and Target
多个文件---> 一个文件夹
许多单独的文件---->一个文件夹
单独文件--->单独文件
许多单独的文件---->许多单独的文件

单独文件:知道名字的文件
多个文件:带有统配符的文件
注意到source中没有对文件夹的操作!!


!!!!
SHFileOperation能操作网络上的文件
如果你想将本地文件复制到192.168.1.99
那么只要在192.168.1.99上共享123目录
然后将pTo设置为\\192.168.1.99\123
就可以了
但不要设置为\\192.168.1.99


对hNameMappings操作是Undocumented!!
如果没有指定hNameMappings
那么hNameMappings一直是NULL
只有当某种操作(copy,move,rename)引起了文件名冲突了,hNameMappings才不是NULL!!!
当第一次copy某些文件到空目录中时hNameMappings一定是NULL
所以hNameMappings只是内存中的一块地区用来让Explorer.exe保存被重命名的文件,以避免文件名冲突!
上面知道了如何才能使hNameMappings有效
现在如何使用hNameMappings,及其所指的结构大小?并取得这个内存块的内容呢?
hNameMappings 是简单LPVOID无法使用loop
要使用hNameMappings,必须定义一个结构体
struct HANDLETOMAPPINGS {
    UINT              uNumberOfMappings; // number of mappings in array
    LPSHNAMEMAPPING   lpSHNameMapping;    // pointer to array of mappings
};
但是可以写一个Enumerate function to enumerate lpSHNameMapping指向的内存块,并且是让Window自己调用我的,不是我主动调用,象Loop

相关联接:
Q154123:File Name Mapping with Windows NT 4.0 Shell
Q133326:SHFILEOPSTRUCT pFrom and pTo Fields Incorrect
Q142066:PRB: SHGetNameMappingPtr() and SHGetNameMappingCount()
Manipulating Files with the SHFileOperation Function in Visual Basic 4.0

 

FOF_SILENT //不产生正在复制的对话框
FOF_NOCONFIRMMKDIR//如果目的目录不存在,就默认创建
FOF_NOCONFIRMATION //不出现确认文件替换对话框(Confirmation Dialog)(默认替换原来的文i件)
FOF_NOERRORUI//不出现错误对话框
最好不要同时使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
因为FOF_NOCONFIRMMKDIR屏蔽了missing directory Error
但FOF_NOERROR又屏蔽了missing directory Error,那么在同时使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR
时也阻止了新目录安静(没有用户确认要产生新目录的对话框)的产生!!
那么如何同时使用FOF_NOERRORUI,FOF_NOCONFIRMMKDIR?
就必须先确认pTo所指定的目录存在即可
BOOL MakeSureDiretoryPathExists(LPCSTR DirPath);

使用它要包含imagehlp.h和imagehlp.lib
如何判断同时存在FOF_NOERRORUI,FOF_NOCONFIRMMKDIR


FOF_RENAMEONCOLLISION//有重复文件时自动重命名


能产生对话框的标志:
FOF_SILENT             //progress dialog           
FOF_RENAMEONCOLLISION //replace dialog
FOF_NOCONFIRMATION     //confirmation dialog
FOF_NOCONFIRMMKDIR     //asks for your permission to create a new folder
FOF_NOERRORUI          //error message


FOF_ALLOWUNDO     //将文件放入回收站,否则直接删除,一般这个最好做默认

posted @ 2010-08-16 10:31 wrh 阅读(3041) | 评论 (0)编辑 收藏
C 标准提供一些函数用来检查输入输出函数调用中的错误。

13.6.1 ferror 函数

在调用各种输入输出函数(如 putc, getc , fread, fwrite 等)时,日过出现错误,除了函数返回值有所反映外,还可以用 ferror 函数检查。它的一般调用形式为   ferror(fp);   如果 ferror 函数返回值为0(假),表示未出错;如果返回一个非零值,表示出错。应该注意,对同一个文件每一次调用输入输出函数,均产生一个新的 ferror 函数值,因此,应当在调用一个输入输出函数后立即检查 ferror 函数的值,否则信息会丢失。

   在执行 fopen 函数时,ferror 函数的初始值自动置为0。


13.6.2   clearerr (清除错误) 函数

clearerr 函数的作用是使文件错误标志和文件结束标志置为0。假设在调用一个输入输出函数时出现错误, ferror 函数值为一个非零值。在调用 clearerr
(fp)后,ferror(fp)的值变成0。

只要出现错误标志,就一直保留,直到对同一文件调用 clearerr 函数或(重新)rewind 函数,或任何其它一个输入输出函数。


 

                              13.7 文件输入输出小结

   在本节中将以上介绍过的输入输出函数作一概括性的小结,以一目了然,便于查阅。下表列出常用的缓冲文件系统函数。

   分类             函数名                   功                                能

打开文件         fopen()                        打开文件

关闭文件         fclose()                        关闭文件

文                    fseek()                         改变文件位置指针的位置
   件                   rewind()                       使文件位置指针重新置于文件开头
定位                ftell()                            返回文件位置指针的当前值
                             
        文           fgetc(),getc()                从指定文件取得一个字符

       件           fputc(),putc()                把字符输出到指定文件

       读               fgets()                           从指定文件读取字符串

       写              fputs()                           把字符串输出到指定文件

                          getw()                           从指定文件读取一个字(int)型

                         putw()                          把一个字(int)型输出到指定文件

                         fread()                        从指定文件中读取数据项

                         fwrite()                       把数据项写到指定文件

                         fscanf()                        从指定文件按格式输入数据

                        fprintf()                         按指定格式将数据写到指定文件中

   文                feof()                         若到文件末尾,函数值为“真”(非0)
   件                ferror()                      若对文件操作出错,函数值为“真”(非0)
状态             clearerr()                   使 ferror 和 feof 函数值置零

 

文件这一章的内容是很重要的,许多可供实际使用的 C 程序都包含文件处理
.

本章只介绍一些最基本的概念,由于篇幅所限,不可能举复杂的例子。

 

如何进行文件操作(程序如下)

#include "stdio.h"
main() /*先新建一个文件夹(file.txt),运行该程序后,就有输入到文件中.*/
{
   FILE *fp;
    int x,y,x1,y1,z;
    printf("please input two integer numbers:");
    scanf("%d %d",&x,&y);
    if((fp=fopen("file.txt","w"))==NULL) /*打开文件file.txt,准备往文件中写入数据*/
    {
         printf("cann't open file");
           exit(0);
    }
    fprintf(fp,"%d %d",x,y); /*将x,y的值写入文件*/
    fclose(fp);   /*关闭文件*/
    if((fp=fopen("file.txt","r"))==NULL) /*打开文件file.txt,准备从文件中读出数据*/
    {
           printf("cann't open file");
           exit(0);

    }

fscanf(fp,"%d %d",&x1,&y1); /*将刚才写入的两个整数分别读到变量x1,y1中*/

fclose(fp);   /*关闭文件*/

    z=x1+y1;    /*计算两个数的和*/

    printf("z=%d",z);   /*显示在屏幕上*/
}

 

 

file2.c 程序

#include<stdlib.h>
#include<stdio.h>
void main()
{
FILE*in,*out;
char ch,infile[10],outfile[10];
printf("Enter the infile name:\n");
scanf("%s",infile);
printf("Enter the infile name:\n");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL)
{
printf("can not open infile\n");
exit(0);
}
if((out=fopen(outfile,"w"))==NULL)
{
printf("can not open outfile\n");
exit(0);
}
while(! feof(in)) fputc(fgetc(in),out);
fclose(in);
fclose(out);

}

 

file1(文本文档里的内容)

11 12

posted @ 2010-08-13 08:51 wrh 阅读(210) | 评论 (0)编辑 收藏

文件打开之后,就可以对它进行读写了。常用的读写函数如下所述。

13.4.1 fputc 函数和 fgetc 函数(putc 函数和 getc 函数)

1. fputc 函数

把一个字符写到磁盘文件上去。其一般调用形式为

fputc (ch,fp);

其中ch 是要输出的字符,它可以是一个字符常量,也可以是一个字符变量.
fp 是文件指针变量。fputc (ch,fp) 函数的作用是将字符(ch的值)输出到所指向的文件中去。fputc 函数也带回一个值:如果输出成功,则返回值就是输出的字符;如果输出失败,则返回一个EOF(即—1)。EOF 是在 stdio.h 文件中定义的符号常量,值为—1。

       在第4章介绍过 putchar 函数,其实 putchar 是从 fputc 函数派生出来的。putchar(c) 是在 stdio.h 文件中用预处理命令 #define 定义的宏:

        #define   putchar(c)   fputc(c,stdout)

    前面已叙述,stdout   是系统定义的文件指针变量,它与终端输出相联.
fputc(c,stdout)的作用是将 c 的值输出到终端.用宏putchar(c)比写fputc(c,stdout)
简单一些。从用户的角度,可以把 putchar(c) 看作函数而不必严格地称它为宏。

2.fgetc 函数

从指定的文件读入一个字符,该文件必须是以读或读写方式打开的。fgetc 函数的调用形式为: ch=fgetc(fp);

fp 为文件型指针变量,ch 为字符变量。fgetc 函数带回一个字符,赋给 ch。
如果在执行 fgetc 函数读字符时遇到文件结束符,函数返回一个文件结束标志EOF(即—1)。如果想从一个磁盘文件顺序读入字符并在屏幕上显示出来,可以用:

ch=fgetc(fp);
while(ch!=EOF)
{
putchar(ch);
ch=fgetc(fp);
}

注意:EOF 不是可输出字符,因此不能在屏幕上显示。由于字符的 ASCII 码不可能出现—1,因此 EOF 定义为—1是合适的。当读入的字符值等于—1(即EOF)时,表示读入的已不是正常的字符而是文件结束符。但以上只适用于读文本文件的情况。现在 ANSI C 已允许用缓冲文件系统处理二进制文件,而读入某一个字节中的二进制数据的值有可能是—1,而这又恰好是EOF的值.
这就出现了需要读入有用数据而却被处理为“文件结束”的情况。为了解决这个问题,ANSI C 提供一个 feof 函数来判断文件是否真的结束。feof(fp)用来测试 fp 所指向的文件当前状态是否“文件结束”。如果是文件结束,函数feof(fp)的值为1(真);否则为0(假)。

如果想顺序读入一个二进制文件中的数据,可以用:

while(! feof(fp))
{
c=fgetc(fp);
……
}

当未遇文件结束,feof(fp)的值为0,! feof(fp) 的值为1,读入一个字节的数据赋给整型变量c,并接着对其进行所需的处理。直到遇文件结束,feof(fp)值为1,! feof(fp) 值为0,不再执行 while 循环.

这种方法也适用于文本文件。

3. fputc 和 fgetc函数使用举例

在掌握了以上几种函数以后,可以编制一些简单的使用文件的程序。

例13 .1 从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入一个“#”为止。程序如下: (本例有错误)
#include "stdio.h"
#include "stdlib.h"
void main()
{
    FILE * fp;
    char ch,filename[10];
    scanf("%s",filename);
    if((fp=fopen(filename,"W"))==NULL)
     {
     printf("cannot open file\n");
     exit(0);
     }
     ch=getchar();
     ch=getchar();
     while(ch!='#')
     {
     fputc(ch,fp);
     putchar(ch);
     ch=getchar();
     }
     putchar(10);
     fclose(fp);
}
运行结果是:
输入:file1.c
cannot open file
(不能打开文件)

文件名由键盘输入,赋给字符数组 filename。 fopen 函数中的第一个参数“文件名” 可以直接写成字符串常量形式(如file1.c),也可以用字符数组名,在字符数组中存放文件名(如本例所用的方法)。本例运行时,从键盘输入磁盘文件名 “file1.c” ,然后输入要写入该磁盘文件的字符“ computer and c”, '#' 是表示输入结束,程序将 “ computer and c” 写到以命名的磁盘文件中,同时在屏幕上显示这些字符 ,以便核对。exit 是标准 C 的库函数,作用是使程序终止,用此函数应当加入 stdlib 头文件。

例13.2 将一个磁盘文件中的信息复制到另一个磁盘文件中。
(能运行,不能复制 )
#include<stdlib.h>
#include<stdio.h>
void main()
{
FILE*in,*out;
char ch,infile[10],outfile[10];
printf("Enter the infile name:\n");
scanf("%s",infile);
printf("Enter the infile name:\n");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL)
{
printf("can not open infile\n");
exit(0);
}
if((out=fopen(outfile,"w"))==NULL)
{
printf("can not open outfile\n");
exit(0);
}
while(! feof(in)) fputc(fgetc(in),out);
fclose(in);
fclose(out);
}

运行情况如下:
Enter the infile name:
file1.txt      (输入原有磁盘文件名)
Enter the infile name:
file2.txt      (输入新复制的磁盘文件名)

程序运行结果是将 file1.txt 文件中的内容复制到 file2.txt 中去。

以上程序是按文本文件方式处理的。也可以用此程序来复制一个二进制文件,只需将两个 fopen 函数中的 r 和 w 分别改为 rb 和 wb 即可。

也可以在输入命令行时把两个文件名一起输入。这时要用到 main 函数的参数。程序可改为:
#include<stdlib.h>
#include<stdio.h>
void main(int agc,char *argv[])
{
FILE * in,* out;
char ch;
if(argc !=3)
{
printf("You forgot to enter a filename\n");
exit(0);
}
if((in=fopen(argv[1],"r"))==NULL)
{
   printf("cannot open infile\n");
exit(0);
}
if((out=fopen(argv[2],"w"))==NULL)
{
   printf("cannot open infile\n");
exit(0);
}
while(! feof(in)) fputc(fgetc(in),out);
fclose(in);
fclose(out);
}


假若本程序的原文件名为 1.c 经编译连接后得到的可执行文件名为 1.exe ,则在DOS命令工作方式下,可以输入以下的命令行:C>1 file1.c file2.c 即在输入可执行文件名后,再输入两个参数 file1.c 和 file2.c ,分别输入到 argv[1]和 argv[2]中,argv[0]的内容为a,argc 的值等于3(因为此命令行共有3个参数) 。如果输入的参数少于3个,则程序会输出:“You forgot to enter a filename”
(你忘了输入一个文件名)。程序执行结果是将 file1.c 中的信息复制到 file2.c 中。可以用以下命令验证:
C>type file1.c
computer and c
(这是 file1.c 文件中的信息)

C>type file2.c
computer and c
(这是 file2.c 文件中的信息。可见 file1.c已复制到 file2.c 中了)。

最后说明一点,为了书写方便,系统把 fputc 和 fgetc 定义为宏名putc 和getc:

#define putc(ch,fp) fputc(ch,fp)
#define getc(fp) fgetc(fp)

这是在 stdio.h 中定义的。因此,用 putc 和 fputc 及用 getc 和 fgetc 是一样的。一般可以把它们作为相同的函数来对待。


 


   13.4.2 fead 函数和 fwrite 函数

用 getc 和 putc 函数可以用来读写文件中的一个字符。但是常常要求一次读入一组数据(例如,一个实数或一个结构体变量的值),ANSI C 标准提出设置两个函数(fead 函数和 fwrite 函数),用来读写一个数据块。它们的一般调用形式为:

fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);

其中:buffer:是一个指针.对 fread 来说,它是读入数据的存放地址. 对fwrite 来说,
是要输出数据的地址(以上指的是起始地址)。

size : 要读写的字节数。
count: 要进行读写多少个 size 字节的数据项。
      fp: 文件型指针。

如果文件以二进制形式打开,用 fead 和 fwrite 函数就可以读写任何类型的信息,例如: fead(f,4,2,fp);      其中 f 是一个实型数组名。一个实型变量占4个字节。这个函数从所指向的文件读入2个4个字节的数据,存储到数组 f 中。
如果有一个如下的结构体类型:

struct student_type
{
char   name[10];
int   num;
int   age;
char   addr[30];
}stud[40];

结构体数组 stud 有40个元素,每一个元素用来存放一个学生的数据(包括姓名、学号、年龄、地址)。假设学生的数据已存放在磁盘文件中,可以用下面的 for 语句和 fread 函数读入40个学生的数据:

for(i=0;i<40;i++)
fread(&stud[i],sizeof(struct student_type),1,fp);

同样,以下 for 语句和 fwrite 函数可以将内存中的学生数据输出到磁盘文件中去:

for(i=0;i<40;i++)
fwrite(&stud[i],sizeof(struct student_type),1,fp);

如果 fead 和 fwrite 调用成功,则函数返回值为 count 的值,既输入或输出数据项的完整个数。

下面写出一个完整的程序。

例13.3   从键盘输入4个学生的有关数据,然后把它们转存到磁盘文件上去。
#include "stdio.h"
#define SIZE 4
struct student_type
{char name[10];
int age;
int num;
char addr[15];

}stud[SIZE];
void save()
{
   FILE * fp;
   int i;
   if((fp=fopen("stu_list","wb"))==NULL)
   {
   printf("cannot open file\n");
   return;
   }
   for(i=0;i<SIZE;i++)
   if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
    printf("file write error\n");
    fclose(fp);
}
void main()
{
int i;
for(i=0;i<SIZE;i++)
scanf("%s%d%d%s",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
save();
}

在main 函数中,从终端键盘输入4个学生的数据,然后调用 save 函数,将这些数据输出到以 " stu_list "命名的磁盘文件中。fwrite 函数的作用是将一个
长度为29字节数据块送到 stu_list 文件中(一个 student_type 类型结构体变量的长度为它的成员长度之和,即10+2+2+15=29)。
运行情况如下:
输入4个学生的姓名、学号、年龄和地址:

Zhang 1001 18 room_101  
Fun    1002 18   room_102        
Tan      1003 18   room_103              
    Lin 1004   21   room_104

    程序运行时,屏幕上并无输出任何信息,只是将从键盘输入的数据送到此盘文件上。为了验证在磁盘文件 “ stu_list ”中是否已存在此数据,可以用以下程序从 stu_list 文件中读入数据,然后在屏幕上输出。
#include "stdio.h"
#define SIZE 4
struct student_type
{
int age;
int num;
char addr[15];
char name[10];
}stud[SIZE];
void main()
{
int i;
FILE * fp;
fp=fopen("stu_list","rb");
for(i=0;i<SIZE;i++)
{
   fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%-10s %4d %4d %-15s\n",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
}
fclose(fp);
}

请注意:输入输出数据的状况。从键盘输入4个学生的数据是 ASCII 码,也就是文本文件。在送到计算机内存时,回车和换行符转换成一个换行符。再从内存以 “wb”方式(二进制写)输出到 stu_list 文件,此时不发生字符转换,按内存中存储形式原样输出到磁盘文件上。在上面验证程序中,又用“fread ”函数从 stu_list 文件向内存读入数据,注意此时用的是“rb” 方式,即二进制方式,数据按原样输入,也不发生字符转换。也就是这时候内存中的数据恢复到第一个程序向 “ stu_list ” 输出以前的情况。最后在验证程序中,用printf 函数输出到屏幕,printf 是格式输出函数,输出 ASCII 码,在屏幕上显示字符。换行符又转换为回车加换行符。

如果企图从 “ stu_list ”文件中以 “r ”方式读入数据就会出错。

fread 和 fwrire 函数一般用于二进制文件的输入输出。因为它们是按数据块的长度来处理输入输出的,在字符发生转换的情况下很可能出现与原设想的情况不同。 例如,写成:fread(&stud[i],sizeof(struct student_type),1,stdin);   企图从终端键盘输入数据,这在语法上并不存在错误,编译能通过。如果用以下形式输入数据: Zhang 1001 18 room_101  
                                           ……

由于 fread 函数要求一次输入29个字节(而不问这些字节的内容),因此输入数据中的空格也作为输入数据而不作为数据间的分隔符了。连空格也存储到 stud[i] 中了,显然是不对的。

这个题目要求的是从键盘输入数据,如果已有的数据已经以二进制形式存储在一个磁盘文件 stu_dat 中,要求从其中读入数据并输出到 stu_list 文件中,可以编写一个 load 函数,从磁盘文件中读二进制数据。

#include "stdio.h"
#define SIZE 4
struct student_type
{
int age;
int num;
char addr[15];
char name[10];
}stud[SIZE];
void load()
{
                  FILE * fp;
int i;
if((fp=fopen("stu_dat","rb"))==NULL)
{
   printf("cannot open file\n");
   return;
              }
   for(i=0;i<SIZE;i++)
   if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)
{ if(feof(fp))
{ fclose(fp);
    return;
}
    printf("file write error\n");
}
    fclose(fp);
}
main()
{
load();
save();
}

 


13.4.3   fprintf (从文件中输出) 函数和 fscanf (从文件中读入) 函数

fprintf 函数、fscanf 函数 与 printf 函数、scanf 函数作用相仿,都是格式读写函数。只有一点不同: fprintf 函数、fscanf 函数的读写对象不是终端而是磁盘文件。它们的一般调用方式为:

fprintf (文件指针,格式字符串,输出表列);
fscanf (文件指针,格式字符串,输入表列);

例如:

fprintf(fp,"%d,%6.2f",a,b);

它的作用是将整型变量 a 和实型变量 b 的值按 %d 和 %6.2f 的格式输出到 fp 指向的文件上。如果 i=3,t=4.5 则输出到磁盘文件上的是以下的字符串:

3, 4.50

同样,用以下函数可以从磁盘文件上读入 ASCII 字符:

fscanf(fp,"%d,%f",&a,&b);

磁盘文件上如果有这样的字符:3, 4.5   即将磁盘文件中的数据 3送给变量 a,4.5 送给变量 b。

用 fprintf 和 fscanf 函数对磁盘文件读写,使用方便,容易理解,但由于在输入时要将 ASCII 码转换为二进制形式,在输出时又要将二进制形式转换成字符,花费时间比较多。因此,在内存与磁盘频繁交换数据的情况下,最好不用 fprintf 和 fscanf 函数,而用 fread(从文件中读) 和 fwrite(往文件中写) 函数。


 

                                            13.4.4 其它读写函数
1. putw 和 getw 函数

大多数 C 编译系统都提供另外两个数:putw 和 getw 函数 ,用来对磁盘文件读写一个字(整数)。例如: putw(10,fp);     它的作用是将整数 10 输出到 fp指向的文件。而 i=getw(fp);     的作用是从磁盘文件读一个整数到内存,赋给整型变量 i。

如果所用的 C 编译系统的库函数中不包括 putw 和 getw 函数,可以自己定义这两个函数。putw 函数如下:

putw(int i,FILE * fp)
{
char * s;                                      图1:                     i
s=&i;                                                       00000000    00001010
putc(s[0],fp);                                                s[0]               s[1]
putw(s[1],fp);
return(i);
}
当调用 putw 函数时,如果用 putw(10,fp); 语句, 形参 i 得到实参传来的值 10, 在 putw 函数中将 i 的地址赋予指针变量 s ,而 s 是指向字符变量的指针变量,因此 s 指向 i 的第 1 个字节,s+1 指向 i 的第 2 个字节。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分别对应的第 1 个字节和第 2 个字节。顺序输出s[0]、s[1]就相当于输出了 i 的两个字节中的内容,见图1.
getw 函数如下:

getw(FILE * fp)
{
char * s;
int   i;
s=char * &i; /*使 s 指向 i 的起始地址 */
s[0]=getc(fp);
s[1]=getc(fp);
return(i);
}

putw 和 getw 函数并不是 ANSI C 标准定义的函数。许多 C 编译系统都提供这两个,但有的不以 putw 和 getw 命名此两函数,而用其它函数名,用时要注意。

2. 读写其它类型数据

如果用 ANSI C 提供的 fread 和 fwrite函数,读写任何类型数据都是十分方便的。如果所用的系统不提供这两个函数,用户只好自己定义所需函数。例如,可以定义一个向磁盘文件写一个实数(用二进制方式)函数 putfloat:

putfloat(float num,FILE * fp)
{
char * s;
int count;
s=(char *) &num;
for(count=0;count<4,count++)
    putc(s[count],fp);
}

同样可以编写出读写任何类型数据的函数。

3. fgets 函数和 fputs 函数

fgets 函数的作用是从指定文件读入一个字符串。例如:fgets (str,a,fp);   a 为要求得到的字符,但只从 fp指向的文件输入 a-1 个字符,然后在最后加一个‘ \0 ’字符,因此得到的字符串共有 a 个字符,把它们放到字符数组 str 中.如果
在读完 a-1个字符之前遇到换行符或 EOF ,读入即结束。 fgets 函数返回值为 str 的首地址。

   fputs 函数的作用是从指定文件输出一个字符串。例如:fputs("Wolong",fp);
把字符串 “ Wolong ” 输出到 fp 指向的文件。fputs 函数中第一个参数可以是字符串常量、字符数组名或字符指针。 字符串末尾的‘ \0 ’ 不输出。若输出成功,函数值为 0;失败时,为 EOF 。

     这两个函数类似以前介绍过的 gets 和 puts 函数, 只是 fgets 和 fputs 函数以指定的文件为读写对象。

fgets(从文件中获取字符串)

fputs(往文件中写字符串)

 

如果所用的 C 编译系统的库函数中不包括 putw 和 getw 函数,可以自己定义这两个函数。putw 函数如下:

putw(int i,FILE * fp)
{
char * s;                                      图1:                     i
s=&i;                                                       00000000    00001010
putc(s[0],fp);                                                s[0]               s[1]
putw(s[1],fp);
return(i);
}
当调用 putw 函数时,如果用 putw(10,fp); 语句, 形参 i 得到实参传来的值 10, 在 putw 函数中将 i 的地址赋予指针变量 s ,而 s 是指向字符变量的指针变量,因此 s 指向 i 的第 1 个字节,s+1 指向 i 的第 2 个字节。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分别对应的第 1 个字节和第 2 个字节。顺序输出s[0]、s[1]就相当于输出了 i 的两个字节中的内容,见图1.
getw 函数如下:

getw(FILE * fp)
{
char * s;
int   i;
s=char * &i; /*使 s 指向 i 的起始地址 */
s[0]=getc(fp);
s[1]=getc(fp);
return(i);
}


如果用 ANSI C 提供的 fread 和 fwrite函数,读写任何类型数据都是十分方便的。如果所用的系统不提供这两个函数,用户只好自己定义所需函数。例如,可以定义一个向磁盘文件写一个实数(用二进制方式)函数 putfloat:

putfloat(float num,FILE * fp)
{
char * s;
int count;
s=(char *) &num;
for(count=0;count<4,count++)
    putc(s[count],fp);
}

同样可以编写出读写任何类型数据的函数。


例13.1从键盘输入一些字符,逐个把它们送到磁盘上,直到输入一个"#"为止.程序如下:
#include<stdlib.h>
#include<stdio.h>
void main()
{
FILE*fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL)
{
printf("can not open file\n");
exit(0);/*终止程序*/
}
ch=getchar();/*接收输入的一个字符*/
ch=getchar();/*这一句可以省略.*/
while(ch!='#')
{
fputc(ch,fp);putchar(ch);
ch=getchar();
}
putchar(10);/*向屏幕输出一个换行符*/
fclose(fp);
}
运行后的结果:输入:is a c# 输出 a c

 

 

                                        13.5     文件的定位

文件中有一个位置指针,指向当前读写的位置。如果顺序读写一个文件,每次读写一个字符,则读写完一个字符后,该位置指针自动移动指向下一个字符位置。如果想改变这样的规律,强制使位置指针指向其它指定的位置,可以用后面介绍的有关函数。

13.5.1 rewind 函数

rewind 函数的作用是使位置指针重新返回文件的开头,此函数没有返回值。

例13.4 有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制到另一文件上。
#include "stdio.h"
void main()
{
FILE * fp1,* fp2;
fp1=fopen("file1.txt","r");
fp2=fopen("file2.txt","w");
while(! feof(fp1))
putchar(getc(fp1));
rewind(fp1);
while(! feof(fp1))
putc(getc(fp1),fp2);
fclose(fp1);
fclose(fp2);
}
(先在某一个位置上新建立一个文本文件,命名为file1.txt然后运行本程序(在vc编译系统运行过))如:“ file1.txt ”里面的内容是:
         Nu11              pointer              assignment
      (无效的) ( 指示器)(分配、任务、作业)
运行后的结果是:

在第一次将内容显示在屏幕上,file1.txt 的位置指针已指到文件末尾,feof 的值为零(真)。执行 rewind 函数 ,使文件的位置指针重新定位于文件开头,并使 feof 函数的值恢复为0(假)。

fopen (打开文件) fclose(文件关闭) rewind(重新) putchar(写一个字符的函数)feof=end of file (文件末尾)   putc (输出字符)

posted @ 2010-08-13 08:50 wrh 阅读(621) | 评论 (0)编辑 收藏

对流式文件可以进行顺序读写,也可以进行随机读写,关键在于控制文件的位置指针。如果位置指针是按字节位置顺序移动的,就是顺序读写;如果能将位置指针按需要移动到任意的位置,就可以实现随机读写.所谓随机读写,是指读写完上一个字符(字节)后,并不一定要读写其后续的字符(字节),而可以读写文件中任意位置上所需要的字符(字节)。

用 fseek 函数可以实现改变文件的位置指针。

fseek 函数的调用形式为: fseek (文件类型指针,位移量,起始点)

“起始点 ”用0、1或 2 代替,0代表 “文件开始”,1 为“当前位置”,2 为 “文件末尾”。 ANSI C 标准指定的名字如下表所示:

        起始点                           名字                      用数字代表
     文件开始                     SEEK_SET                          0
     文件当前位置            SEEK_ CUR                        1                                                       
     文件末尾                     SEEK_END                         2

“位移量”指以 “起始点” 为基点,向前移动的字节数。ANSI C 和大多数版本要求位移量是(long)长整型数据。这样当文件的长度大于64KB时不致出问题。ANSI C 标准规定在数字的末尾加一个字母 L,就表示是 long 型。

fseek 函数一般用于二进制文件,因为文本文件要发生字符转换,计算位置时往往会发生混乱。

下面是fseek 函数调用的几个例子:

fseek(fp,100L,0);/* 将位置指针移到离文件头100个字节处 */

fseek(fp,50L,1); /* 将位置指针移到离当前位置50个字节处 */

fseek(fp,--10L,2);/* 将位置指针从文件末尾处向后退 10 个字节 */

利用 fseek 函数就可以实现随机读写了。

例13.5 在磁盘文件上存有 10 个学生的数据。要求将第 1、3、5、7、9个学生数据输入计算机,并在屏幕上显示出来。程序如下:

#include "stdlib.h"
#include "stdio.h"
struct student_type
{
char name[10];
int num;
int age;
char sex;
}stud[10];
void main()
{
    int a;
    FILE * fp;
    if((fp=fopen("stud_dat.txt","rb"))==NULL)
    {
    printf("can not open file\n");
    exit(0);
    }
    for(a=0;a<10;a+=2)
    {
    fseek(fp,a * sizeof(struct student_type),0);
    fread(&stud[a],sizeof(struct student_type),1,fp);
    printf("%s %d %d %c\n",stud[a].name,stud[a].num,stud[a].age,stud[a].sex);
    }
    fclose(fp);
}
(先新建一个文本文件名为“stud_dat.txt”(可以改其它名字),然后在里面输入10学生的数据。接着再把本程序在VC编译系统中运行……)。


                                        13.5.3 ftell 函数

   ftell 函数的作用是得到流式文件中的当前位置,用相对文件开头的位移量来表示。由于文件中的位置指针经常移动,人们往往不容易知道其当前位置。
用 ftell 函数可以得到当前位置 。如果 ftell 函数返回值为--1L,表示出错。例如:
a=ftell(fp);
if(a==--1L)
printf("error\n");

变量 a 存放当前位置,如调用函数时出错(如不存在 fp 文件),则输出“error”。


    tell(告诉,吩咐,断定,知道,)

 

例13.4 有一个磁盘文件,第一次将它的内容显示在屏幕上,第二次把它复制

#include "stdio.h"
void main()
{
FILE * fp1,* fp2;
fp1=fopen("file1.txt","r");
fp2=fopen("file2.txt","w");
while(! feof(fp1))
putchar(getc(fp1));
rewind(fp1);
while(! feof(fp1))
putc(getc(fp1),fp2);
fclose(fp1);
fclose(fp2);
}

 

例13.5 在磁盘文件上存有 10 个学生的数据。要求将第 1、3、5、7、9个学

#include "stdlib.h"
#include "stdio.h"
struct student_type
{
char name[10];
int num;
int age;
char sex;
}stud[10];
void main()
{
    int a;
    FILE * fp;
    if((fp=fopen("stud_dat.txt","rb"))==NULL)
    {
    printf("can not open file\n");
    exit(0);
    }
    for(a=0;a<10;a+=2)
    {
    fseek(fp,a * sizeof(struct student_type),0);
    fread(&stud[a],sizeof(struct student_type),1,fp);
    printf("%s %d %d %c\n",stud[a].name,stud[a].num,stud[a].age,stud[a].sex);
    }
    fclose(fp);
}

 

 

file1(文本文档里的内容)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

 

stud_dat(文本文档里的内容)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

Nu11              pointer              assignment
(无效的) ( 指示器)(分配、任务、作业)

 

 

posted @ 2010-08-13 08:49 wrh 阅读(1851) | 评论 (0)编辑 收藏
ASCII码是7位编码,字符在计算机中以其ASCII码方式表示,其长度为1个字节, 有符号字符型数。编码范围是0x00-0x7F(0~127)。ASCII字符集包括英文字母、阿拉伯数字和标点符号等字符。其中0x00-0x20和0x7F共33个控制字符。

ASCII 十六进制 控制字 代码含义
00           00            NUL      空
01           01            SOH      标题开始
02           02            STX      正文开始
03           03            ETX      正文结束
04           04            EOT         传输结否
05           05            ENQ        询问
06           06            ACK        确认
07           07            BEL         响铃
08           08            BS          退格
09           09            HT          横向列表
10           0A            LF          换行
11           0B             VT          纵向列表
12           0C            FF             换页
13           0D            CR            回车
14           0E            SO             换档(Shift-Out)
15           0F            SI             换档(Shift-In)
16           10            DLE         数据链扩展
17           11            DC1         设备控制1
18           12            DC2         设备控制2
19           13            DC3         设备控制3
20            14            DC4         设备控制4
21           15            NAK         不确认
22           16            SYN         同步字符
23           17            ETB         传输块结否
24           18            CAN         作废
25           19            EM          介质结束
26           1A            SUB         置换
27           1B            ESC         扩展
28           1C            FS             文件分隔符
29           1D            GS          组分隔符
30           1E            RS          记录分隔符
31           1F            US          单位分隔符

ASCII码对照表

ASCII码 键盘 ASCII 码 键盘 ASCII 码 键盘 ASCII 码 键盘
27 ESC 32 SPACE 33 ! 34 "
35 # 36 $ 37 % 38 &
39 ' 40 ( 41 ) 42 *
43 + 44 ' 45 - 46 .
47 / 48 0 49 1 50 2
51 3 52 4 53 5 54 6
55 7 56 8 57 9 58 :
59 ; 60 < 61 = 62 >
63 ? 64 @ 65 A 66 B
67 C 68 D 69 E 70 F
71 G 72 H 73 I 74 J
75 K 76 L 77 M 78 N
79 O 80 P 81 Q 82 R
83 S 84 T 85 U 86 V
87 W 88 X 89 Y 90 Z
91 [ 92 \ 93 ] 94 ^
95 _ 96 ` 97 a 98 b
99 c 100 d 101 e 102 f
103 g 104 h 105 i 106 j
107 k 108 l 109 m 110 n
111 o 112 p 113 q 114 r
115 s 116 t 117 u 118 v
119 w 120 x 121 y 122 z
123 { 124 | 125 } 126 ~

只支持ASCII码的系统会忽略每个字节的最高位,只认为低7位是有效位。HZ字符编码就是早期为了在只支持7位ASCII系统中传输中文而设计的编码。早期很多邮件系统也只支持ASCII编码,为了传输中文邮件必须使用BASE64或者其他编码方式。


GB2312字符集编码


GB2312 是汉字字符集和编码的代号,中文全称为“信息交换用汉字编码字符集”,由中华人民共和国国家标准总局发布,一九八一年五月一日实施。GB 是“国标” 二字的汉语拼音缩写。

GB2312 字符集 (character set) 只收录简化字汉字,以及一般常用字母和符号,主要通行于中国大陆地区和新加坡等地。GB2312 共收录有 7445 个字符,其中简化汉字 6763 个,字母和符号 682 个。

GB2312 将所收录的字符分为 94 个区,编号为 01 区至 94 区;每个区收录 94 个字符,编号为 01 位至 94 位。GB2312 的每一个字符都由与其唯一对应的区号和位号所确定。例如:汉字“啊”,编号为 16 区 01 位。

GB2312 字符集的区位分布表:

区号    字数    字符类别
01      94    一般符号
02      72    顺序号码
03      94    拉丁字母
04      83    日文假名
05      86    Katakana
06      48    希腊字母
07      66    俄文字母
08      63    汉语拼音符号
09      76    图形符号
10-15            备用区
16-55    3755    一级汉字,以拼音为序
56-87    3008    二级汉字,以笔划为序
88-94            备用区

这本手册列出了 GB2312 的全部字符和它们的区位号。

GB2312 编码

GB2312 原始编码 (encoding) 是对所收录的每个字符都用两个字节 (byte) 表示。第一字节为“高字节”,由字符的区号值加上 32 而形成;第二字节为“低字节”,由字符的位号值加上 32 而形成。例如:汉字“啊”,编号为 16 区 01 位。它的高字节为 16 + 32 = 48 (0x30),低字节为 01 + 32 = 33 (0x21),合并而成的编码为 0x3021。

在区位号值上加 32 的原因大慨是为了避开低值字节区间。

由于 GB2312 原始编码与 ASCII 编码的字节有重叠,现在通行的 GB2312 编码是在原始编码的两个字节上各加 128 修改而形成。例如:汉字“啊”,编号为 16 区 01 位。它的原始编码为 0x3021,通行编码为 0xB0A1。

如果不另加说明,GB2312 常指这种修改过的编码。

GB2312的编码范围是0xA1A1-0x7E7E,去掉未定义的区域之后可以理解为实际编码范围是0xA1A1-0xF7FE。

上面这句有误,应该说GB2312的每一个汉字由两个字节构成,其中每一个字节的范围都在0xA1 ~0xFE,正好每一个字节都有94个编码范围,与区位码个数完全对应。

EUC-CN可以理解为GB2312的别名,和GB2312完全相同。

区位码更应该认为是字符集的定义,定义了所收录的字符和字符位置,而GB2312及EUC-CN是实际计算机环境中支持这种字符集的编码。HZ和 ISO-2022-CN是对应区位码字符集的另外两种编码,都是用7位编码空间来支持汉字。区位码和GB2312编码的关系有点像 Unicode和UTF-8。

GBK字符集编码

GBK 编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode基本多文种平面中的所有CJK汉字。同 GB2312一样,GBK也支持希腊字母、日文假名字母、俄语字母等字符,但不支持韩语中的表音字符(非汉字字符)。GBK还收录了GB2312不包含的 汉字部首符号、竖排标点符号等字符。

GBK的整体编码范围是为高字节范围是0×81-0xFE,低字节范围是0x40-7E和0x80-0xFE,不包括低字节是0×7F的组合。

低字节是0x40-0x7E的GBK字符有一定特殊性,因为这些字符占用了ASCII码的位置,这样会给一些系统带来麻烦。

有些系统中用0x40-0x7E中的字符(如“|”)做特殊符号,在定位这些符号时又没有判断这些符号是不是属于某个 GBK字符的低字节,这样就会造成错误判断。在支持GB2312的环境下就不存在这个问题。需要注意的是支持GBK的环境中小于0x80的某个字节未必就 是ASCII符号;另外就是最好选用小于0×40的ASCII符号做一些特殊符号,这样就可以快速定位,且不用担心是某个汉字的另一半。Big5编码中也 存在相应问题。
CP936和GBK的有些许差别,绝大多数情况下可以把CP936当作GBK的别名。

GB18030字符集编码

GB18030编码向下兼容GBK和GB2312,兼容的含义是不仅字符兼容,而且相同字符的编码也相同。GB18030收录了所有Unicode3.1中的字符,包括中国少数民族字符,GBK不支持的韩文字符等等,也可以说是世界大多民族的文字符号都被收录在内。

GBK和GB2312都是双字节等宽编码,如果算上和ASCII兼容所支持的单字节,也可以理解为是单字节和双字节混合的变长编码。GB18030编码是变长编码,有单字节、双字节和四字节三种方式。

GB18030 的单字节编码范围是0x00-0x7F,完全等同与ASCII;双字节编码的范围和GBK相同,高字节是0x81-0xFE,低字节的编码范围是0x40 -0x7E和0x80-FE;四字节编码中第一、三字节的编码范围是0x81-0xFE,二、四字节是0x30-0x39。

Windows 中CP936代码页使用0x80来表示欧元符号,而在GB18030编码中没有使用0x80编码位,用其他位置来表示欧元符号。这可以理解为是 GB18030向下兼容性上的一点小问题;也可以理解为0x80是CP936对GBK的扩展,而GB18030只是和GBK兼容良好。

unicode字符集编码

   每一种语言的不同的编码页,增加了那些需要支持不同语言的软件的复杂度。因而人们制定了一个世界标准,叫做unicode。unicode为每个字符 提供 了唯一的特定数值,不论在什么平台上、不论在什么软件中,也不论什么语言。也就是说,它世界上使用的所有字符都列出来,并给每一个字符一个唯一特定数值。

Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's),尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。
因 此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是 以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8 和ASCII中,“A”的编码都是0x41.

UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。在讨论Unicode时,搞清楚哪种编码方式非常重要。

UTF-8字符集编码

Unicode Transformation Format-8bit,允许含BOM,但通常不含BOM。是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三 个字节)来编码。UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF8字符集的浏览器上显 示。如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,他们无需下载IE的中文语言支持包。

GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBD大。

GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换

GBK、GB2312--Unicode--UTF8

UTF8--Unicode--GBK、GB2312

对于一个网站、论坛来说,如果英文字符较多,则建议使用UTF-8节省空间。不过现在很多论坛的插件一般只支持GBK。
posted @ 2010-08-06 10:25 wrh 阅读(1195) | 评论 (0)编辑 收藏
仅列出标题
共25页: First 6 7 8 9 10 11 12 13 14 Last 

导航

<2011年5月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(19)

随笔档案

文章档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜