amp@java

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  99 随笔 :: 0 文章 :: 228 评论 :: 0 Trackbacks

2015年2月15日 #

当年是从CSDN博客迁过来的,因为那里很不稳定,那时候这里很火的;
前段时间发现,Blogjava的登录页面居然没有验证码了,图片显示错误,无法登录,预感这个地方要凉,只好到处找替代,但没找到好用的博客,github是一个选项,但似乎不是很适合做博客。
现在终于又可以登录了,不过首页居然只剩一篇文章,我以为数据都没了,登录发现还是有的,不过太让人不放心了。
posted @ 2018-08-18 22:14 amp@java 阅读(143) | 评论 (0)编辑 收藏

 昨天下午开始,之前用得好好的USB鼠标,突然不能用了,找到个PS/2鼠标,却发现主板没有鼠标的PS/2口,只有键盘的PS/2口,真是奇葩,幸好在用的键盘是PS/2口的,费了九牛二虎之力,用键盘操作,Win+R,compmgmt.msc进入计算机管理,上下箭头移到设备管理器,发现右边的USB控制器前全是黄色叹号,尝试卸载再安装,却怎么也装不上,重新启动发现鼠标在启动Windows前还是亮灯的,但到了显示Windows徽标的时候灯就灭了,应该不是硬件问题,而是驱动问题。
为了进一步证实硬件没问题,找了个安装系统的U盘,插进去启动,能够正常使用鼠标,于是目标就聚焦在找回驱动上。
开始折腾:
1、首先是找官方驱动啊,我这电脑是老机,AMD7系列主板,找了半天,这个主板驱动并没有包含USB控制器,因为USB控制器都是Windows自带的驱动,下载了一个南桥驱动,安装后并没有效果;
2、Windows自带的驱动原来都是放在C:\Windows\System32\DriverStore\FileRepository下,USB控制器相关的驱动,就在usbport.inf_amd64_xxxxxxxxxx文件夹里,xxxxxxxxx是一串16进制数字,悲催的是,安装这个驱动时要不提示找不到指定文件,要不说第三方INF没有签名;
3、自己折腾搞不定,找个软件吧,第一个想到的是驱动之家官方的驱动精灵,下载下来发现是个全家桶啊,什么腾讯管家,金山毒霸,浏览器首页修改一应俱全,而且没有鼠标点击,用TAB键根本移动不到取消框,只好默认全部安装了,装完启动,检测,提示系统自带驱动缺失,于是回车修复,但每次修复完,重新检测还是那样,而且没有提示USB控制器驱动安装有问题,有些功能用键盘无法操作,不知道是不是还有哪里可以操作一下,于是又搜了一下,如何用键盘代替鼠标,居然真的找到了!
4、按WIN键,输入设置,回车,打开设置主页:

移到“轻松使用”,进去后左边选择“鼠标”,在右边启用“使用数字小键盘在屏幕上移动鼠标”(按空格键开关),最好把三个开关都打开,如果没有启用CTRL键加速功能,鼠标移动非常慢:

好了,现在可以用小键盘移动鼠标了;
5、继续回到驱动精灵,再次修复,还是不行啊,这个东西除了带来一堆垃圾,什么作用都没有!于是把它带来的垃圾以及它自己卸载了。
6、似乎360也有一个驱动大师,于是就下载了一个,这个倒是很纯洁,但是功能太弱,完全没发现问题;
7、刚才搜索“安装驱动 找不到指定的文件”时,发现一个论坛提到了这个,是驱动人生的论坛,好像还有解决方案,但要注册才能下载,难道驱动人生可以解决?于是就下载了一个驱动人生,安装的时候还是附带全家桶,不过现在可以用键盘移动鼠标取消了,只安装了驱动人生自己,跟刚才两个软件不同的是,它提示USB外设驱动没有安装,于是点修复,结果反反复复出现等待光标,就是无法完成;
8、之前又搜索到,驱动安装的日志在C:\Windows\INF\setupapi.dev.log文件里,于是打开这个文件,发现Driver package failed signature verification. Error = 0xE000022F,驱动程序签名有问题,所以不能安装成功;
9、Windows10有个高级启动选项是禁用强制驱动签名,如何进入高级启动选项呢?以前是按F8,现在不行了,要在设置里面,更新和安全,恢复,高级启动,立即重启,然后设置疑难解答,高级启动,再重启,就可以进入高级启动菜单,按7进入禁止强制驱动签名模式,重启后再用驱动人生修复,果然成功了;
10、打开驱动人生下载目录,DTLFolder\DriversDownLoad,发现它下载了USB驱动目录是USB_10.0.10240.16384_WHQL_107049,里面文件如下:

