Resive world

Come world to Record life


  • Home

  • Tags

  • Categories

  • Archives

  • Sitemap

  • Search

js高级与面向对象之函数

Posted on 2016-07-22 | In javascript

函数声明

1
2
3
4
5
6
7
8
9
function func(){
//函数体
}
//2.函数表达式
var func1 = function(){

}
//3.通过Function构造函数来创建
var func2 = new Function();
Read more »

Django框架基础

Posted on 2016-07-10 | In Web

Django框架大概是python web框架中最有名的一个了,由于学习需要得用python搞个网页出来,那就学学这个喽。

入门级的介绍我是参考自强学堂的简单教程,总的来说讲的还是蛮清楚的。

下面简单记录下搭建过程,其实也是非常容易上手。

安装

当然可以去django官网下载源码直接$sudo pip install Django,而且版本也比较新。

相比下源码直接用来说,用pip安装能自动的把常用的命令对应的放在/usr/local/bin/等里面而不是扎堆放在一起,因此非常方便随处使用。

安装完成后在python命令行里输入

1
2
3
>>> import django
>>> django.VERSION
(1, 9, 7, 'final', 0)

即可查询当前版本了,这个还是要十分清楚的,因为1.7、1.8、1.9各个版本的使用差别还是很大的。

文件结构

django工程首先用django-admin.py startproject project-name来创建,这会生成一个项目文件夹。然后进入文件夹,输入python manage.py startapp app-name命令来生成一个应用。不过新建的app要手动在项目文件里注册,即在Test/Test/settings.py里的INSTALLED_APPS的字典里加上’app-name’字段来帮助项目找到属于他的应用。

文件树大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Test/
├── manage.py
├── MyApp
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── views.py
└── Test
├── __init__.py
├── settings.py
├── urls.py
├── wsgi.py

大的Test文件就是整个项目,MyApp就是一个项目(网站),小的Test就是项目的配置文件,包括项目的基本配置(setting.py),以及url映射文件(urls.py)。

HelloWorld

下面就显示一个HelloWorld。

既然要显示网页,就肯定得有url到文件的映射,这个就是由项目里的urls.py文件设置:

1
2
3
4
5
6
7
8
9
#coding:urf-8
from django.conf.urls import url
from django.contrib import admin
from MyApp import views as MyAppViews # 添加

urlpatterns = [
url(r'^$', MyAppViews.index), # 添加
url(r'^admin/', admin.site.urls),
]

首先得导入项目的views,然后用正则来匹配网页,r’^$’很明显就是匹配根目录。而MyAppViews.index就是对应调用的函数,这个函数就写在app/views.py下:

1
2
3
4
5
#coding:utf-8
from django.http import HttpResponse

def index(request):
return HttpResponse(u"HelloWorld")

很好理解,就是直接打印。

最后启动服务,在项目根目录下输入

1
python manage.py runserver 8000

当然,端口号8000可以省略或者指定其他的端口。

这样就能在本地访问8000端口的http服务了。
理论上,这点东西就足以搞搞静态页面了,不过事实上,他的功能更加强大。

js高级与面向对象之原型链

Posted on 2016-07-09 | In javascript

原型链是什么?

只要是对象就会有原型,那么所有的原型就会形成一个链式的结构,这个结构就称为原型链

Read more »

Git版本控制入门

Posted on 2016-07-06 | In Others

最近看了很多大牛的博客,感觉在迷迷糊糊的考试周里突然又有了学习的动力,不知不觉对工程也有了兴趣。以前总是怀疑我是不是不应该学软件工程而是该学计算机科学,现在想想但是还真是naive。虽然身边的那些师兄、同学都说搞工程什么的特别low(感觉我以前内心深处也是这么想的0.0),但是仔细看了看他们自己似乎也没有什么特别大的成果。我总觉得肚子里越是没有干货的人就越是喜欢对自己稍微了解的领域评头论足。当然,说实话我对Software Engineering这个行当也不是很了解,而且感觉同专业里大多数人了解的应该不会比我多多少,但是这并不是止步不前的借口。且不说知乎上那些大一就能够经济独立的同学,或者是已经工作了的博主,就是身边也有很多取得出色成就的牛人。马上大三了,还有很多路要走。真正搞代码的人虽说从骨子里都有种傲气,但是我们也都清楚真正的力量和自己的藐小。总觉得乔帮主对干咱们这个行当的人总结的特别好,stay hungry,stay foolish.

