标题：iso2709
MARC数据产生与发展
MARC数据最早产生于美国。1961年，美国国会图书馆开始图书馆自动化的设想，随着计算机技术的进步，1963年，美国国会图书馆组织了在内部工作中采用电子计算机技术的可行性调查，1966年1月，产生了《标准机器能读目录款式的建议》，即MARC-1格式，1967年提出MARC-2，它是目前使用的各种机读目录格式的母本。1969年开始向全国发行MARCII格式书目磁带，并将MARCII格式称为US- MARC，即美国机器可读目录。作为一种计算机技术发展早期形成的数据格式，这一格式在定义时比较充分地照顾到图书馆书目数据在文献形式描述、内容描述、检索等方面的需要，表现为：字段数量多；著录详尽；可检索字段多；定长与不定长字段结合，灵活实用；保留主要款目及传统编目的特点；扩充修改功能强；并能在实践中不断发展完善。美国机读目录适合美国国情，英法等国家根据各自情况创建了自己的机读目录，为了进一步协调、促进国际交流，统一各国机读目录格式，国际图书馆联合会在USMARC基础上制订了“国际机读目录通信格式”，即UNIMARC，现在许多国家都采用UNIMARC进行文献编目。
CNMARC简介
CNMARC是中国机读目录（China Machine-Readable Catalogue）的缩写，是用于中国国家书目机构同其它国家书目机构以及中国国内图书馆与情报部门之间，以标准的计算机可读形式交换书目信息。中国机读目录研制于20世纪70年代。1979年成立了全国信息与文献标准化技术委员会，成立北京地区机读目录研制小组；1982年，中国标准总局公布了参照ISO2709制定的国家标准《文献目录信息交换用磁带格式》(GB2901-82)，为中文MARC格式的标准化奠定了基础；1986年UNIMARC中译本面世。在此基础上，根据我国实际情况，编制《中国机读目录通讯格式》讨论稿，1992年2月正式出版《中国机读目录通讯格式》，即CN-MARC。CNMARC格式为我国机读目录实现标准化、与国际接轨，从数据结构方面提供了保障。
ISO2709的格式
cnMarc主要分为三个段,头标 目次 数据三个区.[1]头标区1. 定义
该部分包含根据ISO 2709 制订的对记录进行处理时所需的通用信息。
2. 出现情况
记录头标区出现在每个记录的开头，它是必备的和不可重复的。
3. 字段号、指示符和子字段
记录头标没有字段号、指示符或子字段标识。
4. 定长数据元素
头标中的数据元素是由字符位置标识的。头标的总长度为24个字符。字符位置规定从
0-23。
固定长数据元素表
数据元素名称  字符数 字符位置
(1)记录长度  5 0-4
(2)记录状态  1 5
(3)执行代码  4 6-9
(4)指示符长度  1 10
(5)子字段标识符长度 1 11
(6)数据起始地址 5 12-16
(7)记录附加定义 3 17-19
(8)地址目次区结构 4 20-23
. 内容注释
记录头标定位在每个记录的开头，它包含处理记录的需的数据。
字符位9，10，11，20-23
所含的特定值可通过计算机程序生成。字符位0-4和12-16所含 的是数字型数据，它
表示记录中相应部分的字符数量可能由计算机在生成记录时产生。
字符位5，6-9，17-19
的值，如果采用外来源数据，可以从源记录数据中通过转换程序生成。若使用本格式制作源记录，则
由、手工指定。
详细内容见详细窗固定长模板.
相关字段
记录头标中提供的数据元素在格式的其它部分是没有的。虽然执行代码的一些值，
如“记录类型”和“书目级别”与其它代码数据有些相重，但事实上头标里的代码表示
的是记录的特征，而不是直接表示书目实体本身特征。目次区目次区由一串数字构成,主要反映该记录中的具有字段在数据区的起始位置及长度.每12位表示一个字段信息
1-3:字段名
4-7:长度
8-12:起始位置数据区根据目次区的折分信息可获得字段内容,再通过子字段的分隔符锋得具体子段/子字段内容
记录分隔符的ASCII值为29
字段分隔符的ACSII 值为30
子字段分隔符的ASCII值为31
C#读取ISO2709数据代码
[2]有时候我们需要在C#中读取ISO02709数据，但是有很多新手对这个还不会，今天花了一点时间特意写了这个代码，希望对大家有帮助。using System;
using System.Collections;
/*
此类的功能,是读取ISO2709数据
得到ISO2709数据三个段,头标\\目次\\数据
获得字段信息
获得子字段信息
*/
namespace Nosi.Library
{
/// <summary>
/// Class1 的摘要说明。
/// </summary>
public class Marc
{
#region 常量定义
public const char FLDEND  = (char)30; // 字段结束符
public const char RECEND  = (char)29; // 记录结束符
public const char SUBFLD  = (char)31; // 子字段指示符
public const int FLDNAME_LEN =        3;       // 字段名长度
public const int MAX_MARCREC_LEN =    100000;   // MARC记录的最大长度
#endregion
string m_strMarc = \"\"; // MARC记录体
public Marc()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
//获得头标
private string GetHeader()
{
string strHeader = null;
strHeader = m_strMarc.Substring(0,24);
return strHeader;
}
//获得目次
private string GetMuci()
{
char[] charr = m_strMarc.ToCharArray();
string strMuci = null;
int i = 24; // 头标字符不再读取
while(i < m_strMarc.Length)
{
strMuci += charr[i].ToString();
if(charr[i] == FLDEND) break;  //发现字段标识
i++;
}
return strMuci;
}
// 获得数据区
private string GetData()
{
string strData = null;
int iMuci = this.GetMuci().Length;
int iHeader = this.GetHeader().Length;
int iMarc = m_strMarc.Length;
strData = m_strMarc.Substring(iMuci + iHeader,iMarc - iMuci - iHeader);
return strData;
}
// 获得目次区中的字段名
//  -1 error
//  0  no found
//  1  found
private  int GetFieldPos(string strFieldName,
int nIndex,
out string  strFieldPos)
{
string strMuci = this.GetMuci();
strFieldPos = null;
int i = 0;
int nRet = 0;
if(strMuci == null)
return -1;
if((strMuci.Length - 1) % 12  != 0) // 减1是由于目次区结束标识符[Page]
return -1; // length error
do
{
if(strMuci.Substring(i,3) == strFieldName)
nRet ++;
if(nRet == nIndex)// from zero add
{
strFieldPos = strMuci.Substring(i,12);
break;
}
i += 12;
} while(i<strMuci.Length);
if (strFieldPos  == null) 
return 0; // no found 
return 1;
}
// 通过字段名，字段中出现次数获得字段内容
// 次数从 1  开始计数
// -1 error
// 0  no found
// 1  found
public int GetField(string strFldName,
int nIndex,
out string strFld)
{
strFld = null;
string strFldPos = null;
int nRet = this.GetFieldPos(strFldName,nIndex,out strFldPos);
if (nRet != 1)
return nRet;
if(strFldName.Length != 3 )
return -1;  // subfield must 3 chars 
int nLength = int.Parse( strFldPos.Substring(3,4));
int nBeginPos = int.Parse( strFldPos.Substring(7,5));
char[] chData = this.GetData().ToCharArray();
int nPos =0;
int i = 0;
while( nPos < chData.Length)
{
i += GetCharLength(chData[nPos]);
if((i >= nBeginPos) && i<= (nBeginPos + nLength))
strFld += chData[nPos].ToString();
nPos ++;
}
if(strFld == null)
return 0;
return 1;
}
//从字段中获得出现次数的子字段
// -1 error
// 0 not found
// 1 found
public int GetSubField(string strFld,
string  strSubName,
int nIndex,
out string strSubFld)
{
strSubFld  = null;
if(strSubName.Length != 1) 
return -1; // subfield\'symbol char must 1 char
if(strFld == null)
return -1;
char[] chData = strFld.ToCharArray();
int nPos = 0;
bool isNewSub = false;
int nFound = 0; // 0: not 1: first time found 2: second time found
while( nPos < chData.Length)
{    
nPos ++; [Page]
if((chData[nPos-1] == SUBFLD) && (chData[nPos].ToString() == strSubName))
nFound ++; // found        if ((nFound == nIndex) && (isNewSub == false))
{     
if(chData[nPos] == SUBFLD)
{
isNewSub = true;
break;
}
strSubFld += chData[nPos].ToString();
}
}
if(strSubFld == null)
return 0;
return 1;
}
//从字段组中获得子字段
// -1 error
// 0 not found
// 1 found
public int GetSubField(string strGroup,
string  strSubName,
out string strSubFld)
{
strSubFld  = null;
if(strSubName.Length != 1) 
return -1; // subfield\'symbol char must 1 char
if(strGroup == null)
return -1;
char[] chData = strGroup.ToCharArray();
int nPos = 0;
bool isNewSub = false;
int nFound = 0; // 0: not 1: first time found 2: second time found
while( nPos < chData.Length)
{    
nPos ++; 
if((chData[nPos-1] == SUBFLD) && (chData[nPos].ToString() == strSubName))
nFound ++; // found    
if (isNewSub == false)
{     
if(chData[nPos] == SUBFLD)
{
isNewSub = true;
break;
}
strSubFld += chData[nPos].ToString();
}
}
if(strSubFld == null)
return 0;
return 1;
}
//从字段中获得出现次数字段组
// -1 error
// 0 not found
// 1 found
public int GetFieldGroup(string strFld,
int nIndex,
out string strGroup)
{
strGroup = null;
if(strFld == null)
return -1;
char[] chData = strFld.ToCharArray();
int nPos = 0;
string strSplit = \"a\"; // 一般以a子字段为字段组区分 
int nFound = 0; // 0: not 1: first time found 2: second time found[Page]
while( nPos < chData.Length)
{    
nPos ++; 
if((chData[nPos-1] == SUBFLD) && (chData[nPos].ToString() == strSplit))
nFound ++; // found    
if (nFound == nIndex)
strGroup += chData[nPos].ToString();
if(nFound > nIndex)
break;    
}
if(strGroup == null)
return 0;
return 1;
}
//获得字符的长度
//
private int GetCharLength(char ch)
{
int nLength = 0;
if((short)ch < 0 || (short)ch  > 128)
{
nLength += 2;
}
else 
{
nLength = nLength + 1;
}
return nLength;
}
public string strMarc
{
get 
{
return m_strMarc;
}
set 
{
m_strMarc = value;
}
}
}
}