除了第一个xml文件是程序自己用的外,其他都是USB驱动用到的文件,点右键发现那几个sys文件,除了usbohci.sys和usbuhci.sys外,其他都有数字签名,而usbuhci.sys我这里没用到,问题就出在usbohci.sys上:


11、难道是驱动人生替换了未签名的文件?图谋不轨?为了验证一下,我又下载了一个Windows10安装光盘(版本是当前使用的1703版):
cn_windows_10_multiple_editions_version_1703_updated_march_2017_x64_dvd_10194190.iso
12、怎么提取安装光盘中的内置驱动?找了一下,原来Windows的安装盘从VISTA起,不再使用XP以前的I386目录和Drivers.cab文件存放驱动,而是打包在一个Install.wim镜像文件中,要找到驱动文件,必须用工具提取,这个工具就是Imagex.exe,微软自己做的命令行工具,但是我的电脑上没有,于是下载了一个64位的,放在C盘根目录,通过如下命令即可提取:
c:\IMAGEX_x64 /mount f:\sources\install.wim 5 i:\1703
其中F盘是在iso文件上点右键,打开方式选“Windows资源管理器”打开后虚拟出来的盘符,其实就相当于系统自带的虚拟光驱,I盘是硬盘,用来存放挂载的镜像文件,5是选择挂载哪一个版本的Windows(多合一版),如果不知道要挂哪个,把这个数字改成100,会显示xml文件内容,并提示找不到这个索引号,从xml文件内容就能找到各版本的信息,然后再重新挂载正确的即可。这个挂载其实是个解压缩过程,时间很长,提取完之后就跟安装好了Windows一样,目录都列好了。
今天又发现另一个图形化的工具,Dism++,比这个操作更简单。Dism是PowerShell内置的命令,也是与镜像有关,也能挂载提取,但用了一下似乎提示权限有问题,Dism++是国内开源爱好者自己开发的图形化工具,与Dism没有关系。
13、好了,原版的Windows已经准备好,进入Windows\System32\DriverStore\FileRepository目录,搜索usbohci.sys,在usbport.inf_amd64_8e5f608c0111283d目录下,点右键一看,也是没签名的:
这不是坑爹吗?你自己带的东西都没签名,然后又不给用!!!!
14、有点怀疑是Windows自己更新的时候修改了一些策略,导致之前可以用的不能用了,为了再次验证,又继续下载了两个版本的Windows10安装光盘,分别是早期的1607和最新的1709,找到usbohci.sys,如下所示:
从左到右依次为1607,1703,1709,均未签名,基本可以判断是Windows自己抽风了。
15、昨天晚上搞到12点多,搞定鼠标后没有重启测试,今天早上开机,果然发现鼠标又不能用了,因为我没有选择禁用强制签名选项来启动,系统发现那个没签名的驱动,就把它停了,尝试卸载,结果再装也装不上,于是只好又设置高级启动,重新禁止强制签名,进入系统,装上驱动,恰好这时Windows又在后台偷偷摸摸地更新,不知道更新了啥,让我重启。
16、重启之后,奇迹出现,刚才明明提示没有签名强制安装的驱动,现在居然正常启动也没问题了,而且查看驱动详情的时候出现了矛盾的一幕:
外面显示数字签名者:未经数字签名,里面的sys文件又显示数字签名者是Microsoft Windows,然而进入C:\Windows\System32\drivers目录,找到usbohci.sys,点右键,却发现并没有数字签名:
好吧,你开心就好,反正不要再禁我的鼠标就行……
感谢这次蛋疼的折腾之旅,让我知道了驱动程序来自哪里,安装日志在哪里,哪个软件坑爹又没用,怎么玩安装盘,怎么用键盘操作鼠标,怎么进入高级启动界面……
我为什么要知道这些??????????????为微软的疏忽买单啊!!!!!
啥都不说了,它又提示我重启了,不知道又有什么奇迹会发生……
posted @ 2017-11-19 12:43 amp@java 阅读(1139) | 评论 (0)编辑 收藏

 每次换手机,把旧手机的数据迁移到新手机就是个很麻烦的事情,幸好最近华为的“手机克隆”APP越来越强大,居然能够把微信的聊天记录包括图片原封不动地迁移到新手机上,以前用微信自带的聊天记录转移功能只能转移文字信息,图片视频全部丢失,不知道现在的怎么样。手机克隆还能把SD卡的内容也转移过来,基本满足了需要。
