兼容

这是一场不停的追逐!


  • Home

  • About

  • Tags

  • Archives

gis学习记录

Posted on 2017-07-17 | Edited on 2016-12-22

分辨率,比例尺

分辨率:

  • 1像素对应的代表的地图单位;
  • 地图单位有米和度俩种, 当无投影时,为度; 当有投影如墨卡托投影时,为米;
  • 一度=111319.4908米= 地球周长/360=40075016.688米/360度;

比例尺

  • 屏幕上一米所代表的地图上的实际距离(m)
  • 1英寸=0.0254米; 1英寸=96像素; 则0.0254米=96像素,所以屏幕上1米=96/0.0254(像素)
  • 则比例尺为96*分辨率/0.0254;

根据分辨率求比例尺:

  • 墨卡托投影: 比例尺=分辨率*96/0.0254;
  • 无投影: 比例尺=分辨率96111319.4908/0.0254; 无投影时需要将地图单位从度转换为米;

根据比例尺求分辨率:

  • 墨卡托投影时: 分辨率=比例尺*0.0254/96;
  • 无投影: 分辨率=比例尺0.0254/(96111319.4908);

对于层的起始行列号(startCol, startRow)

  • 谷歌切图方式:
    • 如果切的是世界电图,则为(0, 0)
    • 不是世界地图, 则为所切地图在世界地图中的当前level所在的行列号;
  • 自定义切图方式:
    • 自定义方式时,则以地图的左上角为原点,切起始行列号为(0, 0);

经纬度

经度

  1. 负经度表示西半球; W
  2. 正经度表示东半球; E

纬度

  1. 负纬度为南半球; S
  2. 正纬度为南半球; N

坐标系

理解

1
2
3
4
5
6
7
8
9
10
  假设地球是正圆的,地球表面上的一点可以用经纬度来表示,这时的经纬度是唯一的。但是地球本来就不是圆的,
而是一个椭圆, 所以导致经纬度会根据椭球体的不同而不同. 关于这个椭圆并不是唯一的,比如克拉索夫斯基椭球,
1975国际椭球等等。椭球的不同主要由两个参数来体现: 长半轴和扁率。 之所以会有不同的椭球体出现,是因为地
球太大了。地球不是一个正椭球体,一个椭球体不可能满足地球每个角落的精度要求,在一些边缘地带误差会很大,
在赤道附近有适合赤道使用的椭球体,在极圈附近有适合极圈的椭球地,一切都是为了符合当地的精度需要。如果你
有足够的需求也可以自定义一个椭球体。基于以上原因,就很好理解经纬度为什么不是唯一的..当你使用克拉索夫基
椭球体时是一对经纬度,当使用另外一个椭球体时又是另外一对经纬度。
用经纬度表示的是地理坐标系,也称大地坐标系。有时候用地理坐标系不够方便,人们比较习惯于使用平面坐标系,
平面坐标系用xy表示。把球体表面的坐标转成平面坐标需要一定的手段,这个手段称为投影。投影方法也不是唯一的,
都是为了一个目的,务求使当地的坐标最准确。所以目前就存在了好多投影方法,比如高斯投影、墨卡托投影等。

地心坐标系(geocentric coordinate system)

地球质心(总椭球的几何中心)为原点的大地坐标系, 可分为:

  • 以地球质心为原点建立的空间直角坐标系
  • 以球心与地球质心重合的地球椭球面为基准面所建立的大地坐标系

地理坐标系(Geographic Coordinate System)

1
2
3
4
5
6
7
使用三维球面来定义地球表面位置,以实现通过经纬度对地球表面点位引用的坐标系;
一个地理坐标系包括角度测量单位、本初子午线和参考椭球体三部分.

地理坐标系可以确定地球上任何一点的位置。首先将地球抽象成一个规则的逼近原始自然地球表面的椭球体,
称为参考椭球体,然后在参考椭球体上定义一系列的经线和纬线构成经纬网,从而达到通过经纬度来描述地表
点位的目的。需要说明的是经纬地理坐标系不是平面坐标系,因为度不是标准的长度单位,不可用其直接量测
面积长度。

经纬度

常用的经度和纬度是从地心到地球表面上某点的测量角。通常以度或百分度为单位来测量该角度

  1. 天文经纬度
  2. 大地经纬度
  3. 地心经纬度

参心坐标系

原点与某一地区或国家所采用的参考椭球中心重合,通常与地球质心不重合

  • 西安80, 北京54, wgs84等等

WGS84, 西安西安80, 北京北京54

