ichuan.net

自信打不死的心态活到老

浏览器处理链接href属性的一个差异

浏览器在处理链接的href属性时,如果该链接是相对路经(如href="/test")或者锚点(如href="#test"),IE下读取到的值是拼接好的完整地址,而其他浏览器下读到的是原始href属性值。

加入有个index.html内容如下:

<html><body>

<a id="b" href="#test"></a>
<script>
    alert(document.getElementById('b').getAttribute('href'));
</script>

</body></html>

分别用Chrome、Firefox、IE打开,可以看到差别:

enter image description here

windows下路径长度限制问题

问题

昨日志旭在做一个测试时发现在 windows 下无法删除一个目录,报错如下:

enter image description here

在资源管理器左侧展开查看,发现这是个嵌套很深的目录:

enter image description here

底部红色标注的目录其实还有子目录,但是展示不出来了。在 cmd.exe 下用 del /S /Q e:\test 或者在 powershell 中用 Remove-Item e:\test -recurse 同样无法删除改目录。

原因

查了半天,原来是 windows 的路径长度限制问题导致的。据说 ANSI 版本的 windows API 能操作的最大路径长度是 260 个字符,但我在本机测试时,这个值是 247:

>>> import os
>>> x = 'e:\\'
>>> x += 'e' * (247 - len(x))
>>> len(x)
247
>>> os.mkdir(x)
>>> os.mkdir(x + 'e')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
WindowsError: [Error 206] : 'e:\\eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'
>>>

windows 下的 python 文件操作也是调用的系统 API,所以是受限制的。那之前的深层目录是如何创建的呢?原来是一个 java 程序创建的。java 程序是原生支持长路径名的。

解决方法

根据微软官方文档,要操作大于 260 字符的路径名,就需要使用 Unicode 版本的 windows API,那个限制是 32767,近乎无限制了。并且,需要在目录名前面加特殊字母:\\?\

我们先来重现一个无法在资源管理器和普通 python 代码里删除的深层目录。需注意两点:

  1. 使用 ctypes 里导出的 windll.kernel32 直接调用 Unicode 版本的创建目录 API:CreateDirectoryW
  2. 目录名前加特殊标识:\\?\

代码如下:

import os
import ctypes

mkdir = ctypes.windll.kernel32.CreateDirectoryW

cur = u'\\\\?\\e:\\'

for i in xrange(100):
    cur += u'test\\'
    mkdir(cur, None)

执行后会在 E 盘创建一个删不掉的 test 文件夹。如果你把上面的 mkdir 替换成 os.mkdir,会发现报错。

接下来尝试删除刚创建的嵌套目录。除了需要加特殊标识,还有个要注意的是:windows 下没有 API 提供类似 rm -rf 的功能,只有删除单个文件和删除空目录的 API,我们需要自己实现一个 rm -rf

import os, ctypes

rmdir = ctypes.windll.kernel32.RemoveDirectoryW

def rm_rf(dirname):
    for i in os.listdir(dirname):
        j = os.path.join(dirname, i)
        if os.path.isfile(j):
            os.remove(j)
        else:
            rm_rf(j)
    rmdir(dirname)

rm_rf(u'\\\\?\\e:\\test\\')

执行后会发现刚才的顽固目录被删除了。同样的,如果你把上面的 rmdir 换成 os.rmdir,也会发现报错。

你发现没?上述代码里的 os.listdiros.path.isfileos.path.join 都没换成 windows Unicode API,但也没问题,何解?原来部分 os 模块的接口是支持 unicode 文件名的:

>>> os.path.supports_unicode_filenames
True

但可惜的是 os.rmdir 不支持,不然就不用费心转用 windows API 了。

其他

linux 下对目录长度有限制吗?据说也有:linux 下目录长度限制是 4096 字节,文件名长度限制是 255 字节。

日志@2012/01/11

2012 新年来了,但我最近过的并不顺畅。今天反思了下自己最近的行为,得到了一些教训和指点。

昨日看的一篇帖子中有一句话:

Life is a zero-sum game

翻译过来就是:人生是个零和游戏。这句话给我两点启示:

  1. 现在吃苦,以后自然会吃到甜头;有所付出,才能有所收获。怨天尤人地原地踏步,到头来只能白了少年头,空悲切
  2. 我的精力和时间是有限的,而人类的知识是无穷的。要把时间花在有意义的事情上,少在无聊的事情上浪费精力。对我来说,有意义的事情大概是指自己感兴趣的

今年内我对自己的要求是:

  1. 少一些对生活的抱怨,多一些踏实生活的态度
  2. 为了以后,开始健身
  3. 严谨、认真地对待技术,要有究根刨底的精神

最后一点其实在 2010 年 4 月 berg 就对我提过了,当时并没当回事。

小 G 以前也说过,现在还不是收获的季节。是啊,我才 26 周岁,离无所希冀的老年还很遥远。人生虽然不完美,但留点希望总是好事。

我的 2012 年才刚刚开始。

2011年总结

现在越来越写不了长文了,就简单总结下我即将过去的 2011 年。

工作方面

知道创宇呆了近 15 个月了,这是我人生第二份工作。我还记得那次在回龙观,中午大家一起吃饭,找了一个饭馆围了一桌,大家在笑声中一个一个给我介绍自己,我紧张地拿手机记着一个又一个名号。老董最后自我介绍的,最后也是他结帐的。

进公司不久后就被老杨的个人魅力折服。当时记录的从老杨那里我学到了:1. 管理自己的时间 2. 改掉生活中不良习惯。公司里每个人都有亮点,跟他们共事让我成长很快。

一年前的今天,我初学 python,刚会对照着文档写 django 代码,还在用 php 写 MyPDC 网站;现在呢,早已由 phper 转成了重度 pythoner。

生活方面

今年公司组织了一次南戴河游玩,我得以第一次看到了大海。这里有记录。

有几次失信于别人,很内疚。

学会了游泳,隔了几个月又忘记了。

关于人生目标和理想,我现在的想法是:

在谋生问题没解决之前,不要谈任何追求兴趣和理想。
今生的终极目标是:用一生时间去把自己的价值做到最大化

关于爱情,还是今年 4 月份那次的想法

我估计以后某天可能会与那个她相遇,这只是时间问题。她还没出现是因为现在的我还不在最好的状态,我也不愿意以现在这个样子和身份去见人家。所以我不会再抱怨孤单。在那个时刻来临之前,我一定得勤加锻炼,积累资本,提升自己的价值。想起一句话,“得之我幸,失之我命”。倘若真要孤单一辈子,我也不会畏惧。

养成的一个习惯是周末的时候和单身宅男小分队的徐东和晓明一起吃饭、瞎侃。

买过 bambook 看书,后来荒废了。

无论如何,现在还觉得自己是个打不死的小强。

个人项目方面

开源了 MyPDC;写了个 djblog 博客程序和 911.im 短网址程序;写了个 todolist 应用:jihua.in

2011 大事记

有几个觉得比较大的事:

  1. 出差。今年出差了两次,工作生涯的前两次。感觉出差比平时工作还累。
  2. 买了 vps 写博客。不仅下了决心坚持写博,还对着钱包做了两次艰难的决定。
  3. 相亲。第一次相亲了,见面前心跳个不停,瞬间让我回想起了两年前在绿盟的哈尔滨办事处面试的情形,那时也是这种心跳。相亲就像面试一样,不是么?

明年计划

今年初我列了不少计划,但大都未实现。计划赶不上变化,不过还是可以一列的。明年的计划现在有两个:

  1. 和老马去西藏旅行。
  2. 买自行车,骑车锻炼身体。