但是要把手机上的东西传到电脑就没那么简单了,现在已经没有了以前的大容量存储模式,只能选择MTP模式,这种模式其实不是一个完整的文件系统,有很多限制,所以一些传统的软件读取不到,例如FastCopy是用不了的,用Windows自带的文件管理器来复制,开始计算时间就要等很久,中间出了个错就前功尽弃;还有通过手机上的APP访问电脑共享的方式,在手机上复制也可以,但是同样会莫名其妙卡死,FTP同理,折腾了好久,还是觉得自己动手比较好。
MTP协议在维基百科里解释得比较清楚:https://en.wikipedia.org/wiki/Media_Transfer_Protocol ,简单点说就是:
1、不是以块设备的形式访问,跟U盘不同;
2、只能单线程访问,不能同时进行多个操作,只能一个接一个;
3、控制权在设备上,对外展示的内容由设备决定;
4、默认不能直接对文件进行部分修改,只能复制过来修改完再复制回去,但Android对协议做了扩展,能够修改部分文件内容;
5、在Linux上有些软件能够把它挂载为文件系统,这样其他软件就能像访问普通文件系统一样访问了,但是Windows下似乎没有。

不过有人开发了一个在Windows下通过JNI实现的Java库jmtp,项目托管在Google Code,被墙了,但是GitHub有人fork了一个,可以下载下来,我下载的是https://github.com/reindahl/jmtp
里面包含了C++的代码和Java的代码,以及两个已经编译好的dll文件,分别用于Win32和Win64,把其中一个dll文件放在工程目录下,再把Java源代码加入工程中即可使用,文档比较简陋,但是看test目录下的MtpTest.java,基本可以摸到如何使用了,这个协议比较简单,其实没什么功能,我要的只是把文件复制到电脑上。
根据MtpTest.java,稍微修改一下,做个递归复制即可把手机上的所有文件复制到电脑上:
package test;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.rmi.server.SocketSecurityException;
import java.util.ArrayList;


import jmtp.PortableDevice;
import jmtp.PortableDeviceFolderObject;
import jmtp.PortableDeviceManager;
import jmtp.PortableDeviceObject;
import jmtp.PortableDeviceStorageObject;


public class TestApp {

   

    
public static void main(String[] args) {
        
// TODO Auto-generated method stub
        
        ArrayList
<PortableDeviceStorageObject> devices = new ArrayList<>();

        PortableDeviceManager manager 
= new PortableDeviceManager();

        
for (PortableDevice device : manager) {
            System.out.println(device);
            device.open();
            
            
// Iterate over deviceObjects
            for (PortableDeviceObject object : device.getRootObjects()) {
                String storageName
=object.getName();
                System.out.println(storageName);

                
// If the object is a storage object
                if (object instanceof PortableDeviceStorageObject) {
                    PortableDeviceStorageObject storage 
= (PortableDeviceStorageObject) object;
                    System.out.println(storage.getChildObjects().length);
                    
for (PortableDeviceObject child : storage.getChildObjects()) {
                            copyall(child,
"E:\\手机备份\\"+object.getName());
                    }
                }
            }

            device.close();
            System.out.println(size);
        }

  
  
    }
    
    
public static void copyall(PortableDeviceObject obj,String path) {

        if(obj instanceof PortableDeviceFolderObject) {
          

            String objName=obj.getName();
            
if(objName.contains(":")) {
                objName
=objName.replace(':''');
            }
            String newPath 
= path+"\\"+objName;
            System.out.println(
"创建文件夹:"+newPath);
            
            File file = new File(newPath);
            if(!file.exists()) {
                file.mkdirs();
            }
            for(PortableDeviceObject subObj:((PortableDeviceFolderObject) obj).getChildObjects()) {             
                copyall(subObj,newPath);
            }
        }
        
else {      
            
if(obj.getName().contains(":"))
                
return;
            System.out.println(
"开始复制文件到:"+path+"\\"+obj.getName());
            File file 
= new File(path);
            obj.copy(file.toPath());                     
            System.out.println(
"文件复制完成!");
        }
    }

}
其中发现有点问题:
1、Android设备文件名里是可以包含冒号(:)的,但Windows是不可以的,所以复制到这些文件的时候会有问题,于是遇到目录名这样就把它改为中文的冒号(:),但是遇到文件名这样就不行了,因为这个库的copy函数只需要指定目标目录,不需要指定目标文件名,所以这些文件只能放弃;
2、Android手机的MTP协议是由“媒体存储”这个系统APP控制的,有时候手机上可以看到的文件,通过MTP访问却怎么也看不到,重启手机也不行,应该就是这个APP没有更新数据,需要把它的系统数据清除掉,等它重建完重新访问就可以看到了,不过这个重建时间非常长,可以查看它数据占用的空间,刚清除之后会发现它占用的空间会不断增长,到了不增长的时候就是重建完了,就可以正常访问了;
3、这个库有时候还有点bug,有一次发现它读取到的文件和文件夹都没有了最后一个.后面的部分,所以总是卡住,重新插拔一下手机数据线又没问题了;
4、为了避免复制了半天结果发现不完整,又要重来,最好在复制前先统计一下文件大小,看看跟手机上看到的占用存储空间是不是一致,对于MTP设备上的文件,可以通过getSize函数得到大小,把上面复制操作改为大小累加即可,速度比复制快一些,不过由于小文件太多,也不会快很多。

