<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    amp@java

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      99 隨筆 :: 0 文章 :: 228 評論 :: 0 Trackbacks

    2012年4月8日 #

    當(dāng)年是從CSDN博客遷過來的,因?yàn)槟抢锖懿环€(wěn)定,那時(shí)候這里很火的;
    前段時(shí)間發(fā)現(xiàn),Blogjava的登錄頁面居然沒有驗(yàn)證碼了,圖片顯示錯(cuò)誤,無法登錄,預(yù)感這個(gè)地方要涼,只好到處找替代,但沒找到好用的博客,github是一個(gè)選項(xiàng),但似乎不是很適合做博客。
    現(xiàn)在終于又可以登錄了,不過首頁居然只剩一篇文章,我以為數(shù)據(jù)都沒了,登錄發(fā)現(xiàn)還是有的,不過太讓人不放心了。
    posted @ 2018-08-18 22:14 amp@java 閱讀(149) | 評論 (0)編輯 收藏

     昨天下午開始,之前用得好好的USB鼠標(biāo),突然不能用了,找到個(gè)PS/2鼠標(biāo),卻發(fā)現(xiàn)主板沒有鼠標(biāo)的PS/2口,只有鍵盤的PS/2口,真是奇葩,幸好在用的鍵盤是PS/2口的,費(fèi)了九牛二虎之力,用鍵盤操作,Win+R,compmgmt.msc進(jìn)入計(jì)算機(jī)管理,上下箭頭移到設(shè)備管理器,發(fā)現(xiàn)右邊的USB控制器前全是黃色嘆號,嘗試卸載再安裝,卻怎么也裝不上,重新啟動(dòng)發(fā)現(xiàn)鼠標(biāo)在啟動(dòng)Windows前還是亮燈的,但到了顯示W(wǎng)indows徽標(biāo)的時(shí)候燈就滅了,應(yīng)該不是硬件問題,而是驅(qū)動(dòng)問題。
    為了進(jìn)一步證實(shí)硬件沒問題,找了個(gè)安裝系統(tǒng)的U盤,插進(jìn)去啟動(dòng),能夠正常使用鼠標(biāo),于是目標(biāo)就聚焦在找回驅(qū)動(dòng)上。
    開始折騰:
    1、首先是找官方驅(qū)動(dòng)啊,我這電腦是老機(jī),AMD7系列主板,找了半天,這個(gè)主板驅(qū)動(dòng)并沒有包含USB控制器,因?yàn)閁SB控制器都是Windows自帶的驅(qū)動(dòng),下載了一個(gè)南橋驅(qū)動(dòng),安裝后并沒有效果;
    2、Windows自帶的驅(qū)動(dòng)原來都是放在C:\Windows\System32\DriverStore\FileRepository下,USB控制器相關(guān)的驅(qū)動(dòng),就在usbport.inf_amd64_xxxxxxxxxx文件夾里,xxxxxxxxx是一串16進(jìn)制數(shù)字,悲催的是,安裝這個(gè)驅(qū)動(dòng)時(shí)要不提示找不到指定文件,要不說第三方INF沒有簽名;
    3、自己折騰搞不定,找個(gè)軟件吧,第一個(gè)想到的是驅(qū)動(dòng)之家官方的驅(qū)動(dòng)精靈,下載下來發(fā)現(xiàn)是個(gè)全家桶啊,什么騰訊管家,金山毒霸,瀏覽器首頁修改一應(yīng)俱全,而且沒有鼠標(biāo)點(diǎn)擊,用TAB鍵根本移動(dòng)不到取消框,只好默認(rèn)全部安裝了,裝完啟動(dòng),檢測,提示系統(tǒng)自帶驅(qū)動(dòng)缺失,于是回車修復(fù),但每次修復(fù)完,重新檢測還是那樣,而且沒有提示USB控制器驅(qū)動(dòng)安裝有問題,有些功能用鍵盤無法操作,不知道是不是還有哪里可以操作一下,于是又搜了一下,如何用鍵盤代替鼠標(biāo),居然真的找到了!
    4、按WIN鍵,輸入設(shè)置,回車,打開設(shè)置主頁:

    移到“輕松使用”,進(jìn)去后左邊選擇“鼠標(biāo)”,在右邊啟用“使用數(shù)字小鍵盤在屏幕上移動(dòng)鼠標(biāo)”(按空格鍵開關(guān)),最好把三個(gè)開關(guān)都打開,如果沒有啟用CTRL鍵加速功能,鼠標(biāo)移動(dòng)非常慢:

    好了,現(xiàn)在可以用小鍵盤移動(dòng)鼠標(biāo)了;
    5、繼續(xù)回到驅(qū)動(dòng)精靈,再次修復(fù),還是不行啊,這個(gè)東西除了帶來一堆垃圾,什么作用都沒有!于是把它帶來的垃圾以及它自己卸載了。
    6、似乎360也有一個(gè)驅(qū)動(dòng)大師,于是就下載了一個(gè),這個(gè)倒是很純潔,但是功能太弱,完全沒發(fā)現(xiàn)問題;
    7、剛才搜索“安裝驅(qū)動(dòng) 找不到指定的文件”時(shí),發(fā)現(xiàn)一個(gè)論壇提到了這個(gè),是驅(qū)動(dòng)人生的論壇,好像還有解決方案,但要注冊才能下載,難道驅(qū)動(dòng)人生可以解決?于是就下載了一個(gè)驅(qū)動(dòng)人生,安裝的時(shí)候還是附帶全家桶,不過現(xiàn)在可以用鍵盤移動(dòng)鼠標(biāo)取消了,只安裝了驅(qū)動(dòng)人生自己,跟剛才兩個(gè)軟件不同的是,它提示USB外設(shè)驅(qū)動(dòng)沒有安裝,于是點(diǎn)修復(fù),結(jié)果反反復(fù)復(fù)出現(xiàn)等待光標(biāo),就是無法完成;
    8、之前又搜索到,驅(qū)動(dòng)安裝的日志在C:\Windows\INF\setupapi.dev.log文件里,于是打開這個(gè)文件,發(fā)現(xiàn)Driver package failed signature verification. Error = 0xE000022F,驅(qū)動(dòng)程序簽名有問題,所以不能安裝成功;
    9、Windows10有個(gè)高級啟動(dòng)選項(xiàng)是禁用強(qiáng)制驅(qū)動(dòng)簽名,如何進(jìn)入高級啟動(dòng)選項(xiàng)呢?以前是按F8,現(xiàn)在不行了,要在設(shè)置里面,更新和安全,恢復(fù),高級啟動(dòng),立即重啟,然后設(shè)置疑難解答,高級啟動(dòng),再重啟,就可以進(jìn)入高級啟動(dòng)菜單,按7進(jìn)入禁止強(qiáng)制驅(qū)動(dòng)簽名模式,重啟后再用驅(qū)動(dòng)人生修復(fù),果然成功了;
    10、打開驅(qū)動(dòng)人生下載目錄,DTLFolder\DriversDownLoad,發(fā)現(xiàn)它下載了USB驅(qū)動(dòng)目錄是USB_10.0.10240.16384_WHQL_107049,里面文件如下:

    除了第一個(gè)xml文件是程序自己用的外,其他都是USB驅(qū)動(dòng)用到的文件,點(diǎn)右鍵發(fā)現(xiàn)那幾個(gè)sys文件,除了usbohci.sys和usbuhci.sys外,其他都有數(shù)字簽名,而usbuhci.sys我這里沒用到,問題就出在usbohci.sys上:


    11、難道是驅(qū)動(dòng)人生替換了未簽名的文件?圖謀不軌?為了驗(yàn)證一下,我又下載了一個(gè)Windows10安裝光盤(版本是當(dāng)前使用的1703版):
    cn_windows_10_multiple_editions_version_1703_updated_march_2017_x64_dvd_10194190.iso
    12、怎么提取安裝光盤中的內(nèi)置驅(qū)動(dòng)?找了一下,原來Windows的安裝盤從VISTA起,不再使用XP以前的I386目錄和Drivers.cab文件存放驅(qū)動(dòng),而是打包在一個(gè)Install.wim鏡像文件中,要找到驅(qū)動(dòng)文件,必須用工具提取,這個(gè)工具就是Imagex.exe,微軟自己做的命令行工具,但是我的電腦上沒有,于是下載了一個(gè)64位的,放在C盤根目錄,通過如下命令即可提取:
    c:\IMAGEX_x64 /mount f:\sources\install.wim 5 i:\1703
    其中F盤是在iso文件上點(diǎn)右鍵,打開方式選“Windows資源管理器”打開后虛擬出來的盤符,其實(shí)就相當(dāng)于系統(tǒng)自帶的虛擬光驅(qū),I盤是硬盤,用來存放掛載的鏡像文件,5是選擇掛載哪一個(gè)版本的Windows(多合一版),如果不知道要掛哪個(gè),把這個(gè)數(shù)字改成100,會(huì)顯示xml文件內(nèi)容,并提示找不到這個(gè)索引號,從xml文件內(nèi)容就能找到各版本的信息,然后再重新掛載正確的即可。這個(gè)掛載其實(shí)是個(gè)解壓縮過程,時(shí)間很長,提取完之后就跟安裝好了Windows一樣,目錄都列好了。
    今天又發(fā)現(xiàn)另一個(gè)圖形化的工具,Dism++,比這個(gè)操作更簡單。Dism是PowerShell內(nèi)置的命令,也是與鏡像有關(guān),也能掛載提取,但用了一下似乎提示權(quán)限有問題,Dism++是國內(nèi)開源愛好者自己開發(fā)的圖形化工具,與Dism沒有關(guān)系。
    13、好了,原版的Windows已經(jīng)準(zhǔn)備好,進(jìn)入Windows\System32\DriverStore\FileRepository目錄,搜索usbohci.sys,在usbport.inf_amd64_8e5f608c0111283d目錄下,點(diǎn)右鍵一看,也是沒簽名的:
    這不是坑爹嗎?你自己帶的東西都沒簽名,然后又不給用?。。。?/div>
    14、有點(diǎn)懷疑是Windows自己更新的時(shí)候修改了一些策略,導(dǎo)致之前可以用的不能用了,為了再次驗(yàn)證,又繼續(xù)下載了兩個(gè)版本的Windows10安裝光盤,分別是早期的1607和最新的1709,找到usbohci.sys,如下所示:
    從左到右依次為1607,1703,1709,均未簽名,基本可以判斷是Windows自己抽風(fēng)了。
    15、昨天晚上搞到12點(diǎn)多,搞定鼠標(biāo)后沒有重啟測試,今天早上開機(jī),果然發(fā)現(xiàn)鼠標(biāo)又不能用了,因?yàn)槲覜]有選擇禁用強(qiáng)制簽名選項(xiàng)來啟動(dòng),系統(tǒng)發(fā)現(xiàn)那個(gè)沒簽名的驅(qū)動(dòng),就把它停了,嘗試卸載,結(jié)果再裝也裝不上,于是只好又設(shè)置高級啟動(dòng),重新禁止強(qiáng)制簽名,進(jìn)入系統(tǒng),裝上驅(qū)動(dòng),恰好這時(shí)Windows又在后臺(tái)偷偷摸摸地更新,不知道更新了啥,讓我重啟。
    16、重啟之后,奇跡出現(xiàn),剛才明明提示沒有簽名強(qiáng)制安裝的驅(qū)動(dòng),現(xiàn)在居然正常啟動(dòng)也沒問題了,而且查看驅(qū)動(dòng)詳情的時(shí)候出現(xiàn)了矛盾的一幕:
    外面顯示數(shù)字簽名者:未經(jīng)數(shù)字簽名,里面的sys文件又顯示數(shù)字簽名者是Microsoft Windows,然而進(jìn)入C:\Windows\System32\drivers目錄,找到usbohci.sys,點(diǎn)右鍵,卻發(fā)現(xiàn)并沒有數(shù)字簽名:
    好吧,你開心就好,反正不要再禁我的鼠標(biāo)就行……
    感謝這次蛋疼的折騰之旅,讓我知道了驅(qū)動(dòng)程序來自哪里,安裝日志在哪里,哪個(gè)軟件坑爹又沒用,怎么玩安裝盤,怎么用鍵盤操作鼠標(biāo),怎么進(jìn)入高級啟動(dòng)界面……
    我為什么要知道這些??????????????為微軟的疏忽買單啊?。。。?!
    啥都不說了,它又提示我重啟了,不知道又有什么奇跡會(huì)發(fā)生……
    posted @ 2017-11-19 12:43 amp@java 閱讀(1156) | 評論 (0)編輯 收藏

     每次換手機(jī),把舊手機(jī)的數(shù)據(jù)遷移到新手機(jī)就是個(gè)很麻煩的事情,幸好最近華為的“手機(jī)克隆”APP越來越強(qiáng)大,居然能夠把微信的聊天記錄包括圖片原封不動(dòng)地遷移到新手機(jī)上,以前用微信自帶的聊天記錄轉(zhuǎn)移功能只能轉(zhuǎn)移文字信息,圖片視頻全部丟失,不知道現(xiàn)在的怎么樣。手機(jī)克隆還能把SD卡的內(nèi)容也轉(zhuǎn)移過來,基本滿足了需要。
    但是要把手機(jī)上的東西傳到電腦就沒那么簡單了,現(xiàn)在已經(jīng)沒有了以前的大容量存儲(chǔ)模式,只能選擇MTP模式,這種模式其實(shí)不是一個(gè)完整的文件系統(tǒng),有很多限制,所以一些傳統(tǒng)的軟件讀取不到,例如FastCopy是用不了的,用Windows自帶的文件管理器來復(fù)制,開始計(jì)算時(shí)間就要等很久,中間出了個(gè)錯(cuò)就前功盡棄;還有通過手機(jī)上的APP訪問電腦共享的方式,在手機(jī)上復(fù)制也可以,但是同樣會(huì)莫名其妙卡死,F(xiàn)TP同理,折騰了好久,還是覺得自己動(dòng)手比較好。
    MTP協(xié)議在維基百科里解釋得比較清楚:https://en.wikipedia.org/wiki/Media_Transfer_Protocol ,簡單點(diǎn)說就是:
    1、不是以塊設(shè)備的形式訪問,跟U盤不同;
    2、只能單線程訪問,不能同時(shí)進(jìn)行多個(gè)操作,只能一個(gè)接一個(gè);
    3、控制權(quán)在設(shè)備上,對外展示的內(nèi)容由設(shè)備決定;
    4、默認(rèn)不能直接對文件進(jìn)行部分修改,只能復(fù)制過來修改完再復(fù)制回去,但Android對協(xié)議做了擴(kuò)展,能夠修改部分文件內(nèi)容;
    5、在Linux上有些軟件能夠把它掛載為文件系統(tǒng),這樣其他軟件就能像訪問普通文件系統(tǒng)一樣訪問了,但是Windows下似乎沒有。

    不過有人開發(fā)了一個(gè)在Windows下通過JNI實(shí)現(xiàn)的Java庫jmtp,項(xiàng)目托管在Google Code,被墻了,但是GitHub有人fork了一個(gè),可以下載下來,我下載的是https://github.com/reindahl/jmtp
    里面包含了C++的代碼和Java的代碼,以及兩個(gè)已經(jīng)編譯好的dll文件,分別用于Win32和Win64,把其中一個(gè)dll文件放在工程目錄下,再把Java源代碼加入工程中即可使用,文檔比較簡陋,但是看test目錄下的MtpTest.java,基本可以摸到如何使用了,這個(gè)協(xié)議比較簡單,其實(shí)沒什么功能,我要的只是把文件復(fù)制到電腦上。
    根據(jù)MtpTest.java,稍微修改一下,做個(gè)遞歸復(fù)制即可把手機(jī)上的所有文件復(fù)制到電腦上:
    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:\\手機(jī)備份\\"+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(
    "創(chuàng)建文件夾:"+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(
    "開始復(fù)制文件到:"+path+"\\"+obj.getName());
                File file 
    = new File(path);
                obj.copy(file.toPath());                     
                System.out.println(
    "文件復(fù)制完成!");
            }
        }

    }
    其中發(fā)現(xiàn)有點(diǎn)問題:
    1、Android設(shè)備文件名里是可以包含冒號(:)的,但Windows是不可以的,所以復(fù)制到這些文件的時(shí)候會(huì)有問題,于是遇到目錄名這樣就把它改為中文的冒號(:),但是遇到文件名這樣就不行了,因?yàn)檫@個(gè)庫的copy函數(shù)只需要指定目標(biāo)目錄,不需要指定目標(biāo)文件名,所以這些文件只能放棄;
    2、Android手機(jī)的MTP協(xié)議是由“媒體存儲(chǔ)”這個(gè)系統(tǒng)APP控制的,有時(shí)候手機(jī)上可以看到的文件,通過MTP訪問卻怎么也看不到,重啟手機(jī)也不行,應(yīng)該就是這個(gè)APP沒有更新數(shù)據(jù),需要把它的系統(tǒng)數(shù)據(jù)清除掉,等它重建完重新訪問就可以看到了,不過這個(gè)重建時(shí)間非常長,可以查看它數(shù)據(jù)占用的空間,剛清除之后會(huì)發(fā)現(xiàn)它占用的空間會(huì)不斷增長,到了不增長的時(shí)候就是重建完了,就可以正常訪問了;
    3、這個(gè)庫有時(shí)候還有點(diǎn)bug,有一次發(fā)現(xiàn)它讀取到的文件和文件夾都沒有了最后一個(gè).后面的部分,所以總是卡住,重新插拔一下手機(jī)數(shù)據(jù)線又沒問題了;
    4、為了避免復(fù)制了半天結(jié)果發(fā)現(xiàn)不完整,又要重來,最好在復(fù)制前先統(tǒng)計(jì)一下文件大小,看看跟手機(jī)上看到的占用存儲(chǔ)空間是不是一致,對于MTP設(shè)備上的文件,可以通過getSize函數(shù)得到大小,把上面復(fù)制操作改為大小累加即可,速度比復(fù)制快一些,不過由于小文件太多,也不會(huì)快很多。

    把手機(jī)里的文件復(fù)制到電腦后,通過一些簡單的分析,發(fā)現(xiàn)有很多其實(shí)是垃圾來的,也可以為手機(jī)空間清理提供參考,因?yàn)樵陔娔X上分析起來比在手機(jī)上方便一些。例如一些視頻APP的緩存,居然超過1G,占用了寶貴的內(nèi)部存儲(chǔ)空間,之前一直都沒發(fā)現(xiàn),通過電腦里的按文件大小搜索才發(fā)現(xiàn)。
    posted @ 2017-11-17 14:54 amp@java 閱讀(2256) | 評論 (0)編輯 收藏

    09款老速騰,不支持USB和AUX,要聽歌除了CD以外,就是刻錄在CD上的MP3了,以前不知道用什么軟件刻錄了一張碟,能夠完美地顯示中文文件名和ID3信息,前幾天用ImgBurn刻了一張,發(fā)現(xiàn)中文是亂碼,開始以為是ID3信息顯示亂碼,于是下載了一個(gè)Mp3Tag,把所有ID3信息都清除,結(jié)果顯示文件名依然亂碼,重新寫入ID3信息,發(fā)現(xiàn)ID3可以正常顯示,但文件名還是亂碼。
    于是就把原來那張可以正常顯示中文的碟拿來研究一下,發(fā)現(xiàn)它的ID3標(biāo)簽只是ID3v1,而后來重新寫入的ID3是ID3v2.3,兩個(gè)都可以正常顯示中文,說明ID3信息是正常的,文件名亂碼不是這個(gè)問題。
    但是不知道用什么軟件來顯示光盤的文件系統(tǒng),只能一次次摸索。
    幸好有一張CD-RW可以反復(fù)嘗試。
    ImgBurn默認(rèn)是使用ISO9660+UDF,而ISO 9660則使用最老的ISO 9660文件系統(tǒng),也就是1988版本,文件名默認(rèn)是不支持中文的,不知道是不是這個(gè)原因,于是就把文件系統(tǒng)改為ISO 9660+Joliet,如下圖:

    并且把ISO 9660標(biāo)準(zhǔn)改為1999:

    可能是因?yàn)樽址幋a那里改為了ASCII,所以就好了。
    后來又嘗試只使用UDF文件系統(tǒng),結(jié)果認(rèn)不出碟。



    所以,目前能夠使用中文的環(huán)境其實(shí)就是:
    ImgBurn使用ISO 9660 1999標(biāo)準(zhǔn);
    ID3使用v1或v2.3都可以。

    posted @ 2017-02-10 09:17 amp@java 閱讀(402) | 評論 (0)編輯 收藏

    最近新部署了一個(gè)信息系統(tǒng),廠家居然沒有升級方案,所有數(shù)據(jù)都要重新輸入,包括用戶、角色等都要重新配置,真是操蛋。要是一個(gè)個(gè)錄入簡直是日狗了,這些用戶在其他信息系統(tǒng)早已存在,但是每個(gè)都復(fù)制粘貼提交一遍也不是辦法,于是就想用程序自動(dòng)完成這些操作。步驟如下:
    1、從其他信息系統(tǒng)的數(shù)據(jù)庫導(dǎo)出用戶信息,也可以直接從其他信息系統(tǒng)的界面把所有用戶信息復(fù)制下來放在一個(gè)文本文件里,反正就是準(zhǔn)備好數(shù)據(jù)源;
    2、在需要錄入用戶信息的系統(tǒng)中,用人工操作的方式登錄系統(tǒng),并錄入一個(gè)用戶,同時(shí)用Wireshark抓包,查看整個(gè)過程要提交一些什么樣的表單數(shù)據(jù);
    3、在程序中用httpclient提交同樣的數(shù)據(jù),完成登錄,并從第1步的數(shù)據(jù)源中讀取用戶信息,然后循環(huán)提交錄入用戶所需的數(shù)據(jù),完成用戶的錄入;
    4、新系統(tǒng)沒有默認(rèn)的用戶角色,是需要一個(gè)個(gè)修改的,是根據(jù)用戶的ID來確定當(dāng)前修改的用戶,并且提交一個(gè)角色I(xiàn)D來進(jìn)行設(shè)定,因此需要首先獲取用戶的ID,然后根據(jù)該ID來提交角色I(xiàn)D,而用戶ID是通過用戶列表頁面獲取到的,因此還需要通過正則表達(dá)式來獲取所有用戶的ID,然后循環(huán)提交角色I(xiàn)D,完成角色設(shè)定。

    花了不少時(shí)間才搞定,有幾個(gè)地方需要注意:
    1、如果表單數(shù)據(jù)不包含中文,直接把表單的Name和Value加在HttpPost的URL的?后面即可,不需要專門建立NameValuePair,如下所示:
    HttpPost httppost = new HttpPost("http://1.1.1.1/test/adduser?userid=abc&username=efg");
    httpclient.execute(httppost);

    但是,如果表單數(shù)據(jù)包含中文,例如姓名,用這種方式提交的表單數(shù)據(jù)會(huì)出現(xiàn)亂碼,即使通過URLEncoder進(jìn)行編碼后再發(fā)也不行,必須建立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、用于網(wǎng)頁內(nèi)容查找的正則表達(dá)式的使用方式一般為:
    Pattern p = Pattern.compile(".*?abc(whattoget)123.*?");
    Matcher m = p.matcher(line);
    if(m.matches()){
         String whattoget 
    = m.group(1);
    }
    ".*?abc(whattoget)123.*?"就是一個(gè)正則表達(dá)式,如果用于匹配一行的時(shí)候,由于要查找的內(nèi)容是在行中間,所以前后需要加上.*?,表示前后可以是任意字符,也可以什么都沒有,而表達(dá)式中間的(whattoget)就表示一個(gè)group,編號為1,編號為0的group是整個(gè)匹配的字符串,找到之后提取group(1)即可得到想要的內(nèi)容。
    測試正則表達(dá)式是一項(xiàng)很麻煩的工作,不過有個(gè)很好的軟件可以完成此工作:RegexBuddy,支持各種語言的正則表達(dá)式的調(diào)試。
    學(xué)習(xí)正則表達(dá)式的寶典是《Mastering Regular Expression》。
    posted @ 2016-01-12 15:54 amp@java 閱讀(3574) | 評論 (1)編輯 收藏

    今天遇到一個(gè)非常奇怪的問題,有臺(tái)裝XP的電腦,插上USB鍵盤沒反應(yīng),還以為是鍵盤壞了,又找來兩個(gè)不同型號的鍵盤,依然不行,又以為是USB接口壞了,結(jié)果在電腦啟動(dòng)的時(shí)候又可以按F2進(jìn)入BIOS,這樣就只有一個(gè)原因,Windows的驅(qū)動(dòng)沒裝上了。
    幸好這電腦還有傳統(tǒng)的PS/2口,而且插上就能識(shí)別,否則連Windows都進(jìn)不去,因?yàn)榘碈trl+Alt+Del沒反應(yīng)。
    進(jìn)去之后提示安裝USB鍵盤驅(qū)動(dòng),到最后一步提示安裝失敗,原因是拒絕訪問。
    上網(wǎng)搜了一下,安裝驅(qū)動(dòng)拒絕訪問的其中一個(gè)原因是注冊表有個(gè)鍵的權(quán)限設(shè)置有問題,改過來即可,但是我打開注冊表,連那個(gè)鍵都沒找到,不是這個(gè)原因。
    不過從這個(gè)解決方案中也知道了驅(qū)動(dòng)安裝的日志是在Windows目錄下的setupapi.log文件里面,于是打開那個(gè)文件,發(fā)現(xiàn)每次安裝都有兩個(gè)拒絕訪問的錯(cuò)誤,但并沒有說是注冊表拒絕訪問,在拒絕訪問之前,還提到一個(gè)叫MlCoInst.dll的文件沒有簽名。
    上網(wǎng)搜MlCoInst.dll,沒有找到任何結(jié)果,在System32目錄下找到它,看屬性,果然沒有簽名,是個(gè)三無文件,不知道為什么每次安裝驅(qū)動(dòng)都要調(diào)用它。
    日志里面還提到了“共同安裝程序”,似乎和CoInst有點(diǎn)關(guān)聯(lián),于是又查了一下,原來安裝驅(qū)動(dòng)的時(shí)候可以通過調(diào)用“共同安裝程序”來實(shí)現(xiàn)某些目的,例如修改驅(qū)動(dòng)程序的簽名狀態(tài),欺騙操作系統(tǒng),這樣就可以只安裝一次驅(qū)動(dòng)即可,不用每次插入都安裝一次。
    于是嘗試把MlCoInst.dll刪除,提示刪除失敗。
    在注冊表里面搜索MlCoInst.dll,把所有找到的鍵值都刪除,再次插拔鍵盤,順利安裝完畢,刪除MlCoInst.dll,也成功了,果然是它的問題。

    這個(gè)應(yīng)該是某個(gè)USB設(shè)備的驅(qū)動(dòng)引進(jìn)來的,而且修改了usb.inf,每次安裝任何USB設(shè)備都要調(diào)用它,但它可能與Windows的簽名機(jī)制有沖突,所以導(dǎo)致安裝失敗,真是坑爹!
    posted @ 2015-04-02 17:04 amp@java 閱讀(3605) | 評論 (0)編輯 收藏

    做GUI程序的時(shí)候,通常有個(gè)后臺(tái)工作線程在努力工作,但是中間又需要一些暫停,而關(guān)閉程序的時(shí)候,必須立即結(jié)束那個(gè)線程,退出程序,也有的時(shí)候需要停止后臺(tái)線程,但不關(guān)閉程序。例如,做一個(gè)目錄監(jiān)控程序,發(fā)現(xiàn)目錄中有文件的時(shí)候,執(zhí)行一定的操作,執(zhí)行完之后沒有文件了,就要暫停一下,過幾秒或幾分鐘再次檢測,這時(shí)候就要對線程進(jìn)行暫停操作,如果在暫停的時(shí)候,用戶要關(guān)閉程序,就必須馬上停止線程,如果用戶需要暫停檢測,按下某個(gè)按鈕后,需要讓線程馬上停止,但再次按下某個(gè)按鈕,線程又必須馬上開始。

    以前我都是通過檢測停止標(biāo)記和用Thread.sleep(time)來完成的,后臺(tái)線程的每次循環(huán)都要檢查停止標(biāo)記,如果發(fā)現(xiàn)停止標(biāo)記已設(shè)定,就不再循環(huán),退出線程,在線程內(nèi)部,如果需要暫停,就執(zhí)行Thread.sleep(time)。通過把線程的setDaemon(true)方法,還可以讓線程作為后臺(tái)線程,當(dāng)圖形界面關(guān)閉后,線程也自動(dòng)退出。

    但是,這種方式有個(gè)問題,如果我需要在圖形界面上點(diǎn)擊按鈕來停止線程,但并不退出程序,而點(diǎn)擊按鈕的時(shí)候線程正處于sleep狀態(tài),就對它沒有任何辦法,只能讓它醒過來再操作,如果sleep的時(shí)間比較長,例如1分鐘,那么點(diǎn)擊按鈕之后,用戶最多要等1分鐘才能把線程停下來。當(dāng)然,Thread對象有個(gè)interrupt方法,但是已經(jīng)被標(biāo)記為過期,一般不建議使用了。感謝評論中watchzerg的提醒,Thread的interrupt()并沒有標(biāo)記為過期,可以按照他的說法來操作,更為簡單。

    怎么讓線程能暫停,又能隨時(shí)叫醒呢?原來Java里最原始的對象Object就自帶此功能。

    每個(gè)Object都有wait(time)和notify()方法,前者就是讓擁有該Obejct的線程處于暫停狀態(tài),后者則讓線程馬上喚醒,通過這兩個(gè)方法,就能夠滿足上述的所有要求。

    首先,建立一個(gè)同步對象:
    Object syncObj = new Object();

    然后在線程中需要暫停的地方,調(diào)用該對象的wait(time)方法:
    synchronized (syncObj) {
           syncObj.wait(60*1000);
    }

    在圖形界面的按鈕監(jiān)聽事件中,對該對象執(zhí)行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 閱讀(7692) | 評論 (2)編輯 收藏

    Eclipse有個(gè)功能就是把整個(gè)項(xiàng)目打包成一個(gè)可執(zhí)行的Jar文件,里面包含了所有項(xiàng)目引用了的庫,如果電腦上安裝了JRE,直接雙擊就可以啟動(dòng),看起來很方便,如下圖所示:

    可以選擇把所有類庫打包進(jìn)去,也就是Jar里面還包含一堆Jar:

    還可以生成ant腳本:


    生成的jar文件,可以直接通過java -jar xx.jar啟動(dòng),簡單快捷。


    然而,這樣導(dǎo)出來的可執(zhí)行jar,啟動(dòng)速度卻非常慢,這跟包的大小有關(guān)。有個(gè)項(xiàng)目導(dǎo)出來的包有40MB,結(jié)果啟動(dòng)需要近一分鐘,在性能差的電腦上,甚至要幾分鐘,就是你執(zhí)行完命令后,沒有任何界面顯示,但是查看任務(wù)管理器發(fā)現(xiàn)java進(jìn)程的CPU占用率在浮動(dòng),說明正在努力啟動(dòng),過了一段時(shí)間之后界面突然顯示出來,簡直讓人崩潰??墒窃贓clipse里面運(yùn)行,卻是一點(diǎn)就開。

    我開始嘗試縮小導(dǎo)出的包。但是Eclipse的導(dǎo)出對話框并沒有提供需要打包哪些庫的選項(xiàng),都是默認(rèn)把所有庫都打包進(jìn)去,但是它可以生成ant腳本,可以通過編輯ant腳本的方式來減少不必要的庫。經(jīng)過多次嘗試,終于把40MB的包縮成了17MB,啟動(dòng)速度快了一些,但是依然需要半分鐘以上。

    后來覺得,能不能不打包直接運(yùn)行呢?于是把導(dǎo)出來的包用壓縮軟件解壓,再把里面包含的jar包繼續(xù)解壓,最后得到一堆沒有壓縮的class文件,再通過指定classpath的方式,直接運(yùn)行程序入口class,發(fā)現(xiàn)啟動(dòng)速度和在Eclipse里面一樣,一點(diǎn)就開。

    打包的好處是部署簡單,只需要一個(gè)文件,但帶來的缺點(diǎn)實(shí)在不能忍,打散的方式部署起來稍微難一點(diǎn),但是啟動(dòng)速度夠快,對普通用戶來說,這個(gè)才是最重要的。

    當(dāng)然,還有一種方式是像Eclipse那樣,啟動(dòng)時(shí)顯示一個(gè)圖片,底下一個(gè)進(jìn)度條顯示啟動(dòng)進(jìn)度,不過這樣也加大了工作量,而且每次都要等那進(jìn)度條,實(shí)際上也很煩。
    posted @ 2015-03-10 15:07 amp@java 閱讀(5143) | 評論 (0)編輯 收藏

         摘要: JMF太老了,各種問題得不到解決,Oracle也沒再升級過,如果能找到新東西,最好能把它扔掉。最近OpenCV比較火,還有人用Java封裝了OpenCV,成立了JavaCV項(xiàng)目,通過改造VideoInput這個(gè)基于C語言的項(xiàng)目,能夠用Java來調(diào)用攝像頭,JMF可以扔掉了。如果想測試,非常簡單,把那些編譯好的jar文件放入Build Path即可,如果是在Windows X86環(huán)境下,則只需要把帶...  閱讀全文
    posted @ 2015-02-15 11:41 amp@java 閱讀(10430) | 評論 (7)編輯 收藏

    其實(shí)我覺得用java結(jié)合SQL來做同樣的事情更簡單,但是EXCEL的好處是不用編程,雖然里面有好多陷阱,但是掌握之后能夠熟練運(yùn)用還是比每次都編個(gè)程序更簡單。VLOOKUP函數(shù)的使用比較復(fù)雜,搞了好久都不明白,終于找到了下面這篇文章,解決了很多問題。

    以下是轉(zhuǎn)載文章,原來的出處不知道是哪里,應(yīng)該是來自

    http://www.excelpx.com
    但具體的地址不詳。



    VLOOKUP函數(shù)是Excel中幾個(gè)最重函數(shù)之一,為了方便大家學(xué)習(xí),蘭色幻想特針對VLOOKUP函數(shù)的使用和擴(kuò)展應(yīng)用,進(jìn)行一次全面綜合的說明。本文為入門部分

         一、入門級

          VLOOKUP是一個(gè)查找函數(shù),給定一個(gè)查找的目標(biāo),它就能從指定的查找區(qū)域中查找返回想要查找到的值。它的基本語法為:

          VLOOKUP(查找目標(biāo),查找范圍返回值的列數(shù),精確OR模糊查找)

    下面以一個(gè)實(shí)例來介紹一下這四個(gè)參數(shù)的使用

         例1:如下圖所示,要求根據(jù)表二中的姓名,查找姓名所對應(yīng)的年齡。  

       公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)  

       參數(shù)說明:

           1 查找目標(biāo):就是你指定的查找的內(nèi)容或單元格引用。本例中表二A列的姓名就是查找目標(biāo)。我們要根據(jù)表二的“姓名”在表一中A列進(jìn)行查找。

            公式:B13 =VLOOKUP(A13,$B$2:$D$8,3,0)   

           2 查找范圍(VLOOKUP(A13,$B$2:$D$8,3,0) : 指定了查找目標(biāo),如果沒有說從哪里查找,EXCEL肯定會(huì)很為難。所以下一步我們就要指定從哪個(gè)范圍中進(jìn)行查找。VLOOKUP的這第二個(gè)參數(shù)可以從一個(gè) 單元格區(qū)域中查找,也可以從一個(gè)常量數(shù)組或內(nèi)存數(shù)組中查找。本例中要從表一中進(jìn)行查找,那么范圍我們要怎么指定呢?這里也是極易出錯(cuò)的地方。大家一定要注 意,給定的第二個(gè)參數(shù)查找范圍要符合以下條件才不會(huì)出錯(cuò):

            A 查找目標(biāo)一定要在該區(qū)域的第一列。本例中查找表二的姓名,那么姓名所對應(yīng)的表一的姓名列,那么表一的姓名列(列)一定要是查找區(qū)域的第一列。象本例中,給定的區(qū)域要從第二列開始,即$B$2:$D$8,而不能是$A$2:$D$8。因?yàn)椴檎业?#8220;姓名”不在$A$2:$D$8區(qū)域的第一列。

            B 該區(qū)域中一定要包含要返回值所在的列,本例中要返回的值是年齡。年齡列(表一的D列)一定要包括在這個(gè)范圍內(nèi),即:$B$2:$D$8,如果寫成$B$2:$C$8就是錯(cuò)的。

           3 返回值的列數(shù)(B13 =VLOOKUP(A13,$B$2:$D$8,3,0))。這是VLOOKUP第3個(gè)參數(shù)。它是一個(gè)整數(shù)值。它怎么得來的呢。它是“返回值”在第二個(gè)參數(shù)給定的區(qū)域中的列數(shù)。本例中我們要返回的是“年齡”,它是第二個(gè)參數(shù)查找范圍$B$2:$D$8的第3列。這里一定要注意,列數(shù)不是在工作表中的列數(shù)(不是第4列),而是在查找范圍區(qū)域的第幾列。如果本例中要是查找姓名所對應(yīng)的性別,第3個(gè)參數(shù)的值應(yīng)該設(shè)置為多少呢。答案是2。因?yàn)樾詣e在$B$2:$D$8的第2列中。

           4 精確OR模糊查找(VLOOKUP(A13,$B$2:$D$8,3,0)  ),最后一個(gè)參數(shù)是決定函數(shù)精確和模糊查找的關(guān)鍵。精確即完全一樣,模糊即包含的意思。第4個(gè)參數(shù)如果指定值是0或FALSE就表示精確查找,而值為1 或TRUE時(shí)則表示模糊。這里蘭色提醒大家切記切記,在使用VLOOKUP時(shí)千萬不要把這個(gè)參數(shù)給漏掉了,如果缺少這個(gè)參數(shù)默為值為模糊查找,我們就無法精確查找到結(jié)果了。  

          好了,關(guān)于VLOOKUP函數(shù)的入門級應(yīng)用就說到這里,VLOOKUP函數(shù)可不只是這么簡單的查找,我們講的還只是1/10的用法。其他的沒法在一篇文章中說明。敬請期待“VLOOKUP的使用方法-進(jìn)階篇”吧。

     

    上一講咱們學(xué)習(xí)了VLOOKUP的基本用法和示例,本講將介紹VLOOKUP在使用中的一些小技巧。

    Excel函數(shù)速成教程全系列(包括VLOOKUP函數(shù),IF函數(shù),offset函數(shù),sumif函數(shù)等66個(gè)函數(shù))預(yù)計(jì)6月初全部錄制完成,現(xiàn)已在淘寶開始預(yù)訂(8折優(yōu)惠),地址:http://item.taobao.com/item.htm?id=17500884347

    一、VLOOKUP多行查找時(shí)復(fù)制公式的問題

        VLOOKUP函數(shù)的第三個(gè)參數(shù)是查找返回值所在的列數(shù),如果我們需要查找返回多列時(shí),這個(gè)列數(shù)值需要一個(gè)個(gè)的更改,比如返回第2列的,參數(shù)設(shè)置為2,如 果需要返回第3列的,就需要把值改為3。。。如果有十幾列會(huì)很麻煩的。那么能不能讓第3個(gè)參數(shù)自動(dòng)變呢?向后復(fù)制時(shí)自動(dòng)變?yōu)?,3,4,5。。。   

        在EXCEL中有一個(gè)函數(shù)COLUMN,它可以返回指定單元格的列數(shù),比如

             =COLUMNS(A1) 返回值1

             =COLUMNS(B1) 返回值2

       而單元格引用復(fù)制時(shí)會(huì)自動(dòng)發(fā)生變化,即A1隨公式向右復(fù)制時(shí)會(huì)變成B1,C1,D1。。這樣我們用COLUMN函數(shù)就可以轉(zhuǎn)換成數(shù)字1,2,3,4。。。 

        例:下例中需要同時(shí)查找性別,年齡,身高,體重。

       

         公式:=VLOOKUP($A13,$B$2:$F$8,COLUMN(B1),0)

      公式說明:這里就是使用COLUMN(B1)轉(zhuǎn)化成可以自動(dòng)遞增的數(shù)字。

    二、VLOOKUP查找出現(xiàn)錯(cuò)誤值的問題。

        1、如何避免出現(xiàn)錯(cuò)誤值。

         EXCEL2003 在VLOOKUP查找不到,就#N/A的錯(cuò)誤值,我們可以利用錯(cuò)誤處理函數(shù)把錯(cuò)誤值轉(zhuǎn)換成0或空值。

          即:=IF(ISERROR(VLOOKUP(參數(shù)略)),"",VLOOKUP(參數(shù)略)

         EXCEL2007,EXCEL2010中提供了一個(gè)新函數(shù)IFERROR,處理起來比EXCEL2003簡單多了。

         IFERROR(VLOOKUP(),"") 

        2、VLOOKUP函數(shù)查找時(shí)出現(xiàn)錯(cuò)誤值的幾個(gè)原因

          A、實(shí)在是沒有所要查找到的值

          B、查找的字符串或被查找的字符中含有空格或看不見的空字符,驗(yàn)證方法是用=號對比一下,如果結(jié)果是FALSE,就表示兩個(gè)單元格看上去相同,其實(shí)結(jié)果不同。

          C、參數(shù)設(shè)置錯(cuò)誤。VLOOKUP的最后一個(gè)參數(shù)沒有設(shè)置成1或者是沒有設(shè)置掉。第二個(gè)參數(shù)數(shù)據(jù)源區(qū)域,查找的值不是區(qū)域的第一列,或者需要反回的字段不在區(qū)域里,參數(shù)設(shè)置在入門講里已注明,請參閱。

         D、數(shù)值格式不同,如果查找值是文本,被查找的是數(shù)字類型,就會(huì)查找不到。解決方法是把查找的轉(zhuǎn)換成文本或數(shù)值,轉(zhuǎn)換方法如下:

         文本轉(zhuǎn)換成數(shù)值:*1或--或/1

         數(shù)值轉(zhuǎn)抱成文本:&""  

         VLOOKUP函數(shù)的初級篇就說到這里了,咱們下一講將介紹VLOOKUP的模糊查找有、反向查找等。

     

     在學(xué)習(xí)了VLOOKUP的入門和初級篇后,本文將帶將大家學(xué)習(xí)VLOOKUP的進(jìn)階篇:VLOOKUP的模糊查找。

        一、字符的模糊查找    

            在A列我們知道如何查找型號為“AAA”的產(chǎn)品所對應(yīng)的B列價(jià)格,即:

        =VLOOKUP(C1,A:B,2,0)

           如果我們需要查找包含“AAA”的產(chǎn)品名稱怎么表示呢?如下圖表中所示。

         公式=VLOOKUP("*"&A10&"*",A2:B6,2,0)  

        公式說明:VLOOKUP的第一個(gè)參數(shù)允許使用通配符“*”來表示包含的意思,把*放在字符的兩邊,即"*" & 字符 & "*"。

       二、數(shù)字的區(qū)間查找

          數(shù)字的區(qū)間查找即給定多個(gè)區(qū)間,指定一個(gè)數(shù)就可以查找出它在哪個(gè)區(qū)間并返回這個(gè)區(qū)間所對應(yīng)的值。

        在VLOOKUP入門中我們提示VLOOKUP的第4個(gè)參數(shù),如果為0或FALSE是精確查找,如果是1或TRUE或省略則為模糊查找,那么實(shí)現(xiàn)區(qū)間查找正是第4個(gè)參數(shù)的模糊查找應(yīng)用。

        首先我們需要了解一下VLOOKUP函數(shù)模糊查找的兩個(gè)重要規(guī)則:

        1、引用的數(shù)字區(qū)域一定要從小到大排序。雜亂的數(shù)字是無法準(zhǔn)確查找到的。如下面A列符合模糊查找的前題,B列則不符合。 

        

        2、模糊查找的原理是給一定個(gè)數(shù),它會(huì)找到和它最接近,但比它小的那個(gè)數(shù)。詳見下圖說明。

        

       最后看一個(gè)實(shí)例: 

        例:如下圖所示,要求根據(jù)上面的提成比率表,在提成表計(jì)算表中計(jì)算每個(gè)銷售額的提成比率和提成額。

        

       公式:=VLOOKUP(A11,$A$3:$B$7,2)

       公式說明:

        1、上述公式省略了VLOOKUP最后一個(gè)參數(shù),相當(dāng)于把第四個(gè)參數(shù)設(shè)置成1或TRUE。這表示VLOOKUP要進(jìn)行數(shù)字的區(qū)間查找。

        2、圖中公式中在查找5000時(shí)返回比率表0所對應(yīng)的比率1%,原因是0和10000與5000最接近,但VLOOKUP只選比查找值小的那一個(gè),所以公式會(huì)返回0所對應(yīng)的比率1%。

     

     前言:前面我們分別學(xué)習(xí)了VLOOKUP函數(shù)的入門、初級和進(jìn)階篇。今天我們學(xué)習(xí)VLOOKUP函數(shù)的高級應(yīng)用部分-VLOOKUP函數(shù)的數(shù)組應(yīng)用。(本文由蘭色幻想原創(chuàng),轉(zhuǎn)載請注明轉(zhuǎn)自excel精英培訓(xùn)

     一、VLOOKUP的反向查找。

        一般情況下,VLOOKUP函數(shù)只能從左向右查找。但如果需要從右向右查找,則需要把區(qū)域進(jìn)行“乾坤大挪移”,把列的位置用數(shù)組互換一下。

        例1:要求在如下圖所示表中的姓名反查工號。

         

        公式:=VLOOKUP(A9,IF({1,0},B2:B5,A2:A5),2,0)

        公式剖析:

            1、這里其實(shí)不是VLOOKUP可以實(shí)現(xiàn)從右至右的查找,而是利用IF函數(shù)的數(shù)組效應(yīng)把兩列換位重新組合后,再按正常的從左至右查找。

            2、IF({1,0},B2:B5,A2:A5)這是本公式中最重要的組成部分。在EXCEL函數(shù)中使用數(shù)組時(shí)(前提時(shí)該函數(shù)的參數(shù)支持?jǐn)?shù)組),返回的結(jié) 果也會(huì)是一個(gè)數(shù)組。這里1和0不是實(shí)際意義上的數(shù)字,而是1相關(guān)于TRUE,0相當(dāng)于FALSE,當(dāng)為1時(shí),它會(huì)返回IF的第二個(gè)參數(shù)(B列),為0時(shí)返 回第二個(gè)參數(shù)(A列)。根據(jù)數(shù)組運(yùn)算返回?cái)?shù)組,所以使用IF后的結(jié)果返回一個(gè)數(shù)組(非單元格區(qū)域):{"張一","A001";"趙 三","A002";"楊五","A003";"孫二","A004"}

     二、VLOOKUP函數(shù)的多條件查找。

          VLOOKUP函數(shù)需要借用數(shù)組才能實(shí)現(xiàn)多條件查找。

         例2:要求根據(jù)部門和姓名查找C列的加班時(shí)間。

         分析:我們可以延用例1的思路,我們的努力方向不是讓VLOOKUP本身實(shí)現(xiàn)多條件查找,而是想辦法重構(gòu)一個(gè)數(shù)組。多個(gè)條件我們可以用&連接在一起,同樣兩列我們也可以連接成一列數(shù)據(jù),然后用IF函數(shù)進(jìn)行組合。

        公式:{=VLOOKUP(A9&B9,IF({1,0},A2:A5&B2:B5,C2:C5),2,0)}

        公式剖析:

           1、A9&B9 把兩個(gè)條件連接在一起。把他們做為一個(gè)整體進(jìn)行查找。

           2、A2:A5&B2:B5,和條件連接相對應(yīng),把部分和姓名列也連接在一起,作為一個(gè)待查找的整體。

           3、IF({1,0},A2:A5&B2:B5,C2:C5) 用IF({1,0}把連接后的兩列與C列數(shù)據(jù)合并成一個(gè)兩列的內(nèi)存數(shù)組。按F9后可以查看的結(jié)果為:

           {"銷售張一",1;"銷售趙三",5;"人事楊五",3;"銷售趙三",6}

           4、完成了數(shù)組的重構(gòu)后,接下來就是VLOOKUP的基本查找功能了,另外公式中含有多個(gè)數(shù)據(jù)與多個(gè)數(shù)據(jù)運(yùn)算(A2:A5&B2:B5),,所以必須以數(shù)組形式輸入,即按ctrl+shift后按ENTER結(jié)束輸入。

         三、VLOOKUP函數(shù)的批量查找。

         VLOOKUP一般情況下只能查找一個(gè),那么多項(xiàng)該怎么查找呢?

         例3 要求把如圖表中所有張一的消費(fèi)金額全列出來

         分析:經(jīng)過前面的學(xué)習(xí),我們也有這樣一個(gè)思路,我們在實(shí)現(xiàn)復(fù)雜的查找時(shí),努力的方向是怎么重構(gòu)一個(gè)查找內(nèi)容和查找的區(qū)域。要想實(shí)現(xiàn)多項(xiàng)查找,我們可以對查找的內(nèi)容進(jìn)行編號,第一個(gè)出現(xiàn)的是后面連接1,第二個(gè)出現(xiàn)的連接2。。。

         公式:{=VLOOKUP(B$9&ROW(A1),IF({1,0},$B$2:$B$6&COUNTIF(INDIRECT("b2:b"&ROW($2:$6)),B$9),$C$2:$C$6),2,)}

         公式剖析:

            1、B$9&ROW(A1) 連接序號,公式向下復(fù)制時(shí)會(huì)變成B$9連接1,2,3

            2、給所有的張一進(jìn)行編號。要想生成編號,就需要生成一個(gè)不斷擴(kuò)充的區(qū)域(INDIRECT("b2:b"&ROW($2:$6)),然后在這個(gè)逐行擴(kuò)充的區(qū)域內(nèi)統(tǒng)計(jì)“張一”的個(gè)數(shù),在連接上$B$2:$B$6后就可以對所有的張一進(jìn)行編號了。

           3、IF({1,0}把編號后的B列和C組重構(gòu)成一個(gè)兩列數(shù)組

         通過以上的講解,我們需要知道,VLOOKUP函數(shù)的基本用法是固定的,要實(shí)現(xiàn)高級查找,就需要借助其他函數(shù)來重構(gòu)查找內(nèi)容和查找數(shù)組。

         至此VLOOKUP函數(shù)從入門到高級的四篇VLOOKUP函數(shù)使用教程全部結(jié)束了,VLOOKUP函數(shù)在數(shù)組運(yùn)算中還有著其他應(yīng)用,但只是配角了,所以本系列不再介紹。由于筆者水平有限,不免有錯(cuò)漏之處,請大家多多指點(diǎn)。

    posted @ 2014-12-16 09:10 amp@java 閱讀(519) | 評論 (0)編輯 收藏

    JMF(Java Media Framework)是Java平臺(tái)使用攝像頭、麥克風(fēng)等媒體設(shè)備的應(yīng)用程序框架,但到了2.1.1e就不再更新,在Windows 7 X64上還能正常運(yùn)行,只是安裝的界面讓你感覺回到了Windows98的時(shí)代。


    不過年代久遠(yuǎn)的東西,雖然還能用,但可能會(huì)遇到一些奇怪的問題,折騰了兩個(gè)月,發(fā)現(xiàn)了兩個(gè)比較大的問題:

    第一個(gè)是在Windows 7 x64上提示攝像頭初始化失敗的問題。這個(gè)問題很奇怪,電腦剛開機(jī)的時(shí)候可以順利找到一次攝像頭并正常操作,但是第二次就會(huì)提示攝像頭初始化失敗。有人提出的解決方法是安裝一個(gè)叫ManyCamera的程序,這個(gè)程序可以把一個(gè)攝像頭供多個(gè)程序同時(shí)使用,其實(shí)就等于中間加了一層轉(zhuǎn)換,效果會(huì)有點(diǎn)差別,免費(fèi)版還會(huì)加上水印,要求比較高的人可能會(huì)不爽,但是目前找不到其他辦法。

    第二個(gè)是在程序中找不到攝像頭,不光找不到攝像頭,其他媒體設(shè)備通通找不到,使用以下語句:
    vector = CaptureDeviceManager.getDeviceList ( null )
    按照文檔說明是返回所有媒體設(shè)備,但每次vector都是null。
    在Eclipse中運(yùn)行又能正常,導(dǎo)出成jar之后運(yùn)行就會(huì)找不到攝像頭。
    原因在于找不到j(luò)mf.properities文件,該文件包含所有檢測到的媒體設(shè)備的信息,最簡單的解決方法就是把JMF安裝目錄下lib子目錄中的jmf.properties文件復(fù)制到最后運(yùn)行的jar所在的目錄,不過如果攝像頭改過的話,重新檢測后要把新的文件復(fù)制到j(luò)ar目錄,因?yàn)闄z測到的媒體設(shè)備信息都會(huì)存放在JMF安裝目錄里面的jmf.properties文件里。

    StackOverflow里面有個(gè)人對這個(gè)問題解釋得比較清楚:
    http://stackoverflow.com/questions/8768142/java-capturedevicemanagergetdevicelist-is-empty


    雖然問題解決了,但是還是不明白為何在Eclipse中可以正常運(yùn)行,導(dǎo)出jar后運(yùn)行卻找不到攝像頭,即使把JMF所有jar和lib目錄都加入系統(tǒng)的CLASSPATH環(huán)境變量里還是不行。


    另外,JMF安裝程序會(huì)自動(dòng)把它的jar和lib目錄加入系統(tǒng)的%CLASSPATH%環(huán)境變量,但是如果你卸載了再重新安裝到其他目錄,并不會(huì)改變%CLASSPATH%的值,需要手動(dòng)修改。不過這個(gè)環(huán)境變量似乎沒啥用處。
    最好不要把JMF安裝到默認(rèn)的Program Files目錄,可能會(huì)運(yùn)行不了,安裝到短目錄會(huì)比較保險(xiǎn),它似乎還是只認(rèn)Dos時(shí)代的8.3目錄結(jié)構(gòu),但偏偏又默認(rèn)安裝到Program Files里面。
    posted @ 2014-07-01 10:33 amp@java 閱讀(7275) | 評論 (0)編輯 收藏

    其實(shí)我也搞不懂Windows的域,反正能用就行了。
    但是最近有一臺(tái)客戶端的時(shí)間改不了,總是提示特權(quán)級不夠,按理說應(yīng)該是組策略限制了,但是我把那臺(tái)計(jì)算機(jī)從包含該組策略的OU中移出來,還是不行,這就奇怪了,難道組策略不是指針對OU里面的成員的嗎?百思不得其解啊,最后只能在BIOS里面把時(shí)間改了。
    今天發(fā)現(xiàn)我自己的電腦設(shè)置不了屏幕保護(hù),也是組策略限制了,然后把我的用戶和計(jì)算機(jī)都移出了組策略應(yīng)用的OU,結(jié)果發(fā)現(xiàn)還是設(shè)置不了,這下肯定是組策略的應(yīng)用上有問題了。
    搜索了半天發(fā)現(xiàn)有個(gè)叫rsop.msc的管理工具,可以看到某用戶在某計(jì)算機(jī)上應(yīng)用的組策略,結(jié)果發(fā)現(xiàn)我還是應(yīng)用之前的組策略,但是計(jì)算機(jī)配置和用戶配置前面都有個(gè)紅叉,右鍵-屬性-錯(cuò)誤信息里面顯示:
    Title
    由于下面列出的錯(cuò)誤,組策略結(jié)構(gòu) 失敗。

    系統(tǒng)找不到指定的路徑。

    注意: 由于 GP Core 失敗,其它組策略組件沒有一個(gè)處理了它們的策略。因此,其它組件的狀態(tài)信息不可用。
    好像是有某個(gè)組策略找不到,所以不能應(yīng)用的意思。
    然后想起來在域名下面有個(gè)“新建組策略”,但是沒有做過任何配置,應(yīng)該是有人手賤點(diǎn)了一下新建按鈕加進(jìn)去的,于是把它刪除,還是不行。
    重啟了一下客戶端,居然好了,時(shí)間也可以改了,屏幕保護(hù)也可以改了,一切都按計(jì)劃進(jìn)行。


    莫名其妙~~
    posted @ 2014-06-23 16:11 amp@java 閱讀(1347) | 評論 (0)編輯 收藏

    現(xiàn)在的手機(jī)攝像頭動(dòng)輒幾百萬上千萬像素,如果電腦需要用到攝像頭又沒有的話,不妨用手機(jī)的攝像頭代替。

    我是在做一個(gè)電腦二維碼識(shí)別器的時(shí)候,因?yàn)樵瓉淼臄z像頭太差,從而想到用一臺(tái)淘汰的Android手機(jī)來代替。

    這類應(yīng)用應(yīng)該不少,我首先找到的是一個(gè)叫DraoidCam的應(yīng)用,裝好之后發(fā)現(xiàn)免費(fèi)版沒法調(diào)整分辨率,于是放棄之。

    然后又找到了一個(gè)國內(nèi)做的免費(fèi)軟件,叫魅色,非常簡單,支持USB和WiFi連接方式,如果是USB連接的話,打開USB調(diào)試模式之后,運(yùn)行電腦的客戶端,手機(jī)上就自動(dòng)裝上了App并且自動(dòng)運(yùn)行,可以調(diào)整分辨率,不過最高只有640*480,幀率不到10,不過已經(jīng)能夠滿足我的需求了。

    然后就可以像普通PC攝像頭一樣使用了,在JMF里面也能找到,于是就可以被Java調(diào)用了。經(jīng)測試,效果比原來的PC攝像頭好多了。

    軟件主頁:http://www.libfetion.org/meise/
    posted @ 2014-06-05 15:35 amp@java 閱讀(1721) | 評論 (4)編輯 收藏

         摘要: TabActivity在API 13(Android 3.2)被標(biāo)記為過期,需要使用Fragment來實(shí)現(xiàn),F(xiàn)ragment是Android 3.0引入的一個(gè)概念,主要就是為了適應(yīng)各種不同的屏幕大?。ㄊ謾C(jī)、平板電腦)。Android 4.1發(fā)布時(shí),google還發(fā)布了一個(gè)Android Support v4的包,用于Android 1.6以上的系統(tǒng)兼容新的特性,其中包括Fragment。為了在低于...  閱讀全文
    posted @ 2012-12-27 19:07 amp@java 閱讀(15645) | 評論 (0)編輯 收藏

    SQL Server 2000的導(dǎo)入導(dǎo)出功能還是不錯(cuò)的,支持各種各樣的數(shù)據(jù)庫,但是卻有好多奇怪的bug,不能直接操作,幾乎每一步都要上網(wǎng)搜索,最后搞定了,一定要記下來:
    1、在同一臺(tái)電腦上裝好SQL Server 2000的客戶端和Oracle 10g的客戶端,并分別設(shè)置好到源數(shù)據(jù)庫(SQL Server 2000數(shù)據(jù)庫)和目標(biāo)數(shù)據(jù)庫(Oracle 數(shù)據(jù)庫)的連接,兩個(gè)數(shù)據(jù)庫都有圖形界面的企業(yè)管理器,很容易設(shè)置好;
    2、在控制面板-管理工具-數(shù)據(jù)源里添加一個(gè)DSN,驅(qū)動(dòng)程序選擇類似“Oracle in OraClient10g_home1”的,確定之后輸入Data Source Name(隨意),Description(隨意),TNS Service Name(在企業(yè)管理器里設(shè)置好的連接名),User ID(用戶名),然后按Test Connection測試是否連接成功,成功之后點(diǎn)OK;
    3、在SQL Server 2000的企業(yè)管理器里,在任意一個(gè)表上點(diǎn)右鍵,所有任務(wù),導(dǎo)出數(shù)據(jù),在目的里選擇“Oracle in OraClient10g_home1”,用戶/系統(tǒng)DSN里面就會(huì)出現(xiàn)剛才設(shè)置好的DSN名字,選中,然后輸入用戶名密碼,點(diǎn)兩次下一步就會(huì)出現(xiàn)選擇源表和視圖對話框
    4、這里要注意的是,勾上源中的某個(gè)表,在目的里面就會(huì)出現(xiàn)"用戶名"."表名"的默認(rèn)選項(xiàng),如果你剛才使用的Oracle用戶名是小寫的話,這里也會(huì)是小寫,一定要改成大寫,否則會(huì)提示該用戶名不存在

    目的也可以使用Microsoft OLE DB Provider for Oracle,在屬性里面設(shè)置服務(wù)器名稱為Oracle的TNS名稱,用戶名和密碼輸入Oracle用戶名和密碼,測試連接通過即可,后面的步驟都一樣。

    如果出現(xiàn)以下錯(cuò)誤:

    OLE DB 提供程序 'MSDAORA' 報(bào)錯(cuò)。

    [OLE/DB provider returned message: 未找到 Oracle 客戶端和網(wǎng)絡(luò)組件。這些組件是由 Oracle 公司提供的,是 Oracle 8i (或更高) 客戶軟件安裝的一部分。

     

    在安裝這些組件之前,將無法使用此提供程序。]

    OLE DB 錯(cuò)誤跟蹤[OLE/DB Provider 'MSDAORA' IDBInitialize::Initialize returned 0x80004005:  


    就要修改注冊表,有人已經(jīng)作出了詳細(xì)的修改說明,在這里可以看到:
    我把那個(gè)表也貼在這里:
    Oracle Client  Microsoft Windows NT、
    Oracle Microsoft Windows 95、
    Client Windows 98 和 Windows 98 SE
    Microsoft Windows 2000/XP/2003
    7.x [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\TransactionServer\Local Computer\My Computer]
    "OracleXaLib"="xa73.dll"
    "OracleSqlLib"="SQLLib18.dll"
    "OracleOciLib"="ociw32.dll

     

    [HKEY_LOCAL_MACHINE\SOFTWARE
    Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="xa73.dll"
     "OracleSqlLib"="SQLLib18.dll"
     "OracleOciLib"="ociw32.dll"
     
    8.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="xa80.dll"
    "OracleSqlLib"="sqllib80.dll"
    "OracleOciLib"="oci.dll"
     
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
     "OracleXaLib"="xa80.dll"
     "OracleSqlLib"="sqllib80.dll"
    "OracleOciLib"="oci.dll"
    8.1 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient8.dll"
    "OracleSqlLib"="orasql8.dll"
    "OracleOciLib"="oci.dll"
     
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient8.dll"
    "OracleSqlLib"="orasql8.dll"
    "OracleOciLib"="oci.dll"
     
    9.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient9.dll"
    "OracleSqlLib"="orasql9.dll"
    "OracleOciLib"="oci.dll"
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient9.dll"
    "OracleSqlLib"="orasql9.dll"
    "OracleOciLib"="oci.dll"
     
    10.0 [HKEY_LOCAL_MACHINE\SOFTWARE
    \Microsoft\Transaction Server
    \Local Computer\My Computer]
    "OracleXaLib"="oraclient10.dll"
    "OracleSqlLib"="orasql10.dll"
    "OracleOciLib"="oci.dll"
    [HKEY_LOCAL_MACHINE\SOFTWARE
     \Microsoft\MSDTC\MTxOCI]
    "OracleXaLib"="oraclient10.dll"
    "OracleSqlLib"="orasql10.dll"
    "OracleOciLib"="oci.dll"
     
    posted @ 2012-04-28 10:22 amp@java 閱讀(2565) | 評論 (0)編輯 收藏

    當(dāng)讀寫二進(jìn)制文件,或者要把非標(biāo)準(zhǔn)長度的整數(shù)與標(biāo)準(zhǔn)長度的整數(shù)互相轉(zhuǎn)換時(shí),就要用到大量的位操作,雖然看起來很簡單,實(shí)際上里面卻有很多細(xì)節(jié)很容易出錯(cuò)。

    首先,Java有些標(biāo)準(zhǔn)跟C/C++是不同的:

    1、Java采用高字節(jié)在前的方式讀寫數(shù)據(jù),例如要把一個(gè)4字節(jié)的int數(shù)值寫入文件時(shí),它是按照從高字節(jié)到低字節(jié)的順序?qū)懭氲?,讀取的時(shí)候也是這樣讀出來。
    而C/C++則采用平臺(tái)相關(guān)的方式,在Windows平臺(tái)采用低字節(jié)在前的方式,在Linux/Unix平臺(tái)則采用高字節(jié)在前的方式。
    如果Java要讀取C/C++創(chuàng)建的二進(jìn)制文件,就要注意這個(gè)問題,最好先搞清楚原來的文件是采用哪種方式創(chuàng)建的。網(wǎng)絡(luò)通信也要注意。

    2、Java沒有無符號數(shù),無論byte,short,int,long都是有符號整數(shù),而C/C++有個(gè)unsigned關(guān)鍵字可以設(shè)置一個(gè)數(shù)值為無符號數(shù)。

    3、Java的整數(shù)基本數(shù)據(jù)類型就是byte,short,int,long這幾個(gè),長度分別為1,2,4,8字節(jié),C/C++可以用typedef定義各種數(shù)據(jù)類型。

    第二,Java是采用補(bǔ)碼來存放整數(shù)的。
    有時(shí)候覺得補(bǔ)碼的定義有些奇怪,實(shí)際上可以這樣理解:

    把一個(gè)整數(shù)從0一直往上加1,加到溢出就變成了負(fù)數(shù)的最小值,然后再繼續(xù)加1,最后又能回到0,實(shí)際上就是一個(gè)輪回。
    例如一個(gè)byte類型的整數(shù),一共有8位,能表示256個(gè)數(shù)值,采用補(bǔ)碼的話數(shù)值范圍就是-128~127,表示方法如下:
    0        0000 0000
    1        0000 0001
    .
    .
    126    0111 1110
    127    0111 1111
    -128   1000 0000
    -127   1000 0001
    .
    .
    -1       1111 1111
    0         0000 0000

    第三、不同長度的整數(shù)轉(zhuǎn)換。
    如果是從較短的數(shù)轉(zhuǎn)成較長的數(shù),很簡單,如果是正數(shù)就在高字節(jié)補(bǔ)0,如果是負(fù)數(shù)就在高字節(jié)補(bǔ)1。
    例如byte的127轉(zhuǎn)為short的127:
    byte:0111 1111
    short:0000 0000 0111 0111
    byte的-127轉(zhuǎn)為short的-127
    byte:1000 0001
    short:1111 1111 1000 0001
    如果是從較長的數(shù)轉(zhuǎn)成較短的數(shù),實(shí)際上就是把高位都截?cái)嗔?,所以轉(zhuǎn)出來的數(shù)值可能完全不是一回事了。
    例如short的256轉(zhuǎn)為byte:
    short:0000 0001 0000 0000
    byte: 0000 0000
    把256變成了0
    short的-255轉(zhuǎn)成byte:
    short:1111 1111 0000 0001
    byte:0000 0001
    把-255變成了1

    第四、位運(yùn)算操作符及它們的優(yōu)先級
    Java的位運(yùn)算操作符包括:~非,|按位或,&按位與,^按位異或,<<左移,>>右移,>>>右移左側(cè)補(bǔ)0
    各種運(yùn)算符的優(yōu)先級如下表所示:
    優(yōu)先級
    運(yùn)算符
    結(jié)合性
    1
    () [] .
    從左到右
    2
    ! +(正) -(負(fù)) ~ ++ --
    從右向左
    3
    * / %
    從左向右
    4
    +(加) -(減)
    從左向右
    5
    << >> >>>
    從左向右
    6
    < <= > >= instanceof
    從左向右
    7
    == !=
    從左向右
    8
    &(按位與)
    從左向右
    9
    ^
    從左向右
    10
    |
    從左向右
    11
    &&
    從左向右
    12
    ||
    從左向右
    13
    ?:
    從右向左
    14
    = += -= *= /= %= &= |= ^= ~= <<= >>= >>>=
    從右向左
    根據(jù)該表可以看到,位運(yùn)算操作符的優(yōu)先級各有不同,分別為:
    1、~
    2、>> << >>>
    3、&
    4、^
    5、|
    另外需要特別注意的是,除了~,其他位運(yùn)算操作的優(yōu)先級都低于加減,所以要記得以下語句是返回32而不是7!
    1<<2+3
    還有就是&、^、|的優(yōu)先級都是低于邏輯操作符的,因此下面的語句會(huì)編譯出錯(cuò),幸好Java不像C那樣對所有大于1的值都認(rèn)為是真,否則下面的語句也能編譯通過,但可能與你的意圖不太一樣,可能調(diào)試半天才發(fā)現(xiàn)。
    if(3&1>0)
    如果記不清楚,還是按照你的意圖加上括號最保險(xiǎn)。

    第五、字節(jié)數(shù)組與整數(shù)之間的轉(zhuǎn)換
    為了把一個(gè)整數(shù)存入文件,或者從文件中讀取一個(gè)整數(shù),需要經(jīng)常在字節(jié)數(shù)組和整數(shù)之間轉(zhuǎn)換,這個(gè)過程要用到大量的位運(yùn)算。
    首先需要記住的是,在參與所有運(yùn)算前,Java都會(huì)把byte、short類型的值都轉(zhuǎn)換成int,然后再對轉(zhuǎn)換后的int進(jìn)行操作。例如下面的語句會(huì)編譯出錯(cuò):
    byte a=10,b=20,c;
    c=a+b;

    因?yàn)閍和b在相加前都被轉(zhuǎn)成了int,最后得到的結(jié)果是個(gè)int類型的值,如果要賦給byte類型的c,必須顯式地進(jìn)行類型轉(zhuǎn)換,即把第二句改為:
    c=(byte)(a+b)

    這一點(diǎn)很關(guān)鍵,因?yàn)閷τ谝粋€(gè)最高位為1的byte類型的整數(shù)(負(fù)數(shù)),在運(yùn)算之前它會(huì)被強(qiáng)制轉(zhuǎn)換成int類型,根據(jù)上面所說的第三點(diǎn),其實(shí)就是往前面的三個(gè)高字節(jié)補(bǔ)上1,這樣一來,它在參與位運(yùn)算的過程中,就不僅僅是它本身的8個(gè)bit參與了,實(shí)際上連前3個(gè)字節(jié)的24個(gè)bit(均為1)也參與了。例如有一個(gè)整數(shù)i=1082163328,它的二進(jìn)制表示為:
    01000000 10000000 10000000 10000000
    分為4個(gè)字節(jié)存儲(chǔ),除了第一個(gè)字節(jié)是正數(shù)外,其余3個(gè)字節(jié)均為負(fù)數(shù)。假如用a代表最高字節(jié)的值,用b代表其他三個(gè)字節(jié)的值,如果按照通常的理解,你可能會(huì)這樣得到i的值:
    i=(a<<24)+(b<<16)+(b<<8)+b

    如果a和b都是正數(shù),上面的等式是成立的,但是在這個(gè)例子里,卻是錯(cuò)的,因?yàn)樯鲜街械腶和b都已經(jīng)被強(qiáng)制轉(zhuǎn)換成了int類型再參加運(yùn)算,實(shí)際上
    a=00000000 00000000 00000000 01000000
    b=11111111 11111111 11111111 10000000
    i=01000000 00000000 00000000 00000000+11111111 10000000 00000000 00000000+11111111 11111111 10000000 00000000+11111111 11111111 11111111 10000000
    最后得到的結(jié)果是1065320320,不是原來的值了。
    為了不讓byte在強(qiáng)制轉(zhuǎn)換成int的過程加入了我們不想要的高位1,我們需要把它跟0xff進(jìn)行與操作,i的值應(yīng)該這樣運(yùn)算:
    = ( ( a& 0xff ) << 24 ) +( ( b & 0xff ) << 16 ) + ( ( b & 0xff ) << 8 ) + ( b & 0xff )

    注意,因?yàn)?amp;和<<的優(yōu)先級都低于+,所以上面的括號是不能少的。不過由于跟0xff與操作之后,其余24位都變成了0,因此可以把+改為|操作,因?yàn)槿魏沃蹬c0進(jìn)行或操作都得到本身:
    = ( a & 0xff ) << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )

    由于<<的優(yōu)先級高于|,所以省了一些括號。最高字節(jié)可以不與0xff進(jìn)行與操作,因?yàn)樗D(zhuǎn)換成int后左邊增加的3個(gè)字節(jié)都在左移24位時(shí)被去掉了:
    = a << 24 | ( b & 0xff ) << 16 | ( b & 0xff ) << 8 | ( b & 0xff )


    把int轉(zhuǎn)為字節(jié)數(shù)組的時(shí)候比較簡單,直接右移截?cái)嗉纯桑?/span>
    byte[] b = new byte[4];
    b[0= (byte) (i >> 24);
    b[1= (byte) (i >> 16);
    b[2= (byte) (i >> 8);
    b[3= (byte) i;


    第六、非標(biāo)準(zhǔn)長度整數(shù)的存儲(chǔ)和讀取
    假如有兩個(gè)變量,他們的值可以用12個(gè)bit來表示,如果我們用16bit的short類型來表示一個(gè)變量,那么兩個(gè)變量就需要4個(gè)字節(jié),而實(shí)際上它們只需要3個(gè)字節(jié)就能表示出來,如果存儲(chǔ)空間比較有限,寫入文件時(shí)可以把它們存放在3個(gè)字節(jié)里面,但是讀寫過程就需要進(jìn)行轉(zhuǎn)換。
    在內(nèi)存里,它們都是標(biāo)準(zhǔn)的數(shù)據(jù)類型:
    short a,b;

    寫入文件時(shí),我們用第一個(gè)字節(jié)和第二個(gè)字節(jié)的前半部分來表示a,把第二個(gè)字節(jié)的后半部分和第三個(gè)字節(jié)來表示b,即:
    1:xxxx xxxx
    2:xxxx yyyy
    3:yyyy yyyy
    x和y都表示一個(gè)bit,分別用來存放a和b。寫入時(shí)先把a(bǔ)和b轉(zhuǎn)為字節(jié)數(shù)組:
    byte[] out = new byte[3];
    out[
    0= (byte) ( a >> 4 );//把a(bǔ)的高8位放在第一個(gè)字節(jié)
    out[1= (byte) ( a << 4 );//先把a(bǔ)左移四位,在右邊補(bǔ)上4個(gè)0,第二個(gè)字節(jié)的高4位就是a的低4位了,第二個(gè)字節(jié)的高4位已經(jīng)生成,低4位還是0
    out[1|= (byte) ( b >> 8 & 0x0f );//b右移8位,并與0x0f進(jìn)行與操作,實(shí)際上就只保留了b的高4位,并且是在字節(jié)的低4位上,跟第二步得到的字節(jié)進(jìn)行或操作,就生成了第二個(gè)字節(jié)
    out[2= (byte) b;//把b的高4位截?cái)嗑偷玫搅说?位
    然后再把這個(gè)字節(jié)數(shù)組寫入文件,就可以用3個(gè)字節(jié)表示兩個(gè)整數(shù)了。
    讀取:
    =(short)( (out[0& 0xff<< 4 | ( out[1& 0xf0 )>>4);
    = (short)((out[1& 0x0f<< 8 | ( out[2& 0xff));
    posted @ 2012-04-08 16:56 amp@java 閱讀(1839) | 評論 (2)編輯 收藏

    主站蜘蛛池模板: 毛片基地免费观看| 国产精品怡红院永久免费| 又爽又高潮的BB视频免费看| 亚洲视频在线观看2018| 免费H网站在线观看的| 亚洲一区免费视频| 无码日韩人妻av一区免费| 亚洲中文字幕人成乱码| 免费毛片a在线观看67194| 亚洲日韩国产精品乱-久| 青青青国产免费一夜七次郎| 国产精品亚洲va在线观看| 亚洲国产精品无码久久九九| 一区二区三区免费电影| 久久青青草原亚洲AV无码麻豆| 人妻无码久久一区二区三区免费| 亚洲精品mv在线观看| 在线观看的免费网站| 国产青草亚洲香蕉精品久久| 亚洲AV成人潮喷综合网| 青柠影视在线观看免费高清| 亚洲爆乳精品无码一区二区三区| 222www在线观看免费| 亚洲自国产拍揄拍| 亚洲男人在线无码视频| 久久午夜夜伦鲁鲁片免费无码 | 亚洲精品中文字幕麻豆| a级毛片无码免费真人| 无套内谢孕妇毛片免费看看| 亚洲VA中文字幕无码毛片| 99re热免费精品视频观看| 香蕉视频在线观看免费| 亚洲ⅴ国产v天堂a无码二区| 最近中文字幕无免费视频| 一级毛片在播放免费| 亚洲嫩草影院在线观看| 日韩精品电影一区亚洲| 8888四色奇米在线观看免费看| 亚洲国产欧美一区二区三区 | 亚洲Av无码乱码在线znlu| 四虎成人精品永久免费AV|