屁话撸多了,言归正传,既然要搞工程,首先肯定得会搬砖。所谓搬砖嘛,也就是把建筑材料拼拼补补,一点一点的堆起来,最后弄成个小房子。这件事本身其实没有什么问题,一个小房子自己搞搞也能弄完,出了问题也没人推,自己的设计自己也清楚。但是如果是盖大房子呢,这肯定就不能是一个人就能搞定的了,得有很多人一起弄,那么这就有些麻烦了。搞不好就是你碰了我的砖,我动了你的砖,出了问题我也可以说这块砖不是我搬的等等很麻烦。这就引出了版本控制的重要性,现在几乎所有的项目都是用版本控制和仓储工具的,存在的意义也没什么好争辩的了。在这当中我想最出名的就是Github了,不过Github也只是git版本控制的一个仓储平台,类似的平台还有很多,比如oschina里的git(吐槽下github的网络不稳定,感觉oschina才是比较实用的东西。。。),最终用的是git版本控制方法。而git也只是各种版本控制和仓储工具的一种,还有很多类似SVN、CVS等,不过git应该算是最流行的了。

对于git的安装、使用和它的优点以及细节,Pro Git这本书已经写的非常好了,可以作为教程学习(比那些上来就写命令的菜鸟教程好多了)。这个书的来源也十分值得研究https://github.com/progit/progit,搭建这个阅读环境的方法也十分漂亮。

具体的操作也就不提了,书上写的已经是非常好了,有问题直接查阅。

好动校园理论考试破解(2/2)

Posted on 2016-06-25 | In Web

现在已经分析清楚了,就这么点玩意,照着之前分析出来的接口用python写个小脚本就行了。

hack.py

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
#coding:utf-8
import urllib2,cookielib,urllib,json,sys,time

login_system_url="http://appsrv.ihodoo.com/login"
login_exam_url="http://appsrv.ihodoo.com/auth/exam/enterIndex?"
get_paper_url="http://appsrv.ihodoo.com/auth/exam/start/"
solve_question_url="http://appsrv.ihodoo.com/auth/exam/select/"
submit_paper_url="http://appsrv.ihodoo.com/auth/exam/submit/"
data={}
cj=cookielib.CookieJar()
opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders=[('User-agent','Mozilla/5.0 (Linux; U; Android 2.3.7; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1')]
urllib2.install_opener(opener)

def login_system(username,password):
request=urllib2.urlopen(login_system_url,urllib.urlencode({"username":username,"password":password}))
content=request.read()
response=json.loads(content)
data["uid"]=str(response["uid"])#用户名
data["sno"]=str(response["sno"])#学号
data["token"]=str(response["token"])#token

def login_exam():
url=login_exam_url+"uid="+data["uid"]+"&token="+data["token"]
request=urllib2.urlopen(url)
content=request.read()
response=json.loads(content)
data["id"]=str(response["id"])#某编号
data["totalSubCount"]=str(response["totalSubCount"])#题数
data["examPaperId"]=str(response["examPaperId"])#试卷编号

def get_paper():
url=get_paper_url+data["id"]+"/"+data["examPaperId"]+"?uid="+data["uid"]+"&token="+data["token"]+"&totalCount="+data["totalSubCount"]
request=urllib2.urlopen(url)
content=request.read()
response=json.loads(content)
ans=response["dtos"]
for question in ans:
subId=str(question["subId"])
answers=question["answers"]
option=""
for opt in answers:
option+=","+opt["optionValue"]
option=option[1:len(option)]
#time.sleep(10) 如果每道题需要做10秒。。。
solve_question(subId,option)