1
2
3
4
5
首先有WGS84/北京54/西安80大地坐标系,是用经纬度表示的,也有WGS84/北京54/西安80平面坐标系,使用xy表示的。
WGS84的椭球采用国际大地测量与地球物理联合会第17届大会测量常数推荐值;
北京54采用的是克拉索夫斯基椭球;
西安80采用的是1975国际椭球;
所以地球表面上一点的这三者大地坐标是不一样的,即经纬度是不一样的。

投影坐标、地理坐标、垂直坐标

地图投影的方式

  1. 等角投影 - 投影前后的角度相等, 但长度和面积变形
  2. 等距投影 - 投影前后的长度相等, 但角度和面积变形
  3. 等积投影 - 投影前后的面积相等, 但角度和长度变形

投影坐标

1
2
3
4
5
6
7
8
9
10
11
12
    投影坐标系在二维平面中进行定义。与地理坐标系不同,在二维空间范围内,投影坐标系的长度、角度和面积恒定。
投影坐标系始终基于地理坐标系,而后者则是基于球体或旋转椭球体的。

在投影坐标系中,通过格网上的 x,y 坐标来标识位置,其原点位于格网中心。每个位置均具有两个值,这两个值是
相对于该中心位置的坐标。一个指定其水平位置,另一个指定其垂直位置。这两个值称为 x 坐标和 y 坐标。采用此标记
法,原点坐标是 x = 0 和 y = 0。

在等间隔水平线和垂直线的格网化网络中,中央水平线称为 x 轴,而中央垂直线称为 y 轴。在 x 和 y 的整个范围内,
单位保持不变且间隔相等。原点上方的水平线和原点右侧的垂直线具有正值;下方或左侧的线具有负值。四个象限分别表示
正负 X 坐标和 Y 坐标的四种可能组合。

在地理坐标系中处理数据时,有时用 X 轴表示经度值并用 Y 轴表示纬度值很有用。

地理坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    地理坐标系 (GCS) 使用三维球面来定义地球上的位置。GCS 往往被误称为基准面,而基准面仅是 GCS 的一部分。GCS
包括角度测量单位、本初子午线和基准面(基于旋转椭球体)。
可通过其经度和纬度值对点进行引用。经度和纬度是从地心到地球表面上某点的测量角。通常以度或百分度为单位来测量
该角度。下图将地球显示为具有经度和纬度值的地球。
在球面系统中,水平线(或东西线)是等纬度线或纬线。垂直线(或南北线)是等经度线或经线。这些线包络着地球,构成了
一个称为经纬网的格网化网络。
位于两极点中间的纬线称为赤道。它定义的是零纬度线。零经度线称为本初子午线。对于绝大多数地理坐标系,本初子午
线是指通过英国格林尼治的经线。其他国家/地区使用通过伯尔尼、波哥大和巴黎的经线作为本初子午线。经纬网的原点 (0,0)
定义在赤道和本初子午线的交点处。这样,地球就被分为了四个地理象限,它们均基于与原点所成的罗盘方位角。南和北分别位
于赤道的下方和上方,而西和东分别位于本初子午线的左侧和右侧。
通常,经度和纬度值以十进制度为单位或以度、分和秒 (DMS) 为单位进行测量。维度值相对于赤道进行测量,其范围是
-90°(南极点)到 +90°(北极点)。经度值相对于本初子午线进行测量。其范围是 -180°(向西行进时)到 180°(向东行进时)。如
果本初子午线是格林尼治子午线,则对于位于赤道南部和格林尼治东部的澳大利亚,其经度为正值,纬度为负值。
用 X 表示经度值并用 Y 表示纬度值可能会有帮助。这样,显示在地理坐标系上定义的数据就如同度是线性测量单位一样。
此方法与普通圆柱投影基本相同。
尽管使用经度和纬度可在地球表面上定位确切位置,但二者的测量单位是不同的。只有在赤道上,一经度所表示的距离才约
等于一纬度所表示的距离。这是因为,赤道是唯一一条长度与经线相同的纬线。(其半径与球面地球半径相同的圆称为大圆。赤道
和所有经线都是大圆。)
在赤道上方和下方,用来定义纬度线的圆将逐渐变小,直到最终在南极点和北极点处变为一个点,所有经线均在此处相交。
由于经线沿极点方向逐渐集中,所以一经度所表示的距离最终将减小为零。在 Clarke 1866 旋转椭圆体上,赤道上的一经度等于
111.321 km,而在纬度为 60° 度位置,只有 55.802 km。因为经度和纬度不具有标准长度,所以无法对距离或面积进行精确测
量,或者无法很容易地在平面地图或计算机屏幕上显示数据。

垂直坐标

1
2
3
4
5
6
7
    垂直坐标系可以定义高度或深度值的原点。与水平坐标系类似,除非要显示数据集或者要将数据集与使用不同垂直坐标系的其
