Java 8 之 java.time 包

包概述

java.time 包是在JDK8新引入的,提供了用于日期、时间、实例和周期的主要API。

java.time包定义的类表示了日期-时间概念的规则,包括instants, durations, dates, times, time-zones and periods。这些都是基于ISO日历系统,它又是遵循 Gregorian规则的。

所有类都是不可变的、线程安全的。

继续阅读

J.U.C 包

概述

J.U.C 包是java.util.concurrent包的简写。这个包在JDK5引入,大大增强了Java的并发特性。JDK7还引入ForkJoin框架。

该包提供的能力主要包括:可重入锁,具有原子性操作属性的类,线程池执行服务,调度执行服务,增强的线程安全容器,线程关卡,信号器,ForkJoin任务执行框架等等。
继续阅读

Redis-RDB-Dump-File-Format 中文翻译

今年年初翻译的,都忘得差不多了,最近想用Go写个程序解析RDB文件,重新翻出来。

翻译自:
https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format

如果对本文档的后续更新有兴趣,可关注:https://github.com/wen866595/open-doc

Redis RDB 文件格式

Redis *.rdb 文件是一个内存内存储的二进制表示法。这个二进制文件足以完全恢复Redis的状态。

rdb文件格式为快速读和写优化。LZF压缩可以用来减少文件大小。通常,对象前面有它们的长度,
这样,在读取对象之前,你可以准确地分配内存大小。

为快速读/写优化意味着磁盘上的格式应该尽可能接近于在内存里的表示法。这种方式正是rdb文件采用的。
导致的结果是,在不了解Redis在内存里表示数据的数据结构的情况下,你没法解析rdb文件。

解析RDB的高层算法

在高层层面看,RDB文件有下面的格式:


----------------------------# RDB 是一个二进制文件。文件里没有新行或空格。
52 45 44 49 53              # 魔术字符串 "REDIS"
00 00 00 03                 # RDB 版本号,高位优先。在这种情况下,版本是 0003 = 3
----------------------------
FE 00                       # FE = code 指出数据库选择器. 数据库号 = 00
----------------------------# 键值对开始
FD $unsigned int            # FD 指出 "有效期限时间是秒为单位". 在这之后,读取4字节无符号整数作为有效期限时间。
$value-type                 # 1 字节标记指出值的类型 - set,map,sorted set 等。
$string-encoded-key         # 键,编码为一个redis字符串。
$encoded-value              # 值,编码取决于 $value-type.
----------------------------
FC $unsigned long           # FC 指出 "有效期限时间是豪秒为单位". 在这之后,读取8字节无符号长整数作为有效期限时间。
$value-type                 # 1 字节标记指出值的类型 - set,map,sorted set 等。
$string-encoded-key         # 键,编码为一个redis字符串。
$encoded-value              # 值,编码取决于 $value-type.
----------------------------
$value-type                 # 这个键值对没有有效期限。$value_type 保证 != to FD, FC, FE and FF
$string-encoded-key
$encoded-value
----------------------------
FE $length-encoding         # 前一个数据库结束,下一个数据库开始。数据库号用长度编码读取。
----------------------------
...                         # 这个数据库的键值对,另外的数据库。
FF                          ## RDB 文件结束指示器
8 byte checksum             ## 整个文件的 CRC 32 校验和。

继续阅读

散列

散列一般也叫哈希。散列表也叫哈希表。本位将介绍散列表的基本知识、一致性哈希、哈希碰撞攻击及Java里的哈希实现。

介绍

散列表是普通数组概念的推广,在最坏情况下查找一个元素需要O(n),在一些合理假设下,查找一个元素的期望时间为O(1)。

在散列表中,不是直接把关键字用作数组下标,而是根据关键字计算出下标。

散列函数:作用就是根据关键字计算出数组下标。

碰撞(collision):多个关键字映射到同一个数组下标位置。

槽:一般把散列表的数组的一个存储单元(元素)叫做槽。