def solve_question(subId,option):
url=solve_question_url+data["examPaperId"]+"/"+subId+"?selectOptions="+option+"&token="+data["token"]+"&uid="+data["uid"]
urllib2.urlopen(url)

def submit_paper():
url=submit_paper_url+data["examPaperId"]+"?uid="+data["uid"]+"&token="+data["token"]
request=urllib2.urlopen(url)
content=request.read()
response=json.loads(content)
print "Your score is "+str(response["score"])+" !"

if '__main__'==__name__:
login_system(sys.argv[1],sys.argv[2])
login_exam()
get_paper()
submit_paper()

最后执行python hack.py <账号> <密码> 即可。不出意外的话,几秒钟之后就会显示Your score is 100 ! 了。

好动校园理论考试破解(1/2)

Posted on 2016-06-25 | In Web

背景

不知道从什么时候开始,学校的体育理论考试搞成了下载一个app然后在这上面考。。。本来觉得没什么,然后突然爆出这个app有一坨bug,安卓端多选题只能提交一个答案(后来发现原因是多选题提交答案时的while循环里多写了一个break。。。),导致分数奇低。虽然后来做了一个紧急修复,但从这也能看出开发人员的尿性。。。再后来,有个专门搞app的同学说他能够刷到满分,我稍微想了下,这种考试型app的逻辑能够被破解,无非有两个方法:第一种就是记录所有模拟题库中的题目和答案,然后比对考题进行提交;第二种就是他在把题目发送过来的时候顺带把答案也发送过来了,然后在本地做的成绩校验,最后把结果发回服务器。后来实际操作了下,发现app中的题库在考试阶段是关闭的,那么只就剩下第二种可能了。不得不说开发的同行们也是人才,发送考试卷子还会把答案发过来,而且报文还是明文未加密的,这不是成心勾人犯罪么。。。

这样,思路有了,下面就是操作了。说白了,我们需要做的就是抓包分析,分析他前后台传送的http报文,然后模拟考试。

抓包分析

跟抓网页不一样,这次是抓手机的包,那么就需要用电脑来代理手机的网络,具体做法详见Fiddler代理如何配置。这里讲的很清楚了,不过需要注意的是默认的端口8888可能会被一些程序占用,无法使用的时候换一个端口号即可。

当然首先电脑跟手机得是一个局域网,我这里当然是校园网。

顺便提一句,这个方法还可以用一个网关登陆N多个终端。。。不过目测是分享带宽的。。。

代理配置好之后,打开app,考一次试(这将浪费一次考试机会),记录下fiddler抓到的报文:

一、登陆

request

1
2
3
4
5
6
7
8
9
10
POST http://appsrv.ihodoo.com/login HTTP/1.1
If-Modified-Since: Sat, 18 Jun 2016 03:36:12 GMT+00:00
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 5.1.1; Mi-4c MIUI/V7.3.2.0.LXKCNDD)
Host: appsrv.ihodoo.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 46

username=17751129083&password=*************** (密码不给看)

respond

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"uid":"17751129083",
"user_id":39052,
"sno":"1427406034",
"portalUserId":115982,
"isBindSchool":true,
"isMasterMass":false,
"loginStatus":true,
"bindDto":{
"sno":"1427406034",
"name":"丁庆祝",
"school":{
"id":26,
"name":"苏州大学"
},
"schoolId":26,
"schoolName":"苏州大学",
"currentAdclassId":0,
"currentAdclassName":""
},
"token":"afa6da18-0fd2-476c-93df-4a2e3b0263eb"
}

登陆的过程就是把用户名密码post过去,然后他会返回给你一堆信息,这里显示了json数据部分,意思也都很清楚,尤其注意那个token。

二、进入考试

request

1
GET http://appsrv.ihodoo.com/auth/exam/enterIndex?uid=17751129083&token=afa6da18-0fd2-476c-93df-4a2e3b0263eb HTTP/1.1

