月影传说怎么进不了,华泰证券缺少核心组件依赖的组件

月影传说进去后,只要一启程就卡住了,只有声音,画面定格了,怎么办呢?(logo文件已删)_百度知道
月影传说进去后,只要一启程就卡住了,只有声音,画面定格了,怎么办呢?(logo文件已删)
提问者采纳
.....显卡低了..,话说LZ玩月影都卡.
提问者评价
NVIDIA Gedorce G103M 的显卡
有游戏进入页面 启程之后黑屏
真的是夏卡问题吗?
其他类似问题
为您推荐:
您可能关注的推广
月影传说的相关知识
其他2条回答
更换显卡!
把游戏目录下的video文件夹,随便改个名字就行了,比如+个1,video1
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁剑侠情缘外传月影传说怎么卡在西山居的画面进不去?!!! 本人是WIN7系统,用98兼容模式运行的。_百度知道
剑侠情缘外传月影传说怎么卡在西山居的画面进不去?!!! 本人是WIN7系统,用98兼容模式运行的。
我有更好的答案
把游戏目录下的video文件夹,随便改个名字就行了,比如+个1,video1
可以在xp系统上运行吗??如果可以 ,你可以安装WIN7的XP虚拟 机,在虚拟机上 想装什么装 什么,也没兼容问题了,XP兼容性比WIN7好。所以微软在出W IN7系统时又附带一个XP虚拟机。但虚拟机要上微软网站上下载,WINDOWS VIRTUAL PC,同时再把其奉送 的正 版虚拟XP系统 一起下来,在WIN7安装就OK了然后....你懂得
其他类似问题
为您推荐:
您可能关注的推广
剑侠情缘外传月影传说的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁我的机子是WINDOWS Vista 剑侠情缘外传-月影传说玩不来 进去后屏幕就卡住黑屏 但有声音 为什么怎么解决?
我的机子是WINDOWS Vista 剑侠情缘外传-月影传说玩不来 进去后屏幕就卡住黑屏 但有声音 为什么怎么解决?
09-12-23 & 发布
众所周知,Windows 7是微软继Windows XP、Vista之后推出的新一代操作系统,随着其日正式上市日期的日益临近,全世界电脑用户的目光再一次被该系统吸引。联想起Vista推出时因为兼容性问题,在市场上业绩不佳,新一代的Windows 7能否在至关重要的兼容性上做得更好呢?为此,笔者通过Windows 7 RTM版本来一睹Windows 7的兼容性。   &strong&一、常见软件的测试&/strong&  道听途说为虚,实际测试为实。笔者在自己的笔记本和台式机上分别安装了Windows 7 Ultimate(旗舰版)系统为基础进行系列测试。下面是测试平台:&/p&&table border=0 cellSpacing=1 cellPadding=6 width=460 align=center&&tbody&&tr&&td width=70 align=middle& &/td&&td width=250&笔记本配置&/td&&td width=250&台式机配置&/td&&/tr&&tr&&td align=middle&处理器&/td&&td&Intel Core Duo T2050&/td&&td&AMD Athlon64 X2 4400+&/td&&/tr&&tr&&td align=middle&主板&/td&&td&ATI Radeon Xpress 1100&/td&&td&NVIDIA NF6100&/td&&/tr&&tr&&td align=middle&内存&/td&&td&威刚2GB(2根1GB)&/td&&td&金士顿2GB&/td&&/tr&&tr&&td align=middle&显卡&/td&&td&集成X1200显示核心&/td&&td&256MB 9600GSO独立显卡&/td&&/tr&&tr&&td align=middle&硬盘&/td&&td&希捷80GB&/td&&td&希捷250GB&/td&&/tr&&/tbody&&/table&  为了保证测试更接近多数读者的使用环境,优先选择了两台普通读者常用的平台(这两台电脑在Windows XP系统下使用一直很稳定),以期验证各类软件能否在Windows 7中正常安装、使用和卸载。且使用两台配置不同的电脑可尽量保证测试的准确性,当一个硬件或程序在两台电脑皆出现问题,则标明完全不兼容或无法运行,一台电脑出现问题则进行验证以排除无法使用的原因,没有出现问题的则表明完全兼容。Windows 7能对各类常用应用软件保持良好的兼容性吗?  &strong&1、杀毒软件&/strong&  杀毒软件是操作系统的必需,杀毒软件是为系统保驾护航的重要工具,安装好操作系统后最先安装的就是这类软件。为了确保Windows 7能与各种杀毒软件兼容,目前为止,微软已为Windows 7指定了16家杀毒软件厂商。这些厂商的新版本杀毒软件可确认是与Windows 7兼容的。&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&微软推荐Windows 7兼容杀毒软件   为此,笔者选用了没在列的国内常见的两家厂商的杀毒软件进行测试:金山毒霸极速版、江民杀毒软件KV2009标准版。&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 杀毒软件是最先安装的软件之一   测试结果表明:江民杀毒软件KV2009标准版在两台电脑上安装运行正常;金山毒霸极速版在台式机上安装运行正常,但在测试笔记本电脑上却出现无法安装的异常状况(一点击安装程序系统便花屏并自动重启电脑),为此笔者参考了微软的说明:“在安装杀毒软件前要确认计算机上没有安装其他杀毒软件,如果有的话要将其删除然后再安装新的杀毒软件,否则可能会引起不良后果。”在卸载掉Windows XP中安装的原有的金山毒霸杀毒软件后,问题依旧。为此,笔者又在第三台安装有Windows 7系统的电脑上安装该软件,一切正常,看样子这台电脑在Windows 7系统兼容性方面存在特别问题。&/p&  &strong&2、办公软件&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 微软自家的Office 2000还是可以兼容的   安装测试结果表明,微软Office 等常见办公软件与Windows 7完全兼容,但这类与Vista就能良好兼容的主流软件显然不能测试出Windows 7兼容状况,为此笔者选用了更古老的Office 2000进行测试,该版本于1999年就已推出,测试表明,该软件在Windows 7下安装使用完全正常。另一款常见的办公软件金山WPS Office 2009在Windows 7下安装使用亦完全正常。&/p&  尽管微软Office 2010 目前只是Beta版,但在Windows 7系统下运行正常。&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&微软Office 2010   &strong&3、工具软件&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 常见工具软件测试   笔者选用了各类最具代表性的工具软件进行测试——PC基本工具软件DirectX 9,在Windows 7下安装使用正常;硬件检测软件EVEREST Ultimate Edition 5.02 Final运行正常,较早版本的该软件在笔记本平台上出现了蓝屏死机;硬件工具HD Tune Pro运行正常;CPU-Z/GPU-Z运行正常;随身U盘硬件测试软件3DMARK运行正常;WinRAR3.90安装运行正常;Foxmail运行收发正常;QQ2009运行正常,更不用说新版本了;YY(多玩歪歪)运行正常;新浪UC运行正常;平面工具软件CorelDRAW 12运行正常……。&/p&  这些软件除了一些硬件测试工具,另外就是必备常用的压缩解压缩工具,以及聊天工具等。其中硬件系统测试工具以及行业软件更新并不频繁,这些主要应用于企业,所以针对部署于Windows 7平台可能尚未准备充分,目前不建议行业专属软件应用Windows 7系统。聊天工具除了用户量最大的QQ,还有一些在线的视频聊天室工具,这些软件更新速度很快,目前已经完全兼容Windows 7系统。&/p&&strong&4、播放软件&/strong&  播放器是我们常用的娱乐工具之一,除了本地视频文件的播放,我们还会经常使用一些在线网络电视看一些直播。这里我们选择了一些主流和次主流的视频播放软件在Windows 7系统下,进行了安装使用,均能够正常运行。&/p&&table border=0 cellSpacing=1 cellPadding=6 width=580 align=center&&tbody&&tr&&td width=90 align=middle& 软件名称&/td&&td width=180&软件版本&/td&&td width=180&软件大小&/td&&td width=180&Windows 7兼容性&/td&&/tr&&tr&&td align=middle&暴风影音&/td&&td&2009&/td&&td&21.9MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&PowerDVD&/td&&td&9&/td&&td&135 MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&超级解霸10&/td&&td&10Beta&/td&&td&15.3MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&PPLive&/td&&td&2.3.3正式版&/td&&td&8MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&PPS&/td&&td&2.6.86.8900&/td&&td&4.96MB&/td&&td&通过&/td&&/tr&&/tbody&&/table&  &strong&5、P2P下载软件&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&easyMule(电驴)   P2P下载工具可以说也是琳琅满目,并且其技术上已经非常成熟,在下载工具领域,迅雷、快车、QQ旋风都已经支持多协议下载,可以说各有优点。而VeryCD、BitComet等都是针对各自下载属性拥有自己的忠实用户。由于这些常用工具拥有巨大的用户群,其版本都在不断的更新,所以,对于 Windows 7系统的支持也是紧跟,经过一些常用下载工具的安装测试,在Windows 7系统下,都正常通过。&/p&&table border=0 cellSpacing=1 cellPadding=6 width=580 align=center&&tbody&&tr&&td width=90 align=middle&软件名称&/td&&td width=180&软件版本&/td&&td width=180&软件大小&/td&&td width=180&Windows 7兼容性&/td&&/tr&&tr&&td align=middle&VeryCD&/td&&td&1.1.10正式版&/td&&td&3.93MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&BitComet&/td&&td&1.14&/td&&td&5.63MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&迅雷&/td&&td&5.9.7.1062&/td&&td&10MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&快车&/td&&td&V3.2 正式版&/td&&td&8661KB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&比特精灵&/td&&td&v3.6.0.200&/td&&td&2.23MB&/td&&td&通过&/td&&/tr&&tr&&td align=middle&QQ旋风&/td&&td&V2.1 Beta4&/td&&td&5.52MB&/td&&td&通过&/td&&/tr&&/tbody&&/table&  &strong&6、网银软件&/strong&  Vista与网银的兼容性上做得很差,在早期的测试版中,很多用户也反映Windows 7与网银很多软件/控件不兼容,而随着Windows 7的不断更新,微软宣称Windows 7目前已经与中国建设银行、中国工商银行、招商银行、上海浦东发展银行个人网银系统实现完全兼容。&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图5 安装控件后多数网银都能在Windows 7下正常使用   我们随便挑选了建行的网银做测试,发现其不需要安装任何控件便能直接使用,确实已做到和Windows 7的完全兼容。支付宝则需要下载EXE安装包(下载支付宝首页的安全控件)才能正常访问支付宝。而随机挑选的交通银行网银,亦需要象XP下一样安装控件才能直接使用。它们的使用情况都很正常,其对网银的兼容性高于Vista,接近于XP。&/p& &strong& 7、小结&/strong&  测试表明,绝大多数在Windows XP/Vista上能正常运行的软件在Windows 7中亦能正常运行。 &table border=0 cellSpacing=0 cellPadding=0 align=left&&tbody&&tr&&td vAlign=top&&/td&&/tr&&tr&&td&&/td&&/tr&&/tbody&&/table&一些软件的老版本不能在Windows 7下正常运行,将其更新为新版本后一般也能正常运行。并且,测试得出结论:沿自Windows XP的Windows 7的程序“兼容性标签”已属“鸡肋”,凡是不能直接运行的程序,即使是使用该选项进行对应设置,一样的不能运行。&/p&  &strong&二、常见游戏的测试&/strong&  游戏是软件的一部分,对于很多电脑用户来说,游戏是大家使用电脑进行娱乐的主要手段,为此Windows 7对游戏的兼容性便成为了游戏玩家关注的焦点,为了更好的验证Windows 7对游戏的兼容性,我们除了选择数款热门的游戏进行测试,还特别对一些经典老游戏进行了测试。&/p& &strong& 1、主流游戏测试&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 《魔兽世界》测试正常   《魔兽世界》是全球第一网游,其在国内的玩家群也非常庞大。测试结果表明,Windows 7对其保持了良好的兼容性,硬盘版的《魔兽世界》无论拷贝到笔记本电脑还是台式机测试平台上都能正常运行,其运行速度及状态和Windows XP下并无二样。&/p&  《魔兽争霸3》是一款著名的单机游戏,测试结果表明,Windows 7对其保持了良好的兼容性,硬盘版的《魔兽争霸3》无论在笔记本还是台式机的Windows 7测试平台上都能正常运行,其运行速度和状态和Windows XP下完全一样。&/p&  《命令与征服》是著名的系列单机游戏,测试结果表明,Windows 7对其保持了良好的兼容性,硬盘版的《命令与征服:将军》无论在笔记本还是台式机测试平台上都能正常运行,其运行速度和状态和Windows XP下并无二样。并且,为了更好的验证Windows 7的兼容性,笔者特别选择了著名的《Red Alert》Windows 95版进行测试,在Windows 7下能直接运行该游戏,运行状态正常,但显示效果不佳。&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 新老《极品飞车》测试正常   《极品飞车》是著名的系列赛车游戏,测试结果表明,Windows 7对其保持了良好的兼容性,极品飞车10/11无论在笔记本还是台式机测试平台上都能正常运行,其运行速度和状态和Windows XP下并无二样。并且,为了更好的验证Windows 7的兼容性,笔者特别选择了更老的《极品飞车3》等版本进行测试,测试结果表明运行正常,与XP下无二。&/p&&strong&2、老游戏测试&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&strong&&/strong&&/td&&/tr&&/tbody&&/table&&br&图 DUNE2000画面有些问题   为了重点测试Windows 7这个新系统对游戏的兼容性,老游戏是最好选择。《美女卡丁车》,运行正常;QQ游戏,运行正常;《DUNE2000》硬盘版,能正常进入游戏,但游戏画面左移,不能正常游戏;《抢滩登陆2002》,运行正常;《三国群英传2》,运行正常;《暴力摩托》运行正常,但画面有屏闪,同样的硬件平台操控性比Windows XP下要好;《剑侠情缘外传-月影传说》不能正常运行;《三角洲特种部队2/3》,运行正常……&/p&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 Windows 7也能让网友重温儿时的梦   除此而外,我们也对很多读者爱玩的一些老的游戏模拟器进行了测试。古老的Gens V0.98(世嘉五代模拟器)版本不能正常运行,画面破碎死机自动重启,更新为Gens V2.14版本后运行正常;较老的SMYNES V1.15版本(FC红白机模拟器)运行正常,V1.20中文版更不用说了;1998年就已推出的Callus win95 V0.42版本(街机模拟器),运行正常,与在Windows XP及更老操作系统下运行并没两样。&/p&  &strong&3、小结&/strong&  Windows 7对各种常见游戏软件保持了良好的兼容性,除了已经尘封的DOS游戏,从《魔兽世界》到《孤岛惊魂》,市面上95%以上的Windows游戏都能在Windows 7上正常运行。测试表明,Windows 7在兼具新特性的同时,同样保持了良好的兼容性,其对新老游戏的兼容性比Vista更好,已接近于Windows XP。&/p&  &strong&三、后记,Windows 7时代正悄然到来&/strong&&table border=0 cellSpacing=0 cellPadding=0&&tbody&&tr&&td&&/td&&/tr&&/tbody&&/table&&br&图 蓝屏异常关机,Windows 7仍面临各种运行环境的苛刻考验   通过连续数天一系列的测试表明,目前RTM版本的Windows 7已具备良好的兼容性,它可以对市面上几乎95%的在用软件及游戏提供兼容。而随着Windows 7正式版的推出,及后期Service Pack补丁包的不断修正与更新,凭借较低的硬件需求,相信Windows 7有望成为替代Windows XP的新一代主流操作系统,这将水到渠成。当然,对于多数读者来说,笔者仍不推荐您格式化掉原有的Windows XP系统而一步跨入Windows 7的怀抱,在短期内,“温新不忘旧”,Windows XP和Windows 7双系统并存,将成为多数网友硬盘中的一道亮丽风景。&/p&
请登录后再发表评论!当前访客身份:游客 [
coding中...
:引用来自“Brin想写程序”的评论Possible soluti...
:引用来自“Brin想写程序”的评论Possible soluti...
:引用来自“Brin想写程序”的评论Possible soluti...
:引用来自“江鸟”的评论 引用来自“Brin想写程序...
:引用来自“江鸟”的评论 引用来自“Brin想写程序...
:引用来自“江鸟”的评论 引用来自“Brin想写程序...
:引用来自“江鸟”的评论我们最初遇到这样问题是o...
:引用来自“Brin想写程序”的评论 引用来自“cxz...
:我们最初遇到这样问题是osd比较少时候(不到20)...
:引用来自“罗兴峰”的评论这样的ceph就没法用了哦...
今日访问:0
昨日访问:18
本周访问:39
本月访问:1955
所有访问:17283
列表模式: |
项目的推进必须有一种推动方式,这种推动方式是通过超短期目标来实现的,有效的项目管理,这种短期目标甚至可以规定到小时的级别,这个小时干什么,下个小时做什么都可以制定到项目计划里面。实际工作中,如果能把任务精确到天,那么这个项目的推进就已经是非常之高效的了。
而在敏捷方法论中,不同的具体方法强调不同的项目驱动方式,比如用例驱动开发,测试驱动开发,需求驱动开发等等。在宣传自己具体的项目管理方法时候,各种具体方法都在强调自己的驱动力是万能的,可以作为核心驱动力来把握。以TDD测试驱动为例,很多信仰测试驱动的项目经理,恨不得把所有东西都抽象为单元测试,但是用户需求和单元测试之间存在大量的系统设计工作,在把复杂的用户需求抽象提取设计为的可以进行单元测试的测试用例的过程中会遇到大量的难以逾越的困难,从而导致测试驱动变成了纸上谈兵。
在敏捷过程最为推荐的测试驱动,在我们单位的开发工作中也会碰到特别情况,因为我们在单位的开发工作,都是在日常运维工作的间隙中进行的,虽然都是为了单位工作,但是具体的开发流程更类似于“义务劳动”,是出于责任感和为业务部门排忧解难的职责才进行的开发工作,属于没有强有力制度下的“人情”项目管理,而这种没有强有力制度下的“人情”的测试驱动,很难做到大公司那样规范和苛刻,所以实际开发中我们搞的是非正式的记录的测试用例。一个文本文件,专门用来测试的素材,脑中形成的测试方案。讨论时,随手用简单的A4纸记录,订书机订好备用。
在软件开发实践中,我们通过对项目的迭代划分,在不同的迭代过程试用不同的驱动方法:
在项目启动阶段,设计驱动,大致划分模块,分别编写支撑模块的主干核心代码;
在执行阶段,采用接口驱动方法,精确设计模块之间的接口,驱散设计模型中的云雾,让系统的设计形式化,程序化,确定化;
在实现阶段,需要具体业务需求,才能进一步精华系统,破除接口的设计杂质,于是我们用需求用例驱动开发。
下一个阶段,为了追求的质量,测试驱动开发。
不同阶段,都有不同的驱动力。不能生搬硬套,没有一种驱动力是贯穿整个项目的生命周期的。
还有最后的一个阶段的驱动,则用户驱动。根据用户的需求,做一些表面上的修改。
这个特色阶段,当然对系统架构也提出了非常高的要求,首先就是将系统业务和显示进行尽可能的分离,在设计时采用大量Facade和Mediator设计模式,进行略显与多余的隔离。
发布于 6个月前,
阅读(92) | 评论(0) |
投票(0) | 收藏(5)
结合自己十多年软件开发的经验,希望能简单总结一下在软件开发过程中,对以测试为代表的软件质量保证活动,进行一点不太精确的经验方面的研讨。
测试是保证软件质量的最有效,而且是最直接的手段。测试首先制定详细的测试计划,编写完备的测试用例,执行测试用例,收集结果,整理测试报告,提交反馈,缺陷追踪和管理,回归测试。通过流程要质量,通过流程的执行把软件的缺陷降低到一个可接受的程度,是测试活动的根本目的。通过几天的学习,对这些基本流程和测试思路又在思想中进行了一番整理和归纳。对软件测试的相关知识的理解又做了进一步的加深。
但是这种头痛医头脚痛医脚的测试测试工作,往往让我们对着层出不穷的缺陷,疲于奔命。在日常的工作中,在我们项目的实施阶段,往往才是真正的测试阶段,各种的井喷一样的涌出,让实施工作寸步难行,不停的补丁,改代码,又引入新缺陷,整个工作奔向了没有收敛的方向。在冲破了一个又一个项目的之后,领导和我们一起向缺陷妥协,将一个又一个半成品推向了客户。一方面,固然有项目承建企业的不负责任和项目资金和时间的投入不足,另一方面,寻找可以有效的提高软件项目质量的方法论,其实也是作为可以一起探讨的话题。
软件的开发中,为了提高软件质量,在主流的敏捷方法里面,推崇“测试”驱动开发的软件开发方法,用一个有一个的测试用例提高软件质量。让测试先行,实现了测试用例,然后把测试用例的代码进行重构,在重构中形成软件。这种方法,已经被广大企业,被证明为合适有效的开发方法。但是,由于我们单位的性质,可能很多软件不能从头进行开发,我们的工程师,被项目承建企业限制,不能参与其项目源代码的修改和编写。
组件化是一种大家早已达成共识的软件构架思路,而软件的组件是通过测试的成型中间件。对于成熟的组件,可以不用进行复杂的测试流程,只需要针对接口做接口测试,并且在整个项目中做集成测试即可。使用组件,一方面是复用了代码,另一方面也是复用了质量。正如,我们测试一个应用软件,不会顺便也把运行这个软件的操作系统也测一遍一样,软件的有些部分是可以不用进行测试的。
在我们的软件设计和项目实施的过程中,强调对于成熟组件的使用,可以极大的提高软件的质量,简化测试的工作量。但是,组件的应用并不是轻易就能融入到现有系统当中的,组件需要自己运行的生态环境,这种环境,也就是我们常说的平台框架,但是往往是现有组件,后有的框架,因此,不可避免的需要对组件的接口进行调整和修改,以适应现有的框架。这种针对接口的修改,在设计模式方面,常常采用模式、模式和模式,但是这种模式结构,也不可避免的涉及到程序方面的修改。接口的参数传递,往往出现跨编程语言的情况,此时问题就非常复杂,需要测试和验证的点也非常之多。
在很早以前,软件接口方面,等权威机构都提出了流的概念,来实现模块接口的跨语言交互。而在民间的组织里面,大家采用的是的文件概念进行接口的封装,另一方面等偏学术相关的组织,推崇的是套接字的概念进行接口的封装。但是总之,在接口传递的东西,都是无复杂结构的串结构,体现在程序上也就是类型数组。
对于组件结构的框架,我们常用的有环境(和),环境的体系结构,在其他商业系统方面也有和体系结构,移动端的和也是组件运行环境的代名词。
但是这些标准和规范,都是针对于功能的,而我们的系统是针对于业务进行的开发,这些技术的优点和特征,我们很难直接使用,如果直接使用,也是需要大量的编程开发工作,将系统组件整合为业务,测试和质量保证的挑战依然存在。因此,可以借鉴这些功能方面的设计思路,我们从业务出发,深入到我们单位具体的业务流程和工作的特点,对于业务流程进行划分和抽象分析,把待建设的业务系统,从概念上划分为几个业务组件,全局的来看各个业务系统的研发工作,找到其中的相同业务特征,统一开发,在不同系统中复用同一个业务组件,从而降低开发难度,提高软件质量。
比如在我们部门两个项目里面,对于文件的上传和下载的业务场景,其实可以用同一种组件;而对于上传过后的文件的生命周期记录和管理,其实也可以用同构的数据库进行管理;对于文件在各个存储节点的迁移,也可以用同一种组件;对于视频的转码,也可以用同一种转码平台软件。而针对两个项目的具体的业务场景,不同的地方,在投入精力和资金进行研发,这样一方面提高的效率,另一个方面,质量也得到了更好的保证,经济效益方面也肯定有非常大的优势。
从上文可以看到,组件需要专门的运行组件的平台和框架,但是现在我们往往只有类似于、这种针对于功能的组件化平台,缺乏针对于媒体具体业务的平台框架。因此,设计针对于业务的组件运行的环境,也是实施组件化的设计的一项重要工作。一个框架,如果真正的被用起来,变成有效的框架,首先第一位的要点就是低耦合,无侵入性的,也就是说,作为一个第三方的组件,需要尽可能少的修改,甚至不修改就能快速融入这个框架。通过上文对于、和等环境框架的设计,我认为框架的接口也应该是串结构,也就是数组。在我们部门的实际业务中,在很多地方采用了目录监控机制,进行不同系统之间的信息传递,这种被我们称作的机制和软件,成为我们部门最有效的一种项目实施的方法。这种通过文件系统传递指令,文件内容就是详细信息的组件传递方式,就是这种串结构的一种实现。
设计平台框架的时候,应当以串为最基本的信息传递手段,负责传递的平台,不需要解析和理解传递信息的内容,只要将这个串送达,需要接受的模块即可。以上是我一点看法,关于具体的框架设计,希望能跟同事们做更加深入的探讨。
通过组件框架的结构,复用成熟软件,减少自定义开发带来的质量保证工作,个人认为是最有效的提升软件项目质量的手段。
发布于 6个月前,
阅读(105) | 评论(0) |
投票(0) | 收藏(1)
今天硬盘空间不足了,vs2010太大了,于是卸载掉。换mingw32。。
结果更换完毕后发现cunit用不了。。于是重新安装了一下。
发现网上几乎没有正确的安装文档,我先简单记录一下,然后再整理个详细的。
首先,安装mingw32要把autoconf等相关工具安装上。
然后在msys的终端中配置。
首先 ,第一步运行下libtoolize命令,补下ltmain.sh
然后运行automake --add-missing 作用是补下其他的丢的文件夹
然后是运行autoreconf。。因为cunit自带的automake的脚本版本与msys不一致,所以要autoreconf,但是如果不补齐上面的东西,autoreconf就无法执行。。
终于可以运行./configure --prefix=/mingw
然后是make
最后是make install
libtoolize
automake&--add-missing&
autoreconf
./configure&--prefix=/mingw
make&install
发布于 1年前,
阅读(318) | 评论(0) |
投票(0) | 收藏(0)
&&&&所谓数据驱动型的网站,其实就是常见的MIS系统在B/S形式下的实现。B/S模式在90年年代末大量出现的时候,其主要特征是Page-Based,也就是基于页面的。因为Html技术的网站本身是一张一张的页面组成的内容展示工具。对于MIS系统的比较复杂的高速交互式的操作,用本质上不是非常兼容。
从1995年到2005年的十年间,所有人都在与两大不兼容问题进行斗争,编写了无数无任何意义的代码,尤其是以Java最为甚。
第一个不兼容是ORM,也就是关系对象映射,95年以后,是面向对象程序设计大行其道的时候,Java也是标榜自己的原生的面向对象特质。但是,MIS系统操作的数据,是关系型数据库,其存储在数据库中的数据形式,是以表为形式的。所以绝大多数Java的项目,都将表直接映射为一个对象,对象里面只有get和set方法,这种对象呗成为POJO(Plain Old Java Object),也就是贫血的老旧的Java对象,然后所谓的海量的DAO代码,不断的将各种表对应到POJO的对象当中。
后来出现了hibernate,通过xml配置,将对象和表进行了所谓的快速绑定。
但是hibernate存在两个问题,导致其使用非常受限。
首先hibernate的性能极差,使用hibernate的Java项目的性能会下降十倍左右,而且hibernate采用反射的方式构造POJO对象,POJO对象的特征是大量的产生大量的销毁,在一个用户一次网页的数据访问过程中,至少会生成10个POJO对象,如果一个500并发的小型业务系统正常运行1个月,将会用反射创建13亿个POJO对象。而Sun的Java虚拟机存在一个特性,其系统容纳的类的信息,在运行时,都放在permGen内存区域当中,有一个类,占据permGen一点数据,而在反射的时候,其实是现场编写了一个新的类(反射代理类),所以每一次反射,就会占据PermGen的内存的一小块空间。假设一个代理类只占一个字节,13亿个对象,也就会永远占据1.3G的内存。虽然可以通过调整JVM的permGen内存大小的方式,保证系统能多运行一会,但是在正常的业务系统中,平均1到2个月的宕机几乎是无法避免的。
其次,hibernate的关系映射并不完全覆盖掉所有的关系型数据库提供的功能,很多关系型数据库提供的功能,在hibernate的对象关系型映射,其中并没有充分的实现,很多复杂的SQL几乎不可能改写为hibernate的HSQL和关系映射。所以不可避免的在存在hibernate的系统中,容纳非常多的jdbc直接读写数据库的代码。容易造成事务性和代码维护的困难。
第二个不兼容,也就是业务系统的需求和网页这种交互形式的不兼容。传统的html网页,并没有提供充分的交互能力,所以采用B/S模式的MIS系统,缺乏真正的得到用户赞赏的案例,在日本,大家用的Excel实现业务的功能,在欧洲,SAP的客户端软件大行其道。用网页做的业务系统,经常被诟病为打开慢,没反应,不人性化。根本原因就是交互的时候页面通过form不断的提交,刷新,不符合人们心里对软件系统的预期。
在客户端里面轻松实现的Excel式表格操作,Word式排版,公式,复制粘贴,报表,打印调整,实现都非常困难,实现了也只是一个样子,应付用户的初期审查。
这次的项目,我们也是针对这两个问题,奋战不息。
其实,在解决这个矛盾的过程中,其实微软的C#,早在2003年就找到了相对正确的解决方案。
微软基本思路如下:
不对面向对象进行生搬硬套,用ADO对象的DataSet来处理表,表就是表,没有必要转化为对象进行处理。
交互方面,采用大数据量的view_state隐藏字段,尽可能的本地响应用户的操作,尽量模拟用户在桌面端的体验。但是由于当时还没有Ajax技术,这种提升效果有限。
而Java社区,没有很好的处理好这两个问题,导致很多Java的市场份额,被PHP占据。PHP主要就是在数据绑定方面,直接将表的暴漏给前端,然后用模板的方式进行解析和组装。交互方面基本放弃了MIS系统的开发,全面转向内容型的互联网服务。
项目的模式
Java的项目目前主要有三种开发模式
1.采用三层架构,用Spring+ORM中间件+前端框架实现业务系统。这种开发模式的有点是代码非常面向对象,便于管理,容易阅读,功能清晰。缺点是性能极差,学习成本比较固定,上手需要3个月左右,需要比较系统的培训,受限于系统特性,导致功能比较弱,用户使用感觉不流畅。对于事务管理方面,粒度太低,要么就都加事务,要么都不加,虽然可以配置但是配置文件非常复杂。大多数Java的项目都是如此开发的,多数都实际上失败,缺乏用户的足够好评。
2.采用Servlet,Servlet直接使用JDBC,因为原生的JDBC进行ORM非常复杂,会产生大量的冗余代码,但是开发成本低,学习曲线低,开发的系统非常稳定。实现的功能往往比较强大。少数成功的Java项目,都是采用这种模式进行开发的。
3.第三种模式,参考微软的思路,不采用面向对象来映射数据,而是直接将表暴漏给前端。这种的问题是只适合实现内容管理的MIS系统,而且Java社区,对此思路嗤之以鼻,因此几乎没有这种实现组件,如果用Java实现此模式,就要实现一个Java版本的.net Framework的数据连接组件部分。
这次的项目,主要选择了第二种模式,项目启动阶段,主要考虑到我们人员对Java了解不是很多,如果直接用第一种模式,需要大家先放下所有工作,去从Struts,Spring,Hibernate进行学习,如果学习到独立开发阶段,乐观至少需要1到2个月的时间。学习的主要内容是配置文件的思路。而且在开发时,由于大家都依赖于两个配置文件。在协同过程中Struts.xml, applicationContext.xml不可避免的发生冲突。
第三种模式,走不通是是因为开始的时候需求并不明确,不能完全确认这个系统就是对表的操作,而且实现ADO的组件难度非常大,项目风险非常高。
因此,选择了麻烦而又稳妥的第二条道路。
发布于 1年前,
阅读(244) | 评论(2) |
投票(1) | 收藏(14)
很多有效的业务系统中,采用了传说中万能的dirwatch解决方案,所以讨论在java下的对目录下的文件监控是挺有意义的事情。
WatchService里面提供了对文件夹监控的标准接口WatchService,但是这个接口只提供了Delete,Modify和Create三种事件的监控。
之前,我们一直使用的JNotify,也是只提供了这几个接口事件。
如果我们在Java的网站中,对用户刚刚上传完毕的文件进行立即处理的情况下, 应对对文件的完整性进行确认。
WatchService里面提供给我们的三个事件,是否能让我们判断这个文件是否完整呢?
我写了一个测试用例,代码如下:
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
import&com.kamike.message.FsWatchS
&*&@author&THiNk
public&class&FsWatch&{
&&&&&*&@param&args&the&command&line&arguments
&&&&public&static&void&main(String[]&args)&{
&&&&&&&&//&TODO&code&application&logic&here
&&&&&&&&FsWatchService.start(&D:\\temp\\&);
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&java.nio.file.P
import&java.util.ArrayL
import&java.util.C
import&java.util.L
public&class&PathEvents&{
&&&&private&final&List&PathEvent&&pathEvents&=&new&ArrayList&PathEvent&();
&&&&private&final&Path&watchedD
&&&&private&final&boolean&isV
&&&&PathEvents(boolean&valid,&Path&watchedDirectory)&{
&&&&&&&&isValid&=&
&&&&&&&&this.watchedDirectory&=&watchedD
&&&&public&boolean&isValid(){
&&&&&&&&return&isV
&&&&public&Path&getWatchedDirectory(){
&&&&&&&&return&watchedD
&&&&public&List&PathEvent&&getEvents()&{
&&&&&&&&return&Collections.unmodifiableList(pathEvents);
&&&&public&void&add(PathEvent&pathEvent)&{
&&&&&&&&pathEvents.add(pathEvent);
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&java.nio.file.P
import&java.nio.file.WatchE
&*&@author&THiNk
public&class&PathEvent&{
&&&&private&final&Path&eventT
&&&&private&final&WatchEvent.Kind&
&&&&PathEvent(Path&eventTarget,&WatchEvent.Kind&type)&{
&&&&&&&&this.eventTarget&=&eventT
&&&&&&&&this.type&=&
&&&&public&Path&getEventTarget()&{
&&&&&&&&return&eventT
&&&&public&WatchEvent.Kind&getType()&{
&&&&&&&&return&
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&mon.base.F
import&java.io.IOE
import&java.nio.file.FileVisitR
import&java.nio.file.P
import&java.nio.file.SimpleFileV
import&java.nio.file.attribute.BasicFileA
&*&@author&THiNk
public&class&FunctionVisitor&extends&SimpleFileVisitor&Path&&{
&&&&Function&Path,FileVisitResult&&pathF
&&&&public&FunctionVisitor(Function&Path,&FileVisitResult&&pathFunction)&{
&&&&&&&&this.pathFunction&=&pathF
&&&&@Override
&&&&public&FileVisitResult&visitFile(Path&file,&BasicFileAttributes&attrs)&throws&IOException&{
&&&&&&&&return&pathFunction.apply(file);
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&mon.eventbus.EventB
import&java.io.IOE
import&java.nio.file.FileS
import&java.nio.file.FileVisitR
import&java.nio.file.F
import&java.nio.file.P
import&java.nio.file.SimpleFileV
import&static&java.nio.file.StandardWatchEventKinds.ENTRY_CREATE;
import&static&java.nio.file.StandardWatchEventKinds.ENTRY_DELETE;
import&static&java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import&java.nio.file.WatchE
import&java.nio.file.WatchK
import&java.nio.file.WatchS
import&java.nio.file.attribute.BasicFileA
import&java.util.L
import&java.util.O
import&java.util.concurrent.C
import&java.util.concurrent.ExecutionE
import&java.util.concurrent.FutureT
import&java.util.concurrent.TimeU
import&java.util.logging.L
import&java.util.logging.L
&*&@author&THiNk
public&class&FsWatcher&{
&&&&private&FutureTask&Integer&&watchT
&&&&private&EventBus&eventB
&&&&private&WatchService&watchS
&&&&private&volatile&boolean&keepWatching&=&
&&&&private&Path&startP
&&&&public&FsWatcher(EventBus&eventBus,&Path&startPath)&{
&&&&&&&&this.eventBus&=&Objects.requireNonNull(eventBus);
&&&&&&&&this.startPath&=&Objects.requireNonNull(startPath);
&&&&public&void&start()&throws&IOException&{
&&&&&&&&initWatchService();
&&&&&&&&registerDirectories();
&&&&&&&&createWatchTask();
&&&&&&&&startWatching();
&&&&public&boolean&isRunning()&{
&&&&&&&&return&watchTask&!=&null&&&&!watchTask.isDone();
&&&&public&void&stop()&{
&&&&&&&&keepWatching&=&
&&&&public&void&close()
&&&&&&&&try&{
&&&&&&&&&&&&this.stop();
&&&&&&&&&&&&this.watchService.close();
&&&&&&&&}&catch&(IOException&ex)&{
&&&&&&&&&&&&Logger.getLogger(FsWatcher.class.getName()).log(Level.SEVERE,&null,&ex);
&&&//Used&for&testing&purposes
&&&Integer&getEventCount()&{
&&&&&&&&try&{
&&&&&&&&&&&&return&watchTask.get();
&&&&&&&&}&catch&(InterruptedException&e)&{
&&&&&&&&&&&&throw&new&RuntimeException(e);
&&&&&&&&}&catch&(ExecutionException&ex)&{
&&&&&&&&&&&&&throw&new&RuntimeException(ex);
&&&&private&void&createWatchTask()&{
&&&&&&&&watchTask&=&new&FutureTask&Integer&(new&Callable&Integer&()&{
&&&&&&&&&&&&private&int&totalEventC
&&&&&&&&&&&&
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&Integer&call()&throws&Exception&{
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&while&(keepWatching)&{
&&&&&&&&&&&&&&&&&&&&WatchKey&watchKey&=&watchService.poll(10,&TimeUnit.SECONDS);
&&&&&&&&&&&&&&&&&&&&if&(watchKey&!=&null)&{
&&&&&&&&&&&&&&&&&&&&&&&&List&WatchEvent&?&&&events&=&watchKey.pollEvents();
&&&&&&&&&&&&&&&&&&&&&&&&Path&watched&=&(Path)&watchKey.watchable();
//&&&&&&&&&&&&&&&&&&&&&&&&PathEvents&pathEvents&=&new&PathEvents(watchKey.isValid(),&watched);
//&&&&&&&&&&&&&&&&&&&&&&&&for&(WatchEvent&event&:&events)&{
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&pathEvents.add(new&PathEvent((Path)&event.context(),&event.kind()));
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&totalEventCount++;
//&&&&&&&&&&&&&&&&&&&&&&&&}
//&&&&&&&&&&&&&&&&&&&&&&&&watchKey.reset();
//&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&for(WatchEvent&event&:&events)
&&&&&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&&&&PathEvent&pathEvent=&new&PathEvent((Path)&event.context(),&event.kind());
&&&&&&&&&&&&&&&&&&&&&&&&&&&eventBus.post(pathEvent);
&&&&&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&&&&&&&&&watchKey.reset();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&return&totalEventC
&&&&&&&&&&&&}
&&&&&&&&});
&&&&private&void&startWatching()&{
&&&&&&&&new&Thread(watchTask).start();
&&&&private&void&registerDirectories()&throws&IOException&{
&&&&&&&&Files.walkFileTree(startPath,&new&WatchServiceRegisteringVisitor());
&&&&private&WatchService&initWatchService()&throws&IOException&{
&&&&&&&&if&(watchService&==&null)&{
&&&&&&&&&&&&watchService&=&FileSystems.getDefault().newWatchService();
&&&&&&&&return&watchS
&&&&private&class&WatchServiceRegisteringVisitor&extends&SimpleFileVisitor&Path&&{
&&&&&&&&@Override
&&&&&&&&public&FileVisitResult&preVisitDirectory(Path&dir,&BasicFileAttributes&attrs)&throws&IOException&{
&&&&&&&&&&&&//dir.register(watchService,&ENTRY_CREATE,&ENTRY_DELETE,&ENTRY_MODIFY);
&&&&&&&&&&&&dir.register(watchService,&ENTRY_CREATE,&ENTRY_DELETE,&ENTRY_MODIFY);
&&&&&&&&&&&&return&FileVisitResult.CONTINUE;
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&java.io.F
import&java.io.FilenameF
import&java.io.IOE
import&java.util.I
import&java.util.concurrent.C
import&java.util.concurrent.FutureT
import&java.util.concurrent.LinkedBlockingQ
import&java.util.concurrent.TimeU
import&java.util.regex.P
&*&@author&THiNk
public&class&FileDirectoryStream&{
&&&&File&startD
&&&&String&
&&&&private&LinkedBlockingQueue&File&&fileLinkedBlockingQueue&=&new&LinkedBlockingQueue&File&();
&&&&private&boolean&closed&=&
&&&&private&FutureTask&Void&&fileT
&&&&private&FilenameFilter&filenameF
&&&&public&FileDirectoryStream(String&pattern,&File&startDirectory)&{
&&&&&&&&this.pattern&=&
&&&&&&&&this.startDirectory&=&startD
&&&&&&&&this.filenameFilter&=&getFileNameFilter(pattern);
&&&&public&Iterator&File&&glob()&throws&IOException&{
&&&&&&&&confirmNotClosed();
&&&&&&&&startFileSearch(startDirectory,&filenameFilter);
&&&&&&&&return&new&Iterator&File&()&{
&&&&&&&&&&&&File&file&=&
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&boolean&hasNext()&{
&&&&&&&&&&&&&&&&try&{
&&&&&&&&&&&&&&&&&&&&file&=&fileLinkedBlockingQueue.poll();
&&&&&&&&&&&&&&&&&&&&while&(!fileTask.isDone()&&&&file&==&null)&{
&&&&&&&&&&&&&&&&&&&&&&&&file&=&fileLinkedBlockingQueue.poll(5,&TimeUnit.MILLISECONDS);
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&&&&&return&file&!=&
&&&&&&&&&&&&&&&&}&catch&(InterruptedException&e)&{
&&&&&&&&&&&&&&&&&&&&Thread.currentThread().interrupt();
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&File&next()&{
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&void&remove()&{
&&&&&&&&&&&&&&&&throw&new&UnsupportedOperationException(&Remove&not&supported&);
&&&&&&&&&&&&}
&&&&&&&&};
&&&&private&void&startFileSearch(final&File&startDirectory,&final&FilenameFilter&filenameFilter)&{
&&&&&&&&fileTask&=&new&FutureTask&Void&(new&Callable&Void&()&{
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&Void&call()&throws&Exception&{
&&&&&&&&&&&&&&&&findFiles(startDirectory,&filenameFilter);
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&});
&&&&&&&&start(fileTask);
&&&&private&void&findFiles(final&File&startDirectory,&final&FilenameFilter&filenameFilter)&{
&&&&&&&&File[]&files&=&startDirectory.listFiles(filenameFilter);
&&&&&&&&for&(File&file&:&files)&{
&&&&&&&&&&&&if&(!fileTask.isCancelled())&{
&&&&&&&&&&&&&&&&if&(file.isDirectory())&{
&&&&&&&&&&&&&&&&&&&&findFiles(file,&filenameFilter);
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&fileLinkedBlockingQueue.offer(file);
&&&&&&&&&&&&}
&&&&private&FilenameFilter&getFileNameFilter(final&String&pattern)&{
&&&&&&&&return&new&FilenameFilter()&{
&&&&&&&&&&&&Pattern&regexPattern&=&pile(pattern);
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&boolean&accept(File&dir,&String&name)&{
&&&&&&&&&&&&&&&&return&new&File(dir,&name).isDirectory()&||&regexPattern.matcher(name).matches();
&&&&&&&&&&&&}
&&&&&&&&};
&&&&public&void&close()&throws&IOException&{
&&&&&&&&if&(fileTask&!=&null)&{
&&&&&&&&&&&&fileTask.cancel(true);
&&&&&&&&fileLinkedBlockingQueue.clear();
&&&&&&&&fileLinkedBlockingQueue&=&
&&&&&&&&fileTask&=&
&&&&&&&&closed&=&
&&&&private&void&start(FutureTask&Void&&futureTask)&{
&&&&&&&&new&Thread(futureTask).start();
&&&&private&void&confirmNotClosed()&{
&&&&&&&&if&(closed)&{
&&&&&&&&&&&&throw&new&IllegalStateException(&File&Iterator&has&already&been&closed&);
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.message.
import&mon.base.F
import&java.io.IOE
import&java.nio.file.DirectoryS
import&java.nio.file.DirectoryStream.F
import&java.nio.file.FileVisitR
import&java.nio.file.F
import&java.nio.file.P
import&java.util.I
import&java.util.O
import&java.util.concurrent.C
import&java.util.concurrent.FutureT
import&java.util.concurrent.LinkedBlockingQ
import&java.util.concurrent.TimeU
&*&@author&THiNk
public&class&AsynchronousRecursiveDirectoryStream&implements&DirectoryStream&Path&&{
&&&&private&LinkedBlockingQueue&Path&&pathsBlockingQueue&=&new&LinkedBlockingQueue&Path&();
&&&&private&boolean&closed&=&
&&&&private&FutureTask&Void&&pathT
&&&&private&Path&startP
&&&&private&Filter&
&&&&public&AsynchronousRecursiveDirectoryStream(Path&startPath,&String&pattern)&throws&IOException&{
&&&&&&&&this.startPath&=&Objects.requireNonNull(startPath);
&&&&@Override
&&&&public&Iterator&Path&&iterator()&{
&&&&&&&&confirmNotClosed();
&&&&&&&&findFiles(startPath,&filter);
&&&&&&&&return&new&Iterator&Path&()&{
&&&&&&&&&&&&Path&
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&boolean&hasNext()&{
&&&&&&&&&&&&&&&&try&{
&&&&&&&&&&&&&&&&&&&&path&=&pathsBlockingQueue.poll();
&&&&&&&&&&&&&&&&&&&&while&(!pathTask.isDone()&&&&path&==&null)&{
&&&&&&&&&&&&&&&&&&&&&&&&path&=&pathsBlockingQueue.poll(5,&TimeUnit.MILLISECONDS);
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&&&&&return&(path&!=&null);
&&&&&&&&&&&&&&&&}&catch&(InterruptedException&e)&{
&&&&&&&&&&&&&&&&&&&&Thread.currentThread().interrupt();
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&Path&next()&{
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&void&remove()&{
&&&&&&&&&&&&&&&&throw&new&UnsupportedOperationException(&Removal&not&supported&);
&&&&&&&&&&&&}
&&&&&&&&};
&&&&private&void&findFiles(final&Path&startPath,&final&Filter&filter)&{
&&&&&&&&pathTask&=&new&FutureTask&Void&(new&Callable&Void&()&{
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&Void&call()&throws&Exception&{
&&&&&&&&&&&&&&&&Files.walkFileTree(startPath,&new&FunctionVisitor(getFunction(filter)));
&&&&&&&&&&&&&&&&return&
&&&&&&&&&&&&}
&&&&&&&&});
&&&&&&&&start(pathTask);
&&&&private&Function&Path,&FileVisitResult&&getFunction(final&Filter&Path&&filter)&{
&&&&&&&&return&new&Function&Path,&FileVisitResult&()&{
&&&&&&&&&&&&@Override
&&&&&&&&&&&&public&FileVisitResult&apply(Path&input)&{
&&&&&&&&&&&&&&&&try&{
&&&&&&&&&&&&&&&&&&&&if&(filter.accept(input.getFileName()))&{
&&&&&&&&&&&&&&&&&&&&&&&&pathsBlockingQueue.offer(input);
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&}&catch&(IOException&e)&{
&&&&&&&&&&&&&&&&&&&&throw&new&RuntimeException(e.getMessage());
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&return&(pathTask.isCancelled())&?&FileVisitResult.TERMINATE&:&FileVisitResult.CONTINUE;
&&&&&&&&&&&&}
&&&&&&&&};
&&&&@Override
&&&&public&void&close()&throws&IOException&{
&&&&&&&&if(pathTask&!=null){
&&&&&&&&&&&&pathTask.cancel(true);
&&&&&&&&pathsBlockingQueue.clear();
&&&&&&&&pathsBlockingQueue&=&
&&&&&&&&pathTask&=&
&&&&&&&&filter&=&
&&&&&&&&closed&=&
&&&&private&void&start(FutureTask&Void&&futureTask)&{
&&&&&&&&new&Thread(futureTask).start();
&&&&private&void&confirmNotClosed()&{
&&&&&&&&if&(closed)&{
&&&&&&&&&&&&throw&new&IllegalStateException(&DirectoryStream&has&already&been&closed&);
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.
import&mon.eventbus.AllowConcurrentE
import&mon.eventbus.S
import&com.kamike.message.fswatch.FsW
import&com.kamike.message.fswatch.PathE
import&java.io.IOE
import&java.nio.file.P
import&java.nio.file.P
import&java.util.concurrent.locks.ReentrantL
import&java.util.logging.L
import&java.util.logging.L
import&mons.io.FilenameU
&*&@author&THiNk
public&class&FsWatchService&{
&&&&private&static&FsWatcher&
&&&&private&static&volatile&ReentrantLock&lock&=&new&ReentrantLock();
&&&&public&FsWatchService()
&&&&@Subscribe
&&&&@AllowConcurrentEvents
&&&&public&&void&proc(PathEvent&event)
&&&&&&&&&try&{
&&&&&&&&&&&&Path&path&=&event.getEventTarget();
&&&&&&&&&&&&String&fileName&=&FilenameUtils.concat(&D:\\temp\\&,&path.toString());
&&&&&&&&&&&&if&(fileName.endsWith(&.aspx&))&{
&&&&&&&&&&&&&&&&String&fullPath&=&FilenameUtils.getFullPath(fileName);
&&&&&&&&&&&&&&&&String&srcName&=&FilenameUtils.getBaseName(fileName);
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&}
&&&&&&&&}&catch&(Error&e)&{
&&&&&&&&&&&&e.printStackTrace();
&&&&public&static&void&start(String&path)&{
&&&&&&&&if&(fsw&==&null)&{
&&&&&&&&&&&&lock.lock();
&&&&&&&&&&&&if&(fsw&==&null)&{
&&&&&&&&&&&&&&&&try&{
&&&&&&&&&&&&&&&&&&&&fsw&=&new&FsWatcher(EventInst.getInstance().getAsyncEventBus(),
&&&&&&&&&&&&&&&&&&&&&&&&&&&&Paths.get(path));
&&&&&&&&&&&&&&&&&&&&try&{
&&&&&&&&&&&&&&&&&&&&&&&&fsw.start();
&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&}&catch&(IOException&ex)&{
&&&&&&&&&&&&&&&&&&&&&&&&Logger.getLogger(FsWatchService.class.getName()).log(Level.SEVERE,&null,&ex);
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&}&finally&{
&&&&&&&&&&&&&&&&&&&&lock.unlock();
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&*&To&change&this&license&header,&choose&License&Headers&in&Project&Properties.
&*&To&change&this&template&file,&choose&Tools&|&Templates
&*&and&open&the&template&in&the&editor.
package&com.kamike.
import&mon.eventbus.AsyncEventB
import&mon.eventbus.EventB
import&java.util.concurrent.E
&*&@author&THiNk
public&class&EventInst&{
&&&&private&static&volatile&EventInst&eventInst&=&new&EventInst();
&&&&private&EventBus&eventB
&&&&private&AsyncEventBus&asyncEventB
&&&&private&FsWatchService&fs=new&FsWatchService();
&&&&private&EventInst()&{
&&&&&&&&eventBus=new&EventBus();
&&&&&&&&&&
&&&&&&&&asyncEventBus&=&new&AsyncEventBus(Executors.newFixedThreadPool(50));
&&&&&&&&asyncEventBus.register(fs);
&&&&public&static&EventInst&getInstance()&{
&&&&&&&&return&eventI
&&&&&*&@return&the&eventBus
&&&&public&EventBus&getEventBus()&{
&&&&&&&&return&eventB
&&&&&*&@return&the&eventBus
&&&&public&AsyncEventBus&getAsyncEventBus()&{
&&&&&&&&return&asyncEventB
通过对上面的代码的测试发现:
在Http的文件上传和文件正常拷贝过程中,会触发一次create,一次紧接着create的modify,然后一直传输,最后结束时的触发一次modify.
在真实的业务场景里面,Http的上传,往往文件非常小,最多几M,如果出现中断,用户一般会重传,所以采用记录create,modify,然后等待第二次modify的方法,可以确切的在文件传输完毕后,对第二次modify进行响应,及时进行处理。
而在ftp上传过程中,如果出现了传输中断,或者是文件拷贝过程中被用户终止,在发送这种中断时,也会触发一次modify,此时并不能判断文件是否传完。
在这种情况下,采用对第二次modify进行响应的做法,并不能准确起作用。
但是,某些断点续传功能的ftp server和传输软件(比如迅雷)会在未传输成功的文件的同一个目录下,建立.cfg文件,记录文件的传输进度,当传输成功后,这个.cfg会被删除,这种情况下,可以对这个.cfg的delete事件进行响应。
发布于 1年前,
阅读(327) | 评论(0) |
投票(0) | 收藏(1)
上篇转帖的blog里面提到了Go的特性,作为编写Java时也可以给自己点编程风格的参考。
下面是提到的改进
下面简单学习和分析一下重点的风格提示,领会Ken和Pike的编程思想:
规范的语法(不需要符号表来解析)
垃圾回收(独有)
明确的依赖
无循环依赖
常量只能是数字
int和int32是两种类型
字母大小写设置可见性(letter&case&sets&visibility)
任何类型(type)都有方法(不是类型)
没有子类型继承(不是子类)
包级别初始化以及明确的初始化顺序
文件被编译到一个包里
包package-level&globals&presented&in&any&order
没有数值类型转换(常量起辅助作用)
接口隐式实现(没有“implement”声明)
嵌入(不会提升到超类)
方法按照函数声明(没有特别的位置要求)
方法即函数
接口只有方法(没有数据)
方法通过名字匹配(而非类型)
没有构造函数和析构函数
postincrement(如++i)是状态,不是表达式
没有preincrement(i++)和predecrement
赋值不是表达式
明确赋值和函数调用中的计算顺序(没有“sequence&point”)
没有指针运算
内存一直以零值初始化
局部变量取值合法
方法中没有“this”
分段的堆栈
没有静态和其它类型的注释
内建string、slice和map
数组边界检查
常量只能是数字可以学习。在jdbc编程的时候,我们把SQL语句提成配置文件。
没有子类型继承(不是子类)少用继承
包级别初始化以及明确的初始化顺序注意静态变量和构造函数里面的初始化顺序,Java里面的顺序是和静态变量的在类里面声明的出现顺序有关系的。
文件被编译到一个包里少用别人的Jar包,减少DLL噩梦和Jar噩梦。
接口隐式实现(没有“implement”声明)适当使用Object类型,JFinal就这么做的。效率很高。
嵌入(不会提升到超类)多聚合,多组合,少继承
方法按照函数声明(没有特别的位置要求)能静态的方法就都静态化,提高效率。还有可以将静态方法放到一个工具类里面,不初始化此类,直接调用。FastJson就是这样做的。极大提高效率。
方法即函数同上
接口只有方法(没有数据)interface里面不声明数据。Java社区之前争论过很多的问题,go给出一个参考答案。
方法通过名字匹配(而非类型)这个适量使用Object前提。
没有构造函数和析构函数不要依赖构造函数,可以考虑编写init方法和destory方法,手动获取,释放链接和空间,提高效率。
postincrement(如++i)是状态,不是表达式慎用++
没有preincrement(i++)和predecrement不用++
赋值不是表达式防止最2的==和=混淆
明确赋值和函数调用中的计算顺序(没有“sequence point”)多用括号。提高计算顺序可读性
内存一直以零值初始化注意初始化的值。看情况是否要赋值初值。
方法中没有“this”哈,好东西。非常重要的提醒!!之前我在编程的时候隐隐约约觉得this不是很妥当。带来大量的歧义和隐患。
没有模板Java的模板太恶心。虽然效率低下,但是还是要使用反射构造器。。。
没有异常少用异常做处理,能预测的故障尽量写程序控制。
内建string、slice和map找一个趁手的string,map工具。没有的话,要自己写一个,我选择guava。
数组边界检查注意越界,错误。所有的直接对数组的读取之前都要判断数组里面的数值个数,千万别越界。
发布于 1年前,
阅读(230) | 评论(0) |
投票(0) | 收藏(3)
这几天java的开发,因为本身语言的问题,尤其是java泛型方面的问题,被恶心到了。
尤其是在多线程编程方面,其实线程不等价与真正运行并发数,多线程应该是队列化的,而真正的线程应该与CPU个数有关,应该作为在语言这个层次屏蔽。google的guava的eventbus的深刻体现了这一点。
在go里面的goroutine让我很感兴趣。
准备尝试下go语言。。
KamikeFast的UDP准备用go语言重写
下面的文章的最大好处,还能指导我像Go一样写Java。不用异常,多用组合等等。
而且go的语言特性,体现的C的作者们真实思想,也能让我们更好的理解C语言的使用方法。
这篇文章的几个go的特性,其实是一种编程思路。所有需要的coder们都可以学习一下。
下面转帖一篇文章:
这篇文章是Google首席工程师、Go语言之父自己整理的6月21日在旧金山给Go SF的演讲稿。Rob提到:Go语言本是以C为原型,以C++为目标设计,但最终却大相径庭。值得一提的是,这3门语言都曾当选TIOBE年度语言。
几个礼拜之前我被问到:“对于Go语言,最令你惊讶的是什么?”当时我就明确地给出了答案:“虽然我希望C++程序员能够使用Go作为替代拼,但实际上大部分Go程序员都是从Python和Ruby转过来的,其中却少有C++程序员。”
我、Ken以及Robert都曾是C++程序员,在我们编写软件时觉得应该设计一门更适合解决这个问题的编程语言。奇怪的是,其他程序员似乎却不关心。
今天我将说说是什么让我们决定创造Go语言的,及其出乎意料的结果。这里我谈的更多的会是Go而不是C++,所以即使你不懂C++也没关系。
主旨可以简单地总结为:你更同意Less is more还是Less is less?
这里有一个真实的故事。贝尔实验室中心本来分配3位数字作代号:物理搜索是111,计算科学搜索是127,以及等等。20世纪80年代,随着对搜索的进一步理解,我们认为有必要新增数位以更好地特征化工作,于是我们的中心就成了1127。
Ron Hardin半开玩笑半正经地说如果我们真的更好地理解了世界,我们已经可以去掉一个数位,把127变成27。当然,管理人员并没有相信这个玩笑,当然Ron也没指望他们会相信,但我认为这很有哲理。有时候少意味着更多,你理解得越深,就能越干练。
请记住这个想法。
回想2007年9月的时候,我正在为Google庞大的C++程序做一些比较琐碎但是核心的工作(对,就是你们都用过的那个!),我工作在Google庞大的分布式编译集群上都需要花45分钟。之后有几个C++标准委员会的Google员工为我们做了个演讲,他们给我们介绍了下C++0x(现在被叫做C++11)里会有什么新东西。
在那一个小时的演讲中,我们大概听到了约35种计划中的新特性。当然实际上还有更多,但是在那次演讲中我们只听到了35种左右。有的特性比较小,当然演讲中所提到的任何一种特性都可以称得上标志性的:有的比较精妙,但是很难理解,像右值引用(RValue Reference);其它的很有C++的特色,例如variadic模板;还有一些只是一些相当疯狂的,一如用户定义文字(user-defined literal)。
这时候,我问了自己一个问题:C++委员会真的认为C++的特性还不够多?当然,不同于Ron的玩笑,简化这门语言必是一门更大的成就!也许这很可笑,但是请把这个想法记在心里。
在那个C++演讲的几个月之前,我做了一个演讲(你可以在上看到),是关于一个我在上世纪80年代开发的玩具性的并发性语言。那个语言叫作,也就是Go的前身。
我做那个演讲是因为我在Google工作的时候忘记了一些Newsqueak里的好想法,现在回顾一下。我确信它能简化服务器端代码编写,而且对Google也有好处。
实际上我也试过把这个想法加入C++,但是失败了。把并发操作和C++控制结构整合到一起非常困难,反过来也意味着即使侥幸成功收益也会非常小。
不过C++0x的演讲让我又重新思考了一遍。新的C++内存模型使用了原子类型,这让我很困扰,我认为Ken和Robert肯定也不喜欢。感觉把这样一个如此细节的功能加入已经超负载的类型系统里并不是一个明智的选择。这看起来也很目光短浅,因为硬件也可能在接下来的十年里发生明显的变化,所以把语言和当今的硬件捆绑地太紧不见得是一个正确的选择。
演讲结束后,我们又回到了办公室。我又开始了编译工作,我转过椅子好面向Robert,然后开始问一些关键性的问题。在编译结束之前,我们说服了Ken,决定一起做一些事情。我们再也不想用C++了,同时也很希望能在写Google的代码时能用到并行性特性。“大代码”问题也是一个需要关注的问题,但我们最终决定这个问题最后再解决。
然后我们找了块白板,在上面写下希望能有哪些功能。这里我们只关注大的方面,语法和语义学这些细节性的东西先放到一边去。
之后我们在邮件上交流,这里是内容摘选:
Robert:以C语言为原型,修补部分明显的缺陷,去掉垃圾功能,添加一些缺失的功能。Rob:命名为“Go”,好处有很多,这名字非常简短,容易拼写。工具可以叫做:goc、gol、goa。如果有可交互的调试器/解释器也可以简单地叫它“Go”,后缀名用 .go。Robert:定义空接口语法:interface{}。所有接口都通过这个实现,因此可以用它代替void*。
我们没有一开始就设计出所有的功能,之后花了一年的时间才确定了array和slice功能,不过也有很多语言的特色在最初几天就已经确定下来的。
注意:Robert说要以C语言为原型,而不是C++!但实际上我们也并不是真的从C开始,只是从中借了部分内容,比如运算符、括号和几个相同的关键字。当然为了让它成为最适合我们的语言,我们从所有了解的语言里都借取了一些特性。
最后结果毫无疑问跟C或C++大不相同。以下是Go从C和C++简化的功能:
规范的语法(不需要符号表来解析)
垃圾回收(独有)
明确的依赖
无循环依赖
常量只能是数字
int和int32是两种类型
字母大小写设置可见性(letter case sets visibility)
任何类型(type)都有方法(不是类型)
没有子类型继承(不是子类)
包级别初始化以及明确的初始化顺序
文件被编译到一个包里
包package-level globals presented in any order
没有数值类型转换(常量起辅助作用)
接口隐式实现(没有“implement”声明)
嵌入(不会提升到超类)
方法按照函数声明(没有特别的位置要求)
方法即函数
接口只有方法(没有数据)
方法通过名字匹配(而非类型)
没有构造函数和析构函数
postincrement(如++i)是状态,不是表达式
没有preincrement(i++)和predecrement
赋值不是表达式
明确赋值和函数调用中的计算顺序(没有“sequence point”)
没有指针运算
内存一直以零值初始化
局部变量取值合法
方法中没有“this”
分段的堆栈
没有静态和其它类型的注释
内建string、slice和map
数组边界检查
因为有这么多功能的简化,我相信Go比C和C++更有表现力。Less can be more!
但是也不能全部丢弃。你需要把想法分为模块,例如:类型如何工作、能够实际上良好运行的语法以及有助于保证类库交互的东西。
我们也加入了一下C和C++里没有的东西,比如slice和map、复合文本(composite literal)、顶层文件表达式(这是一个大问题,但经常被忽视)、映射(reflection)、垃圾回收等等,我们还非常自然地加入了并发性。
很明显还缺少了类型层次结构,这让我很生气。
在Go语言的首次启航中,我得到了一个“我不能在没有泛型的环境下工作”的反馈,这真是一个奇怪的言论。
平心而论,我觉得他可能是因为在C++里用惯了STL的原因。从字面意思来看,这就是说着写一个int list或者string map对他来说是一个非常大的负担。我不会在这种奇怪的问题上花太长的时间,所以这种需要泛型支持的也一样。
但更重要的是,只有类型是用来解决这样的问题的,既不是多态函数(polymorphic function)也不是语言原语(language primitive)或者其它类型的帮助,只有类型!
这就是卡住我的的细节。
从C++和Java转向Go的程序员很怀念使用类型编程的方式,特别是继承和子类这样的概念。也许关于“类型”我只是一个门外汉,但我真没发现模板有什么好处。
我已故的朋友Alain Fournier曾告诉我,他认为学术工作最基本的要求就是分工。你知道吗?类型层次也只是一种分类法。你需要决定什么东西封装在什么里面,每个对象的父类型是什么?到底是A继承B还是B继承A?可排序数组究竟是用来排序的数组还是一个通过数组实现的排序器?如果你坚信类型决定设计那这个就是必须理清的问题!
我认为这是一个对于编程的荒谬的思考方式。真正重要的是这些类能为你做什么而不是它们之间是什么关系!
当然这就是Go语言里接口的关系,不过这只是部分规则,Go语言的设计理念实际上比这还要复杂得多。
如果说C++和Java是关于类的层次和分类,那么Go的核心思想就是组合(composition)。
Doug McIlroy,Unix管道原理的最终发明者,在1964年写道:
当我们需要将数据以另一种方式整合到一起时,我们需要一些类似花园里软管的方法将程序耦合在一起,这也和IO的处理方式一样。
同样Go也是这样——Go取自这一思想,但是更进一步——它就是一个组合与联结的语言。
举个例子:接口提供了组合的方式,只要实现了方法M就可以直接放在那儿,无论它是什么都会很合适。
另一个例子是关于并发性如何给我们带来独立执行计算能力。
Go有一个非常不同寻常但是很简单的类型组成方式:嵌入。这些组合技术正是Go的独特之处,与C++或者Java程序截然不同。
虽然这与Go语言的设计不是很相关,但我还是想说:Go是为大型程序设计的,需要大的团队编写和维护。
大型程序设计,通常被认为是C++和Java的领域。我认为,这只是一个历史遗留问题,或许还是一个产业事故,但普遍被认为这和面向对象设计有关。
我不赞同这个观点,大软件需要确定的理念,但强依赖管理、整洁的接口、抽象化以及优秀的文档工具这些更为重要!不幸的是,这些没一个是C++的强项(不过这点Java明显就好得多)。
当然,现在还不能确定,因为用Go语言编写的程序还不够多,但我相信Go会成为一个非常好的大型程序编程语言。时间会证明一切!
现在,回到我们讲话的中心:
为什么Go从头到尾都是以C++为目标来设计的却无法吸引到C++程序员?
Joke认为,这可能是因为Go和C++的设计理念相差甚大吧。
C++希望所有解决方案都能很容易得到/使用。我在C++11 FAQ(常见问题)上看到了这句话:
&&C++能够优美地、灵活地并且零成本地表现出抽象事物的能力,相比专门编写的代码要高效很多。
这种思考方式和Go的运转方式并不一样 。零成本不是目标,至少零CPU成本不是。Go的目标是解放程序员!
Go并没有包罗万象,你不要期待它什么都有,你也无法精确地控制每一个细节。例如:Go没有RAII,但是你可以使用一个垃圾清理器做替代,虽然你甚至无法使用内存释放函数。
你可以从Go中得到很多易于理解但是强大的工具集来组合出问题的解决方案。它跟别的语言比起来也许没有那么快或者精致,但肯定写起来更简单、读起来更容易,也更易于理解,也许还更安全。
从另一个角度看,Go肯定更加简化:
Python和Ruby程序员转向Go是因为他们不需要学更多的关心却可以获得更好的性能,甚至还可以使用并发特性。
C++程序员不愿意转向Go是因为他们竭尽全力只为了对自己的程序的完全掌控,并不希望这样改变。对于他们,软件并不仅是完成工作,而是做好工作。
现在的问题在于,如果Go成功了,会颠覆他们的世界观。
而且我们应该在一开始就注意到:对C++11新特性感兴趣的人是不会对一个功能如此简洁的语言感兴趣的,即使它能完成更多的任务。
原文链接:
发布于 1年前,
阅读(260) | 评论(4) |
投票(0) | 收藏(8)
KamikeFast已经实现了断点续传,UDP文件完整传输,已经更新到最新。
性能需要进一步调优。这个慢慢来了。或者现在可以直接改成c++了。
好麻烦,这十天的经验是。。必须先实现功能再去调优。。想当然的性能提高的技巧,都是坑。。
发布于 1年前,
阅读(79) | 评论(0) |
投票(0) | 收藏(0)
首先说明,UDP大文件传输工具库的Kamike.fast已经可以传输完整文件
花费了10天的所有业余时间,去调这个不到1000行代码。。
重写的不下十遍。。终于能穿越nat传输完整的文件,而且能自动重传丢失报文了。
现在更新一下源代码。在github上面。
目前还有一点小bug和断点续传的前序握手,还要调整。
-----------------------------------------------------------------
不过已经没时间了。开始启动下一个开源项目,这个项目不知道怎么形容,技术比较简单,纯力气活。
功能就是,上传一个excel文件,然后可以自动在数据库建立一个表格。
然后将excel文件里面的内容填入数据库中的这个表格,实现增删改查。加上排序,检索,条件过滤。
支持自定义form的模板,有点像ms的infopath的感觉。但是比较简单。
界面初步用easyui,有时间就自己做一套datagrid的ui出来,没时间就用easyui的datagrid。
此项目的deadline是3月1日。必须完成。
数据库层基于自己的kamike.db中间件,顺便提升一下kamike.db的代码质量,带动kamike.db的开发。
-------------------------------
下面是思路流水账。
参考kamike.db中间件,因为要用dynabean的思想去存储横向的一行。这一行里面的值类型应该是完全不知道。
但是为了绑定到datagrid上面。显示的值,应该就字符串就行。但是在具体编辑页面,又要读取这个信息。
所以要存在两种数据结构,一个是dataset,里面就是字符串。
另一个是detail,里面是字段列表,还有值。但是java里面没有union很讨厌。。
发布于 1年前,
阅读(172) | 评论(0) |
投票(0) | 收藏(3)
今天中午,利用休息时间,完成了这个UDP文件传输库的基本逻辑部分。
这块的代码可以拿出去见人了,估计稍微调整一下,就能实际的传输大文件了。
以后的修改将会在此基本思路的范围内扩展和测试。
目前项目的状况是基本算法完成,但是缺乏测试用例的编写。
不过UDP这种穿越NAT的测试,还需要多台无线路由器进行多层NAT的网络环境模拟,估计挺费时间。
而且下周日我要去南京参加同事的婚礼,估计要完成到正式发布开源工具的水准要一周以后了。
目前的代码已经开源到github,同样是lgpl协议。大家有兴趣的可以参考。
详细文档,估计要在完成穿越用例测试后,才能完成。
不过这个代码量很少,结构也很清楚,关键地方有中文注释,相信大家直接阅读也不会吃力。
下面介绍下目前的报文头部:
//high和low表示一个uuid,标识session
//size是要传输的文件总大小
//window是文件分块的编号
//type表示报文类型,目前分为Data数据报文,和Target控制报文
//id是报文在window分块中的子报文序号
//length表示,实际数据区的长度
//score表示在此window分块中,目前传输成功的报文数
最后,感谢@的指导
更新今天更新去掉了对guava的依赖。
发布于 1年前,
阅读(316) | 评论(1) |
投票(0) | 收藏(1)

我要回帖

更多关于 缺少casino组件lobby 的文章

 

随机推荐