把手机里的文件复制到电脑后,通过一些简单的分析,发现有很多其实是垃圾来的,也可以为手机空间清理提供参考,因为在电脑上分析起来比在手机上方便一些。例如一些视频APP的缓存,居然超过1G,占用了宝贵的内部存储空间,之前一直都没发现,通过电脑里的按文件大小搜索才发现。
posted @ 2017-11-17 14:54 amp@java 阅读(2199) | 评论 (0)编辑 收藏

09款老速腾,不支持USB和AUX,要听歌除了CD以外,就是刻录在CD上的MP3了,以前不知道用什么软件刻录了一张碟,能够完美地显示中文文件名和ID3信息,前几天用ImgBurn刻了一张,发现中文是乱码,开始以为是ID3信息显示乱码,于是下载了一个Mp3Tag,把所有ID3信息都清除,结果显示文件名依然乱码,重新写入ID3信息,发现ID3可以正常显示,但文件名还是乱码。
于是就把原来那张可以正常显示中文的碟拿来研究一下,发现它的ID3标签只是ID3v1,而后来重新写入的ID3是ID3v2.3,两个都可以正常显示中文,说明ID3信息是正常的,文件名乱码不是这个问题。
但是不知道用什么软件来显示光盘的文件系统,只能一次次摸索。
幸好有一张CD-RW可以反复尝试。
ImgBurn默认是使用ISO9660+UDF,而ISO 9660则使用最老的ISO 9660文件系统,也就是1988版本,文件名默认是不支持中文的,不知道是不是这个原因,于是就把文件系统改为ISO 9660+Joliet,如下图:

并且把ISO 9660标准改为1999:

可能是因为字符编码那里改为了ASCII,所以就好了。
后来又尝试只使用UDF文件系统,结果认不出碟。



所以,目前能够使用中文的环境其实就是:
ImgBurn使用ISO 9660 1999标准;
ID3使用v1或v2.3都可以。

posted @ 2017-02-10 09:17 amp@java 阅读(379) | 评论 (0)编辑 收藏

最近新部署了一个信息系统,厂家居然没有升级方案,所有数据都要重新输入,包括用户、角色等都要重新配置,真是操蛋。要是一个个录入简直是日狗了,这些用户在其他信息系统早已存在,但是每个都复制粘贴提交一遍也不是办法,于是就想用程序自动完成这些操作。步骤如下:
1、从其他信息系统的数据库导出用户信息,也可以直接从其他信息系统的界面把所有用户信息复制下来放在一个文本文件里,反正就是准备好数据源;
2、在需要录入用户信息的系统中,用人工操作的方式登录系统,并录入一个用户,同时用Wireshark抓包,查看整个过程要提交一些什么样的表单数据;
3、在程序中用httpclient提交同样的数据,完成登录,并从第1步的数据源中读取用户信息,然后循环提交录入用户所需的数据,完成用户的录入;
4、新系统没有默认的用户角色,是需要一个个修改的,是根据用户的ID来确定当前修改的用户,并且提交一个角色ID来进行设定,因此需要首先获取用户的ID,然后根据该ID来提交角色ID,而用户ID是通过用户列表页面获取到的,因此还需要通过正则表达式来获取所有用户的ID,然后循环提交角色ID,完成角色设定。