respond

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"id" : 10,
"notices" : "",
"startTime" : "2016年06月13日 00时05分",
"endTime" : "2016年06月26日 23时55分",
"totalSubCount" : 50,
"examPaperId" : 318367,
"examPaperName" : "试题来源:篮球21二年级",
"subjectScore" : 2.0,
"studentName" : "丁庆祝",
"studentSno" : "1427406034",
"itemName" : "篮球21",
"examMinutes" : 60,
"isAllowExam" : true,
"isDuring" : true,
"message" : "丁庆祝_篮球21二年级_20160614尚未交卷,请在规定的时间内完成考试!",
"scores" : { }
}

这是进入考试的提醒,把uid和token用Get方法传过去,他会返回你即将得到的考卷的信息,包括某编号(id)、题目数(totalSubCount)、试卷编号(examPaperId)。

三、获得考卷

request

1
GET http://appsrv.ihodoo.com/auth/exam/start/10/318367?uid=17751129083&token=afa6da18-0fd2-476c-93df-4a2e3b0263eb&totalCount=50 HTTP/1.1

respond

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
{
"dtos": [
{
"subName": "在体育锻炼过程中,使外环境与内环境在时间上协调起来,才能达到最佳的体育锻炼效果。",
"subId": 38667,
"sort": 6,
"totalCount": 50,
"options": [
{
"id": 121582,
"optValue": "A",
"optLabel": "√"
},
{
"id": 121583,
"optValue": "B",
"optLabel": "×"
}
],
"answers": [
{
"optionValue": "A"
}
],
"selects": [ ],
"isMarked": false
},

......
......
......
{
"subName": "秋季的人体新陈代谢活动比较弱,对有害物质的抵抗力较低,更容易危害人体健康。",
"subId": 38668,
"sort": 8,
"totalCount": 50,
"options": [
{
"id": 121584,
"optValue": "A",
"optLabel": "√"
},
{
"id": 121585,
"optValue": "B",
"optLabel": "×"
}
],
"answers": [
{
"optionValue": "B"
}
],
"selects": [ ],
"isMarked": false
},
{
"subName": "从文化的视角探讨奥林匹克运动,对___、___、吸收奥林匹克先进文化、加强社会主义精神文明建设,具有重要意义。",
"subId": 39050,
"sort": 29,
"totalCount": 50,
"options": [
{
"id": 122844,
"optValue": "A",
"optLabel": "A 了解奥林匹克运动"
},
{
"id": 122845,
"optValue": "B",
"optLabel": "B 进行奥林匹克比赛"
},
{
"id": 122846,
"optValue": "C",
"optLabel": "C 弘扬奥林匹克精神"
},
{
"id": 122847,
"optValue": "D",
"optLabel": "D 开展奥林匹克教育"
}
],
"answers": [
{
"optionValue": "C"
},
{
"optionValue": "D"
}
],
"selects": [ ],
"isMarked": false
}
],
"message": "",
"isSuccess": true
}

这是获得考卷的过程,把id、examPaperId、uid、token、totalSubCount传过去即可,得到一堆试题。。。。。。这里取三种典型题目,第一个是单选题,第二个是判断题,第三个是多选题。每道题都有题目内容,题目编号,题目顺序(由于json是不保证顺序的,因此需要有个sort来控制顺序)、题目选项、以及题目答案。。。

四、模拟做题

request

1
GET http://appsrv.ihodoo.com/auth/exam/select/318367/38861?selectOptions=B,C&token=afa6da18-0fd2-476c-93df-4a2e3b0263eb&uid=17751129083

返回结果大概就是提交成功之类的。

这个过程其实就是把每道题的id、答案加上自己的uid和token一起发过去,非常简单。

五、提交试卷

request

1
GET http://appsrv.ihodoo.com/auth/exam/submit/318367?uid=17751129083&token=afa6da18-0fd2-476c-93df-4a2e3b0263eb HTTP/1.1

respond

1
2
3
4
5
6
7
8
9
{
"score" : 6.0,
"times" : 1,
"totalRank" : 0,
"scoreRank" : 11395,
"message" : "试卷提交成功!",
"rankMessage" : "您本次考试成绩还没有以前考得高,需要继续加油!",
"isSuccess" : true
}

套路跟上面一样。。。最后发现我得了6.0分。。。

用LaTeX进行论文排版