简单一致性散列:(Simple uniform hashing)假设任何元素散列到m个槽中的每一个的可能性是相同的,且与其他元素已被散列到什么位置上独立无关,这个假设称为简单一致性散列。

继续阅读

我的学习工具

今天跟一个同学聊天,发现很多很好用的工具他都还不知道,我周围的绝大多数同事也不知道。虽然我用的工具不多,用得也不是很深入,但对我的帮助已经非常大,所以写的文字介绍。

浏览器

首先要说的是浏览器,因为上网大多数都是在浏览器里进行的。我用的是Firefox,因为有很多插件可用。Chrome也不错,只是习惯了火狐。

火狐的一个很重的功能是账号同步功能,可以同步的最重要的两个内容:已安装插件、书签。也就是在办公室的火狐上安装了一个插件或者收藏了一个网址,回家后也有了,不用再搞一遍。换了一台机或重装了系统,登录火狐账号后,一切又回来了。这也是云的作用吧!

浏览器插件

现在用的浏览器插件主要有:

  • AutoProxy:翻墙,你懂的!
  • pocket:以前好像叫“read it later”。可以把网页的内容收藏起来、归档,以后想看的时候再看。排版不错,对有些网站还会去掉一些网页周边的广告,只保留内容。
  • 印象笔记插件:可以把一个网页、图片、网址减藏到印象笔记里。在浏览器里用google搜索时,还可以搜笔记里的内容。
  • DownThemAll:下载,断点续传、分块下载。
  • 花瓣插件:微博上很多有价值的文章是图片形式的长微博,保存到花瓣方便查找。
  • 微博极简:过滤微博的,很多信息比如广告是不想看到的。

继续阅读

base64加密 or base64编码?

base64加密?

最近又碰到这么个奇葩的需求:“出于安全考虑,把Cookie里xxx属性的值用base64加密。”

之前碰到的另一个场景是:“一个PC客户端上传一些文件,不采用base64编码没法上传”。在这个案例建议人家取消base64编码时,人家也抬出了“安全”的大棒。

有base64加密吗??真木有,只有base64编码。

base64编码

关于base64编码,来自维基百科 http://zh.wikipedia.org/zh/Base64

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9 ,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是它们不叫Base64。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIME的email,email via MIME,在XML中存储复杂数据。

编码后的数据比原始数据略长,为原来的4/3 。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。

使用恰当的锤子

一句话来说:base64编码是用来解决把不可打印的内容塞进可打印内容的需求的。

如果需要加密,请使用专业的加密算法。想以“一般的用户看不到加密后的内容”为借口,只会糊弄自己。一般的用户不会去查看Cookie的内容,恶意的人根本就不会被这点小伎俩糊弄。

别再用“base64加密”,请用“base64编码”!


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

SMART任务

摘自:《程序员的思维修炼:开发认知潜能的九堂课》

这里的SMART代表具体的、可度量的、可实现的、相关的和时间可控的(Specific, Measurable, Achivable, Relevant, Time-boxed)。对于任何目标,都需要制定一个计划,定出一序列帮助你实现目标的任务。每个任务都应该具有SMART特性。

  • 具体的。一个目标任务应该是具体的。“想学习Erlang”是不够具体的,“想用Erlang编写一个可以动态生成内容的Web容器”就是具体的。

  • 可度量的。可度量的与具体的是相辅相成。很难度量笼统抽象的事物,但是很容易度量具体和详细的事物,只要使用确切的数字即可。度量任务目标,要采取增量进步的方法。

  • 可实现的。一个无法达到的目标不是目标,只是一种疯狂、吸食灵魂的自我挫败。先确定目标是否合理。从现在所处的情况着眼,让每一个目标都可实现。

  • 相关的。目标需要相关,需要在掌控之中。

  • 时间可控的。需要设定一个最后期限,没有期限,目标会逐步衰退,永远被每天更紧急的事情所排挤,这样它永远不会实现。