他数据合并,否则不需要使用垂直坐标系中的大多数信息。
测量单位可能是垂直坐标系最重要的部分。测量单位始终是线性的(例如,国际英尺或米)。另一个重要部分是 z 值究竟代表
高度(高程)还是深度。对于每种类型,z 轴方向分别为正“北”或正“南”。下图显示了两种垂直坐标系:平均海平面和平均低潮面。
平均海平面用作高度值的零水平面。平均低潮面则是基于深度的垂直坐标系。
基于高度的平均海平面坐标系显示一个 z 值。落到平均海平线以下且以其为参照的任何点都具有负 z 值。平均低潮面具有
两个与之关联的 z 值。由于平均低潮面是基于深度的,因此 z 值为正。落到平均低潮面以上且以其为参照的任何点都具有负z值.

坐标转换

  1. 在同一个椭球里的转换都是严密的,而在不同的椭球之间的转换是不严密的。

    1
    如,在WGS-84坐标和北京54坐标之间是不存在一套转换参数可以全国通用的,在每个地方会不一样,因为它们是两个不同的椭球基准
  2. 两个椭球间的坐标转换:

    1
    2
    3
    4
    5
    6
    一般而言比较严密的是用七参数法(包括布尔莎模型,一步法模型,海尔曼特等):
    即X平移,Y平移,Z平移,X旋转,Y旋转,Z旋转,尺度变化K。

    要求得七参数就需要在一个地区需要3个以上的已知点。如果区域范围不大,最远点间的距离不大于30Km(经验值),
    这可以用三参数(莫洛登斯基模型),即X平移,Y平移,Z平移,而将X旋转,Y旋转,Z旋转,尺度变化K视为0,所
    以三参数只是七参数的一种特例。
  3. 在一个椭球的不同坐标系中转换可能会用到平面转换

    1
    2
    现阶段一般分为四参数和平面网格拟合两种方法,以四参数法在国内用的较多,举个例子:
    在深圳既有北京54坐标又有深圳坐标,在这两种坐标之间转换就用到四参数,计算四参数需要两个已知点。
  4. 一个示意图

Proj4库的一个转换关系

常用计算

六度带

中央经线 = 6 * 当地带号 - 3 (使用于1:2.5万 和 1:5万)

三度带

中央经线 = 3 * 当地带号

常用投影

UTM投影

Untitled

Posted on 2017-06-19

ʲô�Ǵأ�
�����ʼ��WIN98һֱ��WIN XP�����ǻ�еӲ�̵����£��������ޡ����Ҿ��������еӲ��Ĭ����������512K��С��������ʱ����һ���������������洢��Ԫ���׳ƴء�������ʱ�����ָ�������С������ز���Ӳ�̵������ṹ������ʹ�÷�����
��������غ�����˼��һ����ֻ������һ���ļ�������һ���ؿ��԰��������������ʱ����С�أ���ΪС�ز����˷ѡ����̡� ����ȷ��������ҵĴ���10K���ļ���25K������Ҫ��������ļ���Ҫռ��3����;���������5K����ô���뱣������ݣ���Ҫʹ��5������������Ԫ���Եô��������ʸ��ߡ�
��������ô�������Dz��Ǵ�ԽСԽ����?����!��Ϊһ������һ��������С�Ĺ����洢��Ԫ�����һ���ļ�����4����Ԫ��400����Ԫ��������ĸ�������? ����Ŀǰ������Ӳ���Ѿ����ں��Ǽ�K�ˣ����������û��Ҫ̫С��

�غ�������ʲô����

�����غ�������������һ�����롣����ϵͳ��Ӳ���϶�д�ļ�ʱ�ĵ�λ����һ�����ݿ顣��������Ӳ�̻��ֵ���С��λֵ�����Ǵأ����ݿ飩ռ�õĵط���

�����صĴ�С���������Ĵ�С��Ӳ��ÿ�ص���������Ӳ�̵���������С�йء������Ǵ洢�����Ͽ���Ӳ��Ѱַ�Ļ�����λ��x86ϵͳ�������Ƕ���512�ֽڵ�������С�����������ļ�ϵͳ��ʽʹ�õĿ�Ѱַ���ݿ飬�صĴ�С����������С�����������Ҳ�ͬ�ļ�ϵͳ���ڲ�ͬ��С�ľ������������в�ͬ��Ĭ�ϴش�С������FAT32����8GB���µķ�����Ĭ�ϴش�СΪ4KB������8GB��16GB�ķ�����Ĭ�ϴش�СΪ16��������8KB����NTFS���ڴ���2GB�ķ�����Ĭ�ϴش�СΪ8��������4KB����

��������ȷ����㣨ϵͳ��Ҫ�ڲֿ⣨�ֿ����ΪӲ�̣�����һЩ�飨���ݣ������Ȱ�����ű���ŵ�һЩ��ֽ�䣨�أ��Ȼ��Ž��ֿ⣬ֽ�������Ǹ�����ֿ��С�������ģ����ֿ�ʼ�ջ��ֳɵ�λΪ0.1m?��С���ӣ����������ֿ���ˣ�ֽ��ʹ�Щ���ֿ�С�ˣ�ֽ���СЩ��

�洢����˵�Ŀ顢ҳ���ء�������Ӧ�Ĺ�ϵ��ʲô��

�����򵥵�˵�����ǿ���԰�������ҳ��ҳ���԰������ɴأ��ؿ��԰�������������������ɡ�һ���Ƕ��ķ��Ρ����磺һ�ص���128������һҳ����64�أ�һ�����4ҳ����ôһ��͵���4x64x128������

ʲô��4K?

������������Ļ�еӲ��Ĭ����512�ֽڵ����������õ���DRAM��Ϊ�洢����; ����еӲ�̣�������SLC��������MLC������������NAND����洢��Ԫ�� ����Ӳ�̵�������4K�������4K������!

��������win98��win xp���������FAT��ʽ�� ���ָ�ʽ�߱�32λ��16λ���̸�ʽ�໥�������Ա���������Ѳ�����Ϊϵͳ�̡� ���ǵ���Vistaʱ�����Ѿ�����Ҫ16λ��DOS�ˣ�����ȫ�������˴�32λ��NTFS��ʽ��NTFS��ʽҲ�������˵������ ��ʵXPʱ������NTFS����Ȼ���ָ�ʽ���ܸ��߸���ȫ�����Ǽ����Բ����һֱ����Ϊϵͳ������һ����Ϊ�洢������

����NTFS��ʽ��һ�����ԣ��Ǿ�����ʼ�ص�λ��!

����NTFS������ʼλ�ò��Ǵ�0��ʼ�����Ǵ�LBA63��ʼ�����ǵ���ʮ����������ʼ��ʼ�洢��

��������NFTSĬ����Ϊ������512�ֽڴ�С�����������ܵ��ڵ�����ʮ����������

����������������ˣ�63��������512�ֽ�=31.5K��Ҳ����˵�����̵�ǰ31.5K�Dz��ܱ�ʹ�õġ�

����ʹ�û�еӲ�̾����ˣ�ʹ�ù�̬Ӳ�̣��洢��һ���֣�Ҳ��Ҫռ��31.5K-35.5K֮��Ĵ���������

��������ֵ���������������ȥ��ǡ��ÿ��һ��������4Kλ�ã��ͻ����һ�����ݴ�2�������������

���������������У�ֻҪ�����Ǹ��ܱ�4K������λ�þ�100%ռ����2������������ֻдһ���֡�

������̬Ӳ��������MLC����SLC��������д���ȡ�����ģ�������������������ܺ������� ���ң������˶�ȡ������ ���ʱ�����۴��Ƕ�󣬶���������ܺͿռ���˷ѡ�

���������������ͽ���4K!

ʲô��4K���룿����

����Ӳ�̷�����ʱ����һ���������������洢��Ԫ���׳ƴء�������ʱ�����ָ�������С������ز���Ӳ�̵������ṹ������ʹ�÷���������ʱ����չ��Ӳ������������չ��ʹ��֮ǰ�����ÿ������512�ֽڲ�������ô�ĺ��������ǽ�ÿ������512�ֽڸ�Ϊÿ������4096 ���ֽڣ�Ҳ�������ڳ�˵�ġ�4K������������NTFS��Ϊ�˱�׼��Ӳ���ļ�ϵͳ�����ļ�ϵͳ��Ĭ�Ϸ��䵥Ԫ��С���أ�Ҳ��4096�ֽڣ�Ϊ��ʹ�����������Ӧ����ʹ����Ӳ�̷���������ʹ�õ��߼��������룬��֤Ӳ�̶�дЧ�ʣ����ԣ����ˡ�4K���롱�ĸ��������ͳӲ�̵�ÿ�������̶���512�ֽڣ��±�׼��”4K����”��Ӳ�̣�Ӳ�̳���Ϊ�˱�֤�����ϵͳ�����ԣ�Ҳ������ģ���512B��������ʱ�ͻ���4K������4K�ز������������������Ծ�Ҫ�á�4K����ķ�ʽ����Ӳ��ģ����������ɡ�4k����������4K���롱���ǽ�Ӳ���������뵽8����������ģ����������512B*8=4096B��4096�ֽڼ���4K������ֻҪ��8�ı�������4K������

Vim使用过程中收集的一些东西

Posted on 2017-05-31

删除空行

1
:g/^\s*$/d

删除/与/形式的注释

1
:%s/\/\*\(.*\n\)\{-}.\{-}\*\///g

##

sqlite3测试代码

Posted on 2017-05-26

c++ 测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#define LOGD printf
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
for (int i = 0; i < argc; ++i) {
LOGD("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
return 0;
}

int testsqlite() {
// 数据库版本
const char* version = sqlite3_libversion();
LOGD("sqlite version: %s", version);

sqlite3 *db;
char *errMsg;
int rv = 0;
// 打开数据库, 如果数据库不存在的话, 则创建
const char* filename = "test.db";
rv = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
if (rv) {
LOGD("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}

// 创建表
char create_table[100] = "CREATE TABLE IF NOT EXISTS customers (id INTEGER PRIMARY KEY,name TEXT NOT NULL)";
rv = sqlite3_exec(db, create_table, callback, 0, &errMsg);
if (rv != SQLITE_OK) {
LOGD("SQLite statement execution error: %s", errMsg);
}

// 插入数据
char insert_value[100] = "INSERT INTO customers VALUES('1', 'roman10')";
rv = sqlite3_exec(db, insert_value, callback, 0, &errMsg);
if (rv != SQLITE_OK) {
LOGD("SQLite statement execution error: %s", errMsg);
}

// 修改数据 : update company set address='gansu', salary=33333;
char change_value[100] = "UPDATE customers SET name=\"newname\" WHERE id=1";
rv = sqlite3_exec(db, change_value, callback, 0, &errMsg);
if (rv != SQLITE_OK) {
LOGD("SQLite statement execution error: %s", errMsg);
}

// 查询数据
{
const char *query = "SELECT ID, NAME FROM customers ORDER BY ROW;";
sqlite3_stmt *statement;
rv = sqlite3_prepare(db, query, -1, &statement, NULL);
if (rv != SQLITE_OK) {
LOGD("SQLite statement execution error: %s", errMsg);
sqlite3_close(db);
return 0;
}

int count = sqlite3_column_count(statement);
LOGD("列大小为: %d", count);
while (sqlite3_step(statement) == SQLITE_ROW) {
// 第一列的数据: id
int rowNum = sqlite3_column_int(statement, 0);
// 第二列的数据: name
char *rowData = (char *)sqlite3_column_text(statement, 1);

LOGD("第%d行数据: %d - %s", rowNum, rowData);
}
sqlite3_finalize(statement);
}

sqlite3_close(db);
return 0;
}

Untitled

Posted on 2017-05-23

GDAL 库是一个跨平台的栅格地理数据格式库,包括读取、写入、转换、处理各种栅格数据格式(有些特定的格式对一些操作如写入等不支持)。它使用了一个单一的抽象数据模型就支持了大多数的栅格数据。这里有 GDAL 库支持的格式:http://www.gdal.org/formats_list.html

  1. 获取图像的基本信息

采用 GDAL 读取图像成功后,可以获取图像的一些基本信息,如下:

描述信息:const char* GDALDataset::GetDriver()->GetDescription(),通常是图像的格式

  1. 图像大小
    图像宽度 int GDALDataset::GetRasterXSize()
    图像高度 int GDALDataset::GetRasterYSize()

  2. 波段数:int GDALDataset::GetRasterCount()
    波段数即图像每个像素点所含的颜色种类,物理中的光学中学过颜色就是某频率的光波
    波段少则一个,多则很多个,在遥感影象中波段通常有多个。

  3. 投影信息:GDALDataset::GetProjectionRef()
    有的图像没有投影信息,不如一般的 JPG、BMP 格式图像。

  4. 地理坐标信息:double adfGeoTransform[6]
    GDALDataset::GetGeoTransform(adfGeoTransform)

地理坐标信息是一个含 6 个 double 型数据的数组,adfGeoTransform[1] 和 adfGeoTransform[5] 表示东西和南北方向一个像素对应的距离,adfGeoTransform[0] 和 adfGeoTransform[3] 表示左上角的坐标。

  1. 波段信息:数据集中重要的信息,有波段尺寸、数据类型、颜色信息等。
    获取波段的方法: GDALRasterBand *poBand;

poBand = poDataset->GetRasterBand(i) poBand 为指向第 i 个波段的指针

波段尺寸:int poBand->GetXSize()

int   poBand->GetYSize()

数据类型:const char* GDALGetDataTypeName(poBand->GetRasterDataType())

颜色信息:const char* GDALGetColorInterpretationName(poBand->GetColorInterpretation())

tinyxml2使用的记录

Posted on 2017-04-04

类结构

XMLNode指的是所有被<…>…</…>包括的内容, 具体有声明, 注释, 节点及节点间的文本.
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
0. 整个文档为XMLDocument
1. 下面为XMLDeclaration
<?xml version="1.0" encoding="UTF-8"?>
2. 一个<phonebook>...</phonebook>是一个XMLElement
<phonebook>
3. XMLComment
<!--one item behalfs one contacted person.-->
4. 一个<item>是一个XMLElement;
5. item中的name="1"是一个XMLAttribute
<item name="1">
5. item中的<name>也是一个XMLElement
6. <name>与</name>之间的是一个XMLText
<name>miaomaio</name>
<addr>Shaanxi Xi'an</addr>
<tel>13759911917</tel>
<email>miaomiao@home.com</email>
</item>
<item name="2">
<name>gougou</name>
<addr>Liaoning Shenyang</addr>
<tel>15840330481</tel>
<email>gougou@home.com</email>
</item>
3. 下面为XMLComment
<!--more contacted persons.-->
</phonebook>

写的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool writexmlfile() {
try {
XMLDocument* xmldoc = new XMLDocument();

// 设置文件声明
const char* decla = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
XMLDeclaration* declarations = xmldoc->NewDeclaration(decla);
xmldoc->LinkEndChild(declarations);
// 创建根元素
XMLElement* rootele = xmldoc->NewElement("phonebook");
// 链接作为根对象
xmldoc->LinkEndChild(rootele);

// 创建一个元素
XMLElement* item1 = xmldoc->NewElement("item");
// 链接到根元素就成为根元素的第一个项
rootele->LinkEndChild(item1);
// 为第一个项设置属性
item1->SetAttribute("name", "1");
// 为item1设置俩个元素
XMLElement* name1 = xmldoc->NewElement("name");
XMLElement* tel1 = xmldoc->NewElement("tel");
item1->LinkEndChild(name1);
item1->LinkEndChild(tel1);
// 为元素设置
name1->SetText("Ding");
tel1->SetText("111111");

// 保存文件
xmldoc->SaveFile("write.xml");
} catch (...) {
return false;
}

return true;
}

读的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
bool readxmlfile() {
try {
XMLDocument* xmldoc = new XMLDocument();
xmldoc->LoadFile("write.xml");

// 读声明

// root
XMLElement* root = xmldoc->RootElement();
// item1
XMLElement* item1 = root->FirstChildElement();
XMLElement* name1 = item1->FirstChildElement();
XMLElement* tel1 = name1->NextSiblingElement();
// 得到item1的attribute属性值
const char* item1name = item1->Attribute("name");
std::cout << "item1属性值:" << item1name << std::endl;
// 得到name1和tel1的XMLText值
const char* name1val = name1->GetText();
const char* tel1val = tel1->GetText();
std::cout << "name项的值为:" << name1val << std::endl;
std::cout << "tel项的值为: " << tel1val << std::endl;

// item2
// XMLElement* item2 = item1->NextSiblingElement("item");
//
delete xmldoc;
} catch (...) {
return false;
}

return true;
}

编码转换

Posted on 2017-03-23

检测文件编码

1
$file filename

利用 iconv 进行编码转换

$iconv [选项] [文件]

选项可以通过:$iconv --help获取.

例子(从utf-8 -> gbk2312):
$iconv -f utf-8 -f gbk2312 a.txt > b.txt

使用 convmv 转换

1
$convmv -f GBK -t UTF-8 *.txt

使用 enca 转换

  1. 查看文件编码
    $enca -L zh_CN a.txt

  2. 编码转换

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $enca -L 当前语言 -x 目标编码 文件名

    # 例如要把当前目录下的所有文件都转成 utf-8
    $enca -L zh_CN -x utf-8 *

    # 检查文件的编码
    $enca -L zh_CN file

    # 将文件编码转换为 "UTF-8" 编码
    $enca -L zh_CN -x UTF-8 file

    # 如果不想覆盖原文件可以这样,很简单吧。
    $enca -L zh_CN -x UTF-8 <file1> file2

<> 读书笔记之第一章 习惯c++

Posted on 2017-03-21

条款01: 视c++为一个语言联邦

组成c++ 的是个部分

  1. C : c++以C为基础;
  2. Objecet-Oriented C++ : classes(构造函数与析构函数), 封装(encapsulation), 继承(inheritance),
    多态(polymorphism), virtual 函数(动态绑定);
  3. Template C++: C++的泛型编程(generic programming) 部分;
  4. STL : Template程序库;

条款02: 尽量以const, enum, inline 替换 #define

<> 读书笔记之第二章 构造/析构/赋值运算

Posted on 2017-03-21

条款5: c++默默编写并调用那些函数

  1. 对于一个空类, 编译器默认会生成default构造函数,析构函数,copy构造函数,copy assignment操作符,
    并且这些都是public且inline的;
  2. 只有当这些函数被需要(即代码中有调用)时才会生成;

    1
    2
    3
    4
    5
    6
    7
    class Empty{
    public:
    Empty() {} // 如果类里面已经自定义了一个构造函数, 则编译器不会生成此构造函数
    Empty(const Empty& rhs) {...} // 单纯的将每一个non-static变量拷贝到目标对象
    ~Empty() {} // 析构函数, 编译器默认的创建的是non-virtual,除非有子类, 并且子类的析构函数是virtual的
    Empty& operator=(const Empty& rhs) {...} // 同copy构造函数
    };
  3. 如果一个类内含reference变量 或 内含const变量,编译器默认生成的copy构造函数和copy assignment操作符
    将不知所措, 所以此时应该自己实现;

  4. 如果base class将copy assignment操作符声明为private, 编译器将拒绝为derived class 生成一个copy
    assignment 操作符, 由于子类无权调用子类的函数, 编译器无能为力, 所以就….

条款6: 若不想使用编译器自动生成的版本,就明确拒绝

  1. 将copy 构造函数 和 copy assignment操作符声明为private且不予实现;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class HomeForSale{
    public:
    ...
    private:
    HomeForSale(const HomeForSale&);
    HomeForSale& operator=(const HomeForSale&);
    };
    // 定义上述代码后, 当客户企图拷贝时, 编译器会阻挠;
    // 但是你不慎在member函数或friend函数之内调,链接器可能会抱怨.
  2. 对于想杜绝在member函数或friend函数内调用的情况,可以声明如下类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class Uncopyable {
    protected:
    Uncopyable() {}
    ~Uncopyable() {}
    private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
    };
    // 然后在需要阻止的时候继承此类就可以了
    class HomeForSale: private Uncopyable {
    ...
    };
    // 由于在编译器生成版的函数中会尝试调用子类的接口, 但是他们是private
    // 的, 所以就会被编译器拒绝而导致编译错误.

条款7: 为多态基类声明virtual析构函数

  1. c++明确指出,当derived class 对象经由一个base class指针被删除, 而该base
    class带有一个non-virtual析构函数时, 其结果是未定义的, 其通常结果是对象
    的derived成分没有被销毁;
  2. 如果一个class不企图被当做一个bas class, 令其析构函数为virtual往往是一个
    馊主意; 由于声明虚函数需要占用额外空间(vptr);
  3. 只有当class内含至少一个virtual函数,才为它声明virtual析构函数;
  4. 标准的string不含任何virtual函数;
  5. 在你需要一个pure class, 但是你又没有pure virtual 函数, 你可以声明一个pure virtual析构函数,
    并且提供定义, 因为编译器会在AWOW的子类的析构函数中创建一个对~AWOW的调用动作, 如果不定义,
    链接器会报错;
    1
    2
    3
    4
    5
    class AWOW{
    public:
    virtual ~AWOW()=0;
    };
    AWOW::~AWOW(){}

条款8: 别让异常逃离析构函数

  1. c++标准不禁止析构函数抛出异常, 但是不鼓励;
  2. 析构函数应该捕捉任何异常, 然后处理掉或结束程序;
  3. 如果客户需要对某个操作函数运行期间抛出的异常作反应, 应该用一个普通函数, 而不是在析构函数中.

条款9: 绝不在构造函数和析构函数中调用 virtual函数

如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Transaction{
public:
Transaction() { logTransaction(); }
virtual void logTransaction() const=0; // 做出一份因类型不同而不同的日志记录
};
class BugTransaction: public Transaction{
public:
virtual void logTransaction() const;
};
class SellTransaction: public Transaction {
public:
virtual void logTransaction() const;
};

  1. 当derived class构造函数被调用时, base class一定会更早被调用; 而 derived
    class构造函数调用virtual函数时, 调用的是base class版本; 在base class
    构造期间virtual函数绝不会下降到derived class阶层;
  2. 当 derived class 析构函数开始执行, 对象内的 derived class 成员变量便呈现未定义值,
    所以c++视他们仿佛不存在. 进入 base class 析构函数对象就成为一个 base class 对象;
  3. 解决的办法: 将 logTransaction 改为 non-virtual, 然后要求derived class 构造函数传递必要信息给
    Transaction 构造函数, 如下:
    1
    2
    3
    4
    5
    class Transaction {
    public:
    explicit Transaction(const std::string& logInfo);
    void logTransaction(const std::string& logInfo) const;
    }

条款10: 令 operator= 返回一个 reference to *this

1
2
3
4
int x, y, z;
x = y = z = 15; // 赋值连锁形式
// 由于赋值采用右结合律, 上面被解析为:
x = (y = (z = 15));

为了实现”连锁赋值”, 赋值操作符必须返回一个 reference 直线操作符的左侧实参, 如下:

1
2
3
4
Widget& operator=(const Widget& rhs) {
...
return (*this);
}

同样适用于+=, -=, *=等等.

条款11: 在operator= 中处理 “自我赋值”

  1. 最初版的opeator=:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Bitmap {
...
};
class Widget{
...
private:
Bitmap* pb;
};
Widget& Widget::operator=(const Widget& rhs) {
delete pb;
pb = new Bitmap(*rhs.pb);
return (*this);
}
// 缺乏自我赋值安全性
  1. 如果rhs 和 this 是同一个对象的话, delete 则会产生错误; 针对这种情况应该添加证同测试:
1
2
3
4
5
6
7
8
Widget& Widget::opeator=(const Widget& rhs) {
if (this == &rhs) return *this;

delete pb;
pb = new Bitmap(*rhs.pb);
return *this;
}
// 缺乏异常安全性
  1. 上述虽然实现了自我赋值安全性, 但是缺乏异常安全性, 如果delete pb后, new失败后, 岂不是this
    的pb指向了一个无效指针, 我们应该在赋值pb所指东西之前别删除pb:

    1
    2
    3
    4
    5
    6
    7
    Widget& Widget::opeator=(const Widget& rhs) {
    // if (this == &rhs) return *this; // 不是绝对必要, 但是关心效率的话可以加上
    Bitmap* temp = pb;
    pb = new Bitmap(*rhs.pb);
    delete temp;
    return *this;
    }
  2. 替代方案: copy and swap 技术:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Widget{
    void swap(Widget& rhs); // 交换数据
    };

    Widget& Widget::opeator=(const Widget& rhs) {
    Widget temp(rhs);
    swap(temp);
    return (*this);
    }

note:1. 确保当对象自我赋值时, operator =仍然行为良好; 2. 确定任何函数操作多个对象时,
并且其中多个对象是同一个对象时, 其行为仍然正确.

条款12: 复制对象时勿忘每一个成分

设计良好的面向对象系统(OO-System)会将对象的内部封装起来,只留俩个函数负责对象拷贝(复制),
那便是copy构造函数和copy assignment操作符, 称之为copying函数.
note:

  1. copying 函数应该确保复制”对象内的所有成员变量” 及 “所有base class 成分”
  2. 不要尝试以某个copying 函数实现另一个copying 函数. 应该将共同机能放进第三个函数中,
    并由两个coping 函数共同调用.

c++ 数据的存储位置

Posted on 2017-03-07

c++主要的内存区域

  1. 常量存储区(Const Data);
  2. 栈(Stack);
  3. 自由存储区(Free Store);
  4. 堆(Heap);
  5. 全局/静态存储区(Global/Static);

常量存储区(Const Data)

  1. 常量存储区保存字符串常量和其他在编译期可以确定值的数据;
  2. 类对象是不能存储在这个区间的;
  3. 这个区的数据在程序运行期间都是可以使用的;
  4. 这个区的数据是只读的, 针对此区数据的修改行为是行不通的;
  5. ??

栈(Stack)

  1. 栈存储自动变量, 分配速度快于动态存储区(堆和自由存储区);
  2. 空间分配紧紧涉及到栈顶指针的增加, 而不需要复杂的管理;
  3. 对象在分配内存后直接构造, 内存回收后直接销毁, 所以除了
    未初始化的栈空间外, 程序员没有直接管理内存的机会(除非
    使用有意篡改的new和显式析构函数);

自由存储区

  1. 俩大动态内存区域之一, 通过 new 分配, delete 释放;
  2. 通过new/delete动态分配和释放对象的抽象概念;
  3. 和堆有区别, 并非等价;

堆(Heap)

  1. 俩大动态内存区域之一, 通过 malloc/free(或其他变体)分配/释放;
  2. 由操作系统维护;
  3. 在没有明确说明 new/delete 用 malloc/free 实现的编译器中, 堆和自由
    存储区是不同的;
  4. ??

全局/静态存储区

  1. 程序启动是已经分配好存储空间, 但是初始化可能在程序执行时进行;
  2. ??

参考

Memeory Management - Part1

123…6

DaSea

Fucking Code!

51 posts
25 tags
GitHub
© 2018 DaSea
Powered by Hexo v3.7.1
|
Theme — NexT.Gemini v6.3.0