Posted on 2016-06-16 | In LaTeX

都知道写文档论文之类的肯定是用LaTeX比较漂亮,虽然我对用LaTeX写数学公式稍微有点了解,但是还是没有直接用它来排版。下面就整理下用LaTeX写文档的方法。

安装

最常用的LaTeX排版工具是MikTeX。选择好windows版本,下载安装即可。可执行文件是%install_path%/miktex/bin/x64/texworks.exe。

论文模板

这里的格式通常是在网上找模板。。。毕竟自己弄还是挺麻烦的,而且还要考虑中文编码的问题。我找到的模板如下:(用pdfLaTeX+MakeIndex+BibTex编译)

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
\documentclass[a4paper, 11pt]{article}

%%%%%% 导入包 %%%%%%
\usepackage{CJKutf8}
\usepackage{graphicx}
\usepackage[unicode]{hyperref}
\usepackage{xcolor}
\hypersetup{hidelinks}%%%取消链接的红框框%%%%

\usepackage{indentfirst}

%%%%%% 设置字号 %%%%%%
\newcommand{\chuhao}{\fontsize{42pt}{\baselineskip}\selectfont}
\newcommand{\xiaochuhao}{\fontsize{36pt}{\baselineskip}\selectfont}
\newcommand{\yihao}{\fontsize{28pt}{\baselineskip}\selectfont}
\newcommand{\erhao}{\fontsize{21pt}{\baselineskip}\selectfont}
\newcommand{\xiaoerhao}{\fontsize{18pt}{\baselineskip}\selectfont}
\newcommand{\sanhao}{\fontsize{15.75pt}{\baselineskip}\selectfont}
\newcommand{\sihao}{\fontsize{14pt}{\baselineskip}\selectfont}
\newcommand{\xiaosihao}{\fontsize{12pt}{\baselineskip}\selectfont}
\newcommand{\wuhao}{\fontsize{10.5pt}{\baselineskip}\selectfont}
\newcommand{\xiaowuhao}{\fontsize{9pt}{\baselineskip}\selectfont}
\newcommand{\liuhao}{\fontsize{7.875pt}{\baselineskip}\selectfont}
\newcommand{\qihao}{\fontsize{5.25pt}{\baselineskip}\selectfont}

%%%% 设置 section 属性 %%%%
\makeatletter
\renewcommand\section{\@startsection{section}{1}{\z@}%
{-1.5ex \@plus -.5ex \@minus -.2ex}%
{.5ex \@plus .1ex}%
{\normalfont\sihao\CJKfamily{hei}}}
\makeatother

%%%% 设置 subsection 属性 %%%%
\makeatletter
\renewcommand\subsection{\@startsection{subsection}{1}{\z@}%
{-1.25ex \@plus -.5ex \@minus -.2ex}%
{.4ex \@plus .1ex}%
{\normalfont\xiaosihao\CJKfamily{hei}}}
\makeatother

%%%% 设置 subsubsection 属性 %%%%
\makeatletter
\renewcommand\subsubsection{\@startsection{subsubsection}{1}{\z@}%
{-1ex \@plus -.5ex \@minus -.2ex}%
{.3ex \@plus .1ex}%
{\normalfont\xiaosihao\CJKfamily{hei}}}
\makeatother

%%%% 段落首行缩进两个字 %%%%
\makeatletter
\let\@afterindentfalse\@afterindenttrue
\@afterindenttrue
\makeatother
\setlength{\parindent}{2em} %中文缩进两个汉字位

%%%% 下面的命令重定义页面边距,使其符合中文刊物习惯 %%%%
\addtolength{\topmargin}{-54pt}
\setlength{\oddsidemargin}{0.63cm} % 3.17cm - 1 inch
\setlength{\evensidemargin}{\oddsidemargin}
\setlength{\textwidth}{14.66cm}
\setlength{\textheight}{24.00cm} % 24.62

%%%% 下面的命令设置行间距与段落间距 %%%%
\linespread{1.4}
% \setlength{\parskip}{1ex}
\setlength{\parskip}{0.5\baselineskip}