花了不少时间才搞定,有几个地方需要注意:
1、如果表单数据不包含中文,直接把表单的Name和Value加在HttpPost的URL的?后面即可,不需要专门建立NameValuePair,如下所示:
HttpPost httppost = new HttpPost("http://1.1.1.1/test/adduser?userid=abc&username=efg");
httpclient.execute(httppost);

但是,如果表单数据包含中文,例如姓名,用这种方式提交的表单数据会出现乱码,即使通过URLEncoder进行编码后再发也不行,必须建立NameValuePair,再加到HttpPost的Entity里面,如下所示:
HttpPost httppost = new HttpPost("http://1.1.1.1/test/adduser?userid=abc");
List
<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(
new BasicNameValuePair("username","张三"));
httppost.setEntity(
new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
httpclient.execute(httppost);

2、用于网页内容查找的正则表达式的使用方式一般为:
Pattern p = Pattern.compile(".*?abc(whattoget)123.*?");
Matcher m = p.matcher(line);
if(m.matches()){
     String whattoget 
= m.group(1);
}
".*?abc(whattoget)123.*?"就是一个正则表达式,如果用于匹配一行的时候,由于要查找的内容是在行中间,所以前后需要加上.*?,表示前后可以是任意字符,也可以什么都没有,而表达式中间的(whattoget)就表示一个group,编号为1,编号为0的group是整个匹配的字符串,找到之后提取group(1)即可得到想要的内容。
测试正则表达式是一项很麻烦的工作,不过有个很好的软件可以完成此工作:RegexBuddy,支持各种语言的正则表达式的调试。
学习正则表达式的宝典是《Mastering Regular Expression》。
posted @ 2016-01-12 15:54 amp@java 阅读(3566) | 评论 (1)编辑 收藏

今天遇到一个非常奇怪的问题,有台装XP的电脑,插上USB键盘没反应,还以为是键盘坏了,又找来两个不同型号的键盘,依然不行,又以为是USB接口坏了,结果在电脑启动的时候又可以按F2进入BIOS,这样就只有一个原因,Windows的驱动没装上了。
幸好这电脑还有传统的PS/2口,而且插上就能识别,否则连Windows都进不去,因为按Ctrl+Alt+Del没反应。
进去之后提示安装USB键盘驱动,到最后一步提示安装失败,原因是拒绝访问。
上网搜了一下,安装驱动拒绝访问的其中一个原因是注册表有个键的权限设置有问题,改过来即可,但是我打开注册表,连那个键都没找到,不是这个原因。
不过从这个解决方案中也知道了驱动安装的日志是在Windows目录下的setupapi.log文件里面,于是打开那个文件,发现每次安装都有两个拒绝访问的错误,但并没有说是注册表拒绝访问,在拒绝访问之前,还提到一个叫MlCoInst.dll的文件没有签名。
上网搜MlCoInst.dll,没有找到任何结果,在System32目录下找到它,看属性,果然没有签名,是个三无文件,不知道为什么每次安装驱动都要调用它。
日志里面还提到了“共同安装程序”,似乎和CoInst有点关联,于是又查了一下,原来安装驱动的时候可以通过调用“共同安装程序”来实现某些目的,例如修改驱动程序的签名状态,欺骗操作系统,这样就可以只安装一次驱动即可,不用每次插入都安装一次。
于是尝试把MlCoInst.dll删除,提示删除失败。
在注册表里面搜索MlCoInst.dll,把所有找到的键值都删除,再次插拔键盘,顺利安装完毕,删除MlCoInst.dll,也成功了,果然是它的问题。

这个应该是某个USB设备的驱动引进来的,而且修改了usb.inf,每次安装任何USB设备都要调用它,但它可能与Windows的签名机制有冲突,所以导致安装失败,真是坑爹!
posted @ 2015-04-02 17:04 amp@java 阅读(3567) | 评论 (0)编辑 收藏

做GUI程序的时候,通常有个后台工作线程在努力工作,但是中间又需要一些暂停,而关闭程序的时候,必须立即结束那个线程,退出程序,也有的时候需要停止后台线程,但不关闭程序。例如,做一个目录监控程序,发现目录中有文件的时候,执行一定的操作,执行完之后没有文件了,就要暂停一下,过几秒或几分钟再次检测,这时候就要对线程进行暂停操作,如果在暂停的时候,用户要关闭程序,就必须马上停止线程,如果用户需要暂停检测,按下某个按钮后,需要让线程马上停止,但再次按下某个按钮,线程又必须马上开始。

以前我都是通过检测停止标记和用Thread.sleep(time)来完成的,后台线程的每次循环都要检查停止标记,如果发现停止标记已设定,就不再循环,退出线程,在线程内部,如果需要暂停,就执行Thread.sleep(time)。通过把线程的setDaemon(true)方法,还可以让线程作为后台线程,当图形界面关闭后,线程也自动退出。

但是,这种方式有个问题,如果我需要在图形界面上点击按钮来停止线程,但并不退出程序,而点击按钮的时候线程正处于sleep状态,就对它没有任何办法,只能让它醒过来再操作,如果sleep的时间比较长,例如1分钟,那么点击按钮之后,用户最多要等1分钟才能把线程停下来。当然,Thread对象有个interrupt方法,但是已经被标记为过期,一般不建议使用了。感谢评论中watchzerg的提醒,Thread的interrupt()并没有标记为过期,可以按照他的说法来操作,更为简单。

怎么让线程能暂停,又能随时叫醒呢?原来Java里最原始的对象Object就自带此功能。

每个Object都有wait(time)和notify()方法,前者就是让拥有该Obejct的线程处于暂停状态,后者则让线程马上唤醒,通过这两个方法,就能够满足上述的所有要求。

首先,建立一个同步对象:
Object syncObj = new Object();

然后在线程中需要暂停的地方,调用该对象的wait(time)方法:
synchronized (syncObj) {
       syncObj.wait(60*1000);
}

在图形界面的按钮监听事件中,对该对象执行notify()方法:
        button_1.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {

                thread.setStop(true);
                synchronized (syncObj) {
                        syncObj.notify();
                 }
                //为了等待线程退出,还可以加上以下语句:
                thread.join();

            }
        });