稳抓稳打,采取循序渐进、比较细小的里程碑。当实现它们之后,会更有动力去实现下一个里程碑。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

正则表达式反向引用

参考: http://java.dzone.com/articles/backreferences-java-regular

以前没用过这种用法,mark。

介绍

反向引用是基于的,组就是把多个字符当作单一的单元看待。组是通过在一对小括号(())内放置正则字符来创建的,每对小括号对应一个组。

反向引用是便捷的,允许重复正则而不需要再写一次。可以通过 \# 来引用前面定义的组,# 是组的序号,从 1 开始。

正则引擎在处理匹配时,要求 反向引用与所引用的组 匹配的内容必须是一样的:即,(\d\d\d)\1 匹配 123123,而不匹配123456

继续阅读

吃自己的狗粮,用Dropbox Go SDK

获取appKey和设置回调地址

到这个页面https://www.dropbox.com/developers/apps 创建一个应用,应用的类型选择Dropbox API app,在这个页面还可以选择应用能访问的数据范围。

很重要的一点就是:应该只赋予应用最小权限,也就是只访问它自己创建的文件。

应用创建好后就可以在详细页面查看它的的App key,也就是下面要用的。

在应用的详细页面,还要设置授权后的回调地址,也就是“ OAuth redirect URIs ”的输入框,这个地址必须是合法的URL,哪怕是不存在的,也就是,可以设置成“https://127.0.0.1/oauth2/authorized”。

获取授权码

将上面得到的appKey和回调地址拼接成下面这样:
https://www.dropbox.com/1/oauth2/authorize?response_type=token&client_id=abc1234569XYZ&redirect_uri=https://127.0.0.1/oauth2/authorized

里面的client_id的值填appKey,redirect_uri填回调地址,把这个地址拷贝到浏览器打开,如果你还没有登录Dropbox,会提醒你登录,登录后大概是这样的界面:
vpsBak4coderbee

点击“允许”授权成功后,浏览器会调整,地址栏里的地址会变,拷出来大概是这样的:
https://127.0.0.1/oauth2/authorized#access_token=O_xxkdkdkdw2yeidikcppdfdoiffjj&token_type=bearer&uid=158130000

上面的access_token: O_xxkdkdkdw2yeidikcppdfdoiffjj就是代码要用的。

调用Go SDK

首先要把sdk clone回来: git clone https://github.com/wen866595/godropbox.git , 这条命令会把sdk拷贝到当前的godropbox目录下。


package main

import (
        "./dropbox"
        "fmt"
        "os"
        "flag"
)

var (
        tokens = map[string]string{
                "access_token": "you oauth2 access token",
                "token_type":   "bearer",
        }
)

func main() {
        flag.Parse()

        args := flag.Args()
        if len(args) < 2 {
                fmt.Printf("Usage: godropbox path/to/locale/file  /path/at/dropbox\n")
                return
        }

        oauth2 := &dropbox.OAuth2{AccessToken: tokens["access_token"], TokenType: tokens["token_type"]}

        dropboxApi := &dropbox.DropboxApi{Signer: oauth2, Root: "sandbox", Locale: "CN"}

        localePath, remotePath := flag.Arg(0), flag.Arg(1)
        _, err := dropboxApi.UploadByChunked(localePath, remotePath, 10485760, 8)   //  10485760表示一次上传的块大小为1M,对于大文件,这个值设得大点可以减少上传的次数。
        if err != nil {
                fmt.Printf("error msg: %s\n", err)
                os.Exit(1)
        } else {
                os.Exit(0)
        }
}

把上面的代码保存在main.go文件里面,放到godropbox目录下,到godropbox目录用 go build命令构建成一个可执行文件。在我的VPS上使用: ./godropbox path/to/locale/file /path/at/dropbox,效果还行。

以前用Java SDK写过一个上传的功能,文件上传完了还要很久才退出。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。