%%%% 正文开始 %%%%
\begin{document}
\begin{CJK}{UTF8}{gbsn}

%%%% 定理类环境的定义 %%%%
\newtheorem{example}{例} % 整体编号
\newtheorem{algorithm}{算法}
\newtheorem{theorem}{定理}[section] % 按 section 编号
\newtheorem{definition}{定义}
\newtheorem{axiom}{公理}
\newtheorem{property}{性质}
\newtheorem{proposition}{命题}
\newtheorem{lemma}{引理}
\newtheorem{corollary}{推论}
\newtheorem{remark}{注解}
\newtheorem{condition}{条件}
\newtheorem{conclusion}{结论}
\newtheorem{assumption}{假设}

%%%% 重定义 %%%%
\renewcommand{\contentsname}{目录} % 将Contents改为目录
\renewcommand{\abstractname}{摘要} % 将Abstract改为摘要
\renewcommand{\refname}{参考文献} % 将References改为参考文献
\renewcommand{\indexname}{索引}
\renewcommand{\figurename}{图}
\renewcommand{\tablename}{表}
\renewcommand{\appendixname}{附录}
\renewcommand{\algorithm}{算法}

%%%% 定义标题格式,包括title,author,affiliation,email等 %%%%
\title{功能说明}
\author{丁庆祝\footnote{电子邮件:dqz48548263@qq.com,博客:\url{http://blog.mythsman.com}}\\[2ex]%链接、注解%
\xiaosihao 苏州大学 2014级计算机学院\\[2ex]
}
\date{2016年6月}

%%%% 以下部分是正文 %%%%
\maketitle
\tableofcontents
\newpage

--这里是正文--

\newpage%这个newpage很重要,不加的话可能会莫名报错...%
\end{CJK}
\end{document}

这主要是写中文文档的配置,当然他会提醒你下载一些包,照做即可。

基本格式

其实,通常使用的时候,我们最需要的操作只是对文章进行分章节:

1
2
3
4
5
6
7
8
9
10
\section{Section}
Section content
\subsection{Subsection}
Subsection content
\subsubsection{Subsubsection}
Subsubsection content
\paragraph{paragraph}
Paragraph content
\subparagraph{subparagraph}
subparagraph content

效果大概是这样:


js高级与面向对象之继承

Posted on 2016-06-15 | In javascript

一个对象没有某些属性和方法,另一个对象有,拿过来使用,就是继承

Read more »

Huffman无损压缩和解压算法实现

Posted on 2016-06-14 | In Algorithm

高中学信息论的课后作业,本来自己的项目文档和中期汇报还没写,为了强行装x答应了下来,结果硬是熬夜到四点才敲完。。。。(以后绝不装逼了)

虽然算法看上去不难,但是不得不说还是走了很多弯路,学到了很多东西,在这里做个记录。

需求

用Huffman 编码实现文件的无损压缩和解压。

算法

算法当然用到了霍夫曼编码,构造霍夫曼树。具体过程也很简单,就是把读入的字节流按照字节进行频数分析,对频率高的字符用短编码,对频率低的用长编码。然后将编码的映射表和编码后的结果写入文件,这时候生成的文件就是压缩后的文件了。根据信息论的相关知识,这大概算是无损编码中压缩效率最高的了。

困难

相比我在遇到这个问题的时候,遇到的最大难度其实是文件的读写。由于平时对文件读写操作的练习不到位,出了很多洋相。比如忘记了java中char是两字节的;比如byte是有符号的;比如中文字符的编码问题;比如ObjectInputStream对象的available方法返回的是当前block的剩余字符而不是整个文件的剩余字符;除此之外,还要考虑压缩后的比特流长度可能不能构成完整的字节,因此要设计空白比特的填充处理;由于是压缩文件,因此还要考虑空间效率,不能直接用ArrayList之类的东西存储数据,否则开销大的还不如不压缩。。。。。。估计是因为我太弱了,这种过程对我来说还是充满了挑战的。。。

代码

没有考虑读入和写入的效率问题,文件处理(尤其是压缩的写入过程)写的比较丑。。。

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

//霍夫曼树的节点
class Node {

public Node left, right;
public int source;
public int weight;
public String dest;

public Node(int sour, int wei) {
source = sour;
weight = wei;
left=right=null;
dest="";
}
}

//写入文件的头信息
class Header implements Serializable {

private static final long serialVersionUID = 1L;
public String[] mp;

public Header(String[] m) {
mp = m;

}
}

/**
* 压缩解压的主类
* @author Myths
*
*/
public class Huffman {

public String[] mp;
public int[] cnt;
public String path;

public Huffman(String path){
this.path = path;
mp = new String[256];
cnt = new int[256];
}

//封装了解压的方法
public void unzip() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream ins = new ObjectInputStream(new FileInputStream(new File(path)));
FileOutputStream writer = new FileOutputStream(new File(path.substring(0, path.length() - 5)));
Header zipFile = (Header) ins.readObject();

Map<String, Character> mp = new HashMap<String, Character>();
for (int i = 0; i < 256; i++) {
if (zipFile.mp[i] != null) {
mp.put(zipFile.mp[i], (char) i);
}
}

String buff = "";
byte[] bf = null;
while (ins.available() >= 4) {

if (ins.available() == 4) {
bf = new byte[4];
for (int i = 0; i < 4; i++)
bf[i] = ins.readByte();
if (ins.available() == 0) {
break;
}
for (int j = 0; j < 4; j++) {
buff += b2s(bf[j]);
while (buff.length() > 256) {
String s = "";
int cnt = 0;
for (int i = 0; i < buff.length(); i++) {
s += buff.charAt(i);
if (mp.containsKey(s)) {
writer.write(mp.get(s));

cnt += s.length();
s = "";
break;
}
}
writer.flush();
buff = buff.substring(cnt, buff.length());
}
}
}
byte c = ins.readByte();
buff += b2s(c);
while (buff.length() > 256) {
String s = "";
int cnt = 0;
for (int i = 0; i < buff.length(); i++) {
s += buff.charAt(i);
if (mp.containsKey(s)) {
writer.write(mp.get(s));
cnt += s.length();
s = "";
break;
}
}
writer.flush();
buff = buff.substring(cnt, buff.length());
}

}

for (int i = 0; i < 4; i++) {
if (bf[i] == 0) {
buff += "0";
} else if (bf[i] == 1) {
buff += "1";
}
}

String s = "";
for (int i = 0; i < buff.length(); i++) {
s += buff.charAt(i);
if (mp.containsKey(s)) {
writer.write(mp.get(s));
s = "";
}
}
writer.flush();
writer.close();
ins.close();
}

//封装了压缩的方法
public void zip() throws IOException {
readFrequency();
huffmanEncrypt();
FileInputStream ins = new FileInputStream(new File(path));
Header zipFile = new Header(mp);
ObjectOutputStream ous = new ObjectOutputStream(new FileOutputStream(path + ".huff"));
ous.writeObject(zipFile);

String buff = "";
int c;
while ((c = ins.read()) != -1) {
buff += mp[c];
while (buff.length() >= 8) {
ous.writeByte((byte) (s2b(buff.substring(0, 8))));
buff = buff.substring(8, buff.length());
}
}

for (int i = 0; i < 4; i++) {
if (i < buff.length()) {
ous.writeByte(buff.charAt(i) - '0');
} else {
ous.writeByte(255);
}
}

ous.flush();
ous.close();
ins.close();
}

//字节转二进制字符串
public String b2s(byte c) {
int cc = (c + 256) % 256;
String s = "";
while (cc > 0) {
if (cc % 2 == 1) {
s += "1";
} else {
s += "0";
}
cc /= 2;
}
while (s.length() < 8) {
s += "0";
}
return s;
}

//二进制字符串转字节
public byte s2b(String s) {
byte c = 0;
for (int i = 7; i >= 0; i--) {
c *= 2;
if (s.charAt(i) == '1') {
c += 1;
}

}
return c;
}

// 读取文件,并获得每个字符的频数
public void readFrequency() throws IOException {

File file = new File(path);
FileInputStream ins=new FileInputStream(file);
int c;
while ((c = ins.read()) != -1) {
cnt[c] += 1;
}
ins.close();
}

// 读取频数,返回Huffman映射表
public void huffmanEncrypt() {

PriorityQueue<Node> pq = new PriorityQueue<Node>(256, new Comparator<Node>() {

@Override
public int compare(Node o1, Node o2) {

return o1.weight - o2.weight;
}

});
int times = 0;
for (int i = 0; i < 256; i++) {
if (cnt[i] > 0.5) {
pq.add(new Node(i, cnt[i]));
times++;
}
}

for (int i = 0; i < times - 1; i++) {
Node nodeFir, nodeSec;
nodeFir = pq.poll();
nodeSec = pq.poll();
Node newNode = new Node(-1, nodeSec.weight + nodeFir.weight);
newNode.left = nodeSec;
newNode.right = nodeFir;
pq.add(newNode);
}

Node root = pq.poll();
Queue<Node> q = new LinkedBlockingQueue<Node>();
q.add(root);
while (!q.isEmpty()) {
Node cur = q.poll(); // bfs遍历
if (cur.source == -1) { // 非叶子节点
if (cur.left != null) {
cur.left.dest = cur.dest + "1";
q.add(cur.left);
}
if (cur.right != null) {
cur.right.dest = cur.dest + "0";
q.add(cur.right);
}
} else { // 叶子节点
mp[cur.source] = cur.dest;
}
}
}

public static void main(String[] args) throws IOException, ClassNotFoundException {

Huffman huff = new Huffman("C:\\Users\\Administrator\\Desktop\\in.txt.huff");

huff.unzip();

//Huffman huff = new Huffman("C:\\Users\\Administrator\\Desktop\\in.txt");

//huff.zip();
}
}

Mysql批量导入数据的问题

Posted on 2016-06-11 | In Database

问题

之前的文章讲过了,如果想向Mysql快速的批量导入数据的话,最好的方法就是使用load data local in file "path" into table mytable 。但是在最近的一次使用中,我发现,对于使用含有auto_increment字段的表,多次导入数据的时候,该字段的值会出现跳跃丢失。。。不知道是怎么一回事。下面是实验过程。

实验环境

mysql 5.7.12

实验步骤

一、创建一个简单的表:

1
2
3
4
5
6
7
8
9
10
11
mysql>  create table tmp(id int not null primary key auto_increment,value int not null);
Query OK, 0 rows affected (0.23 sec)

mysql> desc tmp ;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| value | int(11) | NO | | NULL | |
+-------+---------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

注意到id字段设置为auto_increment。

二、创建一个数据文件in.txt:

1
2
3
null    1
null 2
null 3

三、导入数据

第一次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> load data local infile "in.txt" into table tmp;
Query OK, 4 rows affected, 5 warnings (0.06 sec)
Records: 4 Deleted: 0 Skipped: 0 Warnings: 5

mysql> select * from tmp;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 0 |
+----+-------+
4 rows in set (0.00 sec)

第二次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> load data local infile "in.txt" into table tmp;
Query OK, 4 rows affected, 5 warnings (0.04 sec)
Records: 4 Deleted: 0 Skipped: 0 Warnings: 5

mysql> select * from tmp;
+----+-------+
| id | value |
+----+-------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 0 |
| 8 | 1 |
| 9 | 2 |
| 10 | 3 |
| 11 | 0 |
+----+-------+
8 rows in set (0.00 sec)

很明显可以看到,中间丢失了三个id,不知道是为什么。

问题解决

最后问了百度知道。。。知道上的同学说是数据最后加了个空行;本来我还不相信,以为每条数据之后都要加个回车,但是仔细一研究果然是这样。加了空行后,这一行数据的值会为默认值,而且自增Id的值也会出现问题,就像上面描述的这样;而把最后的回车删除之后,结果就没有问题了。。。

1…404142…58

574 posts
69 categories
286 tags
© 2024 Companyd
Powered by Hexo
|
Theme — NexT.Muse v5.1.4