posted @ 2015-03-10 16:52 amp@java 阅读(7677) | 评论 (2)编辑 收藏

Eclipse有个功能就是把整个项目打包成一个可执行的Jar文件,里面包含了所有项目引用了的库,如果电脑上安装了JRE,直接双击就可以启动,看起来很方便,如下图所示:

可以选择把所有类库打包进去,也就是Jar里面还包含一堆Jar:

还可以生成ant脚本:


生成的jar文件,可以直接通过java -jar xx.jar启动,简单快捷。


然而,这样导出来的可执行jar,启动速度却非常慢,这跟包的大小有关。有个项目导出来的包有40MB,结果启动需要近一分钟,在性能差的电脑上,甚至要几分钟,就是你执行完命令后,没有任何界面显示,但是查看任务管理器发现java进程的CPU占用率在浮动,说明正在努力启动,过了一段时间之后界面突然显示出来,简直让人崩溃。可是在Eclipse里面运行,却是一点就开。

我开始尝试缩小导出的包。但是Eclipse的导出对话框并没有提供需要打包哪些库的选项,都是默认把所有库都打包进去,但是它可以生成ant脚本,可以通过编辑ant脚本的方式来减少不必要的库。经过多次尝试,终于把40MB的包缩成了17MB,启动速度快了一些,但是依然需要半分钟以上。

后来觉得,能不能不打包直接运行呢?于是把导出来的包用压缩软件解压,再把里面包含的jar包继续解压,最后得到一堆没有压缩的class文件,再通过指定classpath的方式,直接运行程序入口class,发现启动速度和在Eclipse里面一样,一点就开。

打包的好处是部署简单,只需要一个文件,但带来的缺点实在不能忍,打散的方式部署起来稍微难一点,但是启动速度够快,对普通用户来说,这个才是最重要的。

当然,还有一种方式是像Eclipse那样,启动时显示一个图片,底下一个进度条显示启动进度,不过这样也加大了工作量,而且每次都要等那进度条,实际上也很烦。
posted @ 2015-03-10 15:07 amp@java 阅读(5132) | 评论 (0)编辑 收藏

     摘要: JMF太老了,各种问题得不到解决,Oracle也没再升级过,如果能找到新东西,最好能把它扔掉。最近OpenCV比较火,还有人用Java封装了OpenCV,成立了JavaCV项目,通过改造VideoInput这个基于C语言的项目,能够用Java来调用摄像头,JMF可以扔掉了。如果想测试,非常简单,把那些编译好的jar文件放入Build Path即可,如果是在Windows X86环境下,则只需要把带...  阅读全文
posted @ 2015-02-15 11:41 amp@java 阅读(10415) | 评论 (7)编辑 收藏