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

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

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

    Feeling

        三人行,必有我師焉

       ::  :: 新隨筆 :: 聯系 ::  :: 管理 ::
      185 隨筆 :: 0 文章 :: 392 評論 :: 0 Trackbacks

    2008年5月18日 #

         摘要: 很多網上下載的PDF文件都包含各種形式的水印,本文主要闡述如何使用易轉換一鍵刪除PDF文件中的各種圖片水印和文字水印  閱讀全文
    posted @ 2021-03-09 20:29 三人行,必有我師焉 閱讀(437) | 評論 (0)編輯 收藏

    Spark源代碼下載地址: http://spark.apache.org/downloads.html

    下載后,直接用 Scala IDE 通過已存在的項目導入到Eclipse workspace中去,然后Eclipse會自動進行編譯。第一次編譯會報很多錯誤,不過總的來說,導致編譯錯誤的源頭有三個:
    1、Scala編譯器版本錯誤
    2、Eclipse Maven插件不能自動識別spark project的一些pom,報Plugin execution not covered by lifecycle configuration異常
    3、一些項目,maven會自動生成scala和java文件,但是這些自動生成的代碼文件沒有配置在eclipse項目的classpath里。

    針對第一種錯誤,比較簡單,對于每個scala項目,右鍵屬性選擇spark對應的scala編譯器版本。



    當然spark代碼里的項目有幾十個,只能手工一個個設置了,比較傻,沒辦法,還不停的彈出對話框,不停地回車吧。

    編譯的難點主要在第二種錯誤上,比如spark-sql項目的pom, 里面有個build-helper-maven-plugin,它下面的execution,eclipse maven插件無法識別,報Plugin execution not covered by lifecycle configuration異常,解決方案參見 https://www.eclipse.org/m2e/documentation/m2e-execution-not-covered.html,先使用 Eclipse quick-fix選項自動修復,忽略此 maven goal,Eclipse 會為 pom.xml自動添加一段xml代碼,包含在 pluginManagement section中,里面有一段 <action><ignore/></action>,此處手動修改成
    <action>
        <execute>
            <runOnIncremental>false</runOnIncremental>
        </execute>
    </action>
    然后右鍵 maven update project 就OK了。

    一共有5個project需要修改pom,如圖


    修改pom后重新編譯,依舊會報一些錯誤,這些錯誤都是由于maven自動生成的java和scala代碼沒有添加到classpath里導致的編譯錯誤,只需要手工添加一下即可,需要手工添加項目有 spark-streaming-flume-sink 的 src_managed\main\compiled_avro 目錄 和 spark-sql 項目的 test\gen-java 目錄。

    全部編譯好以后的截圖:


    修改完以后,Spark代碼全部編譯下來大概耗時25分鐘左右(CPU 雙核 I7 4600)

    原文地址:http://www.tkk7.com/cnfree/archive/2016/11/08/431965.html
    posted @ 2016-11-08 13:12 三人行,必有我師焉 閱讀(2255) | 評論 (0)編輯 收藏

      Spark簡介

      Spark是整個BDAS的核心組件,是一個大數據分布式編程框架,不僅實現了MapReduce的算子map 函數和reduce函數及計算模型,還提供更為豐富的算子,如filter、join、groupByKey等。是一個用來實現快速而同用的集群計算的平臺。

      Spark將分布式數據抽象為彈性分布式數據集(RDD),實現了應用任務調度、RPC、序列化和壓縮,并為運行在其上的上層組件提供API。其底層采用Scala這種函數式語言書寫而成,并且所提供的API深度借鑒Scala函數式的編程思想,提供與Scala類似的編程接口

      Sparkon Yarn

      

      從用戶提交作業到作業運行結束整個運行期間的過程分析。

      一、客戶端進行操作

    1. 根據yarnConf來初始化yarnClient,并啟動yarnClient

    2. 創建客戶端Application,并獲取Application的ID,進一步判斷集群中的資源是否滿足executor和ApplicationMaster申請的資源,如果不滿足則拋出IllegalArgumentException;

    3. 設置資源、環境變量:其中包括了設置Application的Staging目錄、準備本地資源(jar文件、log4j.properties)、設置Application其中的環境變量、創建Container啟動的Context等;

    4. 設置Application提交的Context,包括設置應用的名字、隊列、AM的申請的Container、標記該作業的類型為Spark;

    5. 申請Memory,并最終通過yarnClient.submitApplication向ResourceManager提交該Application。

      當作業提交到YARN上之后,客戶端就沒事了,甚至在終端關掉那個進程也沒事,因為整個作業運行在YARN集群上進行,運行的結果將會保存到HDFS或者日志中。

      二、提交到YARN集群,YARN操作

    1. 運行ApplicationMaster的run方法;

    2. 設置好相關的環境變量。

    3. 創建amClient,并啟動;

    4. 在Spark UI啟動之前設置Spark UI的AmIpFilter;

    5. 在startUserClass函數專門啟動了一個線程(名稱為Driver的線程)來啟動用戶提交的Application,也就是啟動了Driver。在Driver中將會初始化SparkContext;

    6. 等待SparkContext初始化完成,最多等待spark.yarn.applicationMaster.waitTries次數(默認為10),如果等待了的次數超過了配置的,程序將會退出;否則用SparkContext初始化yarnAllocator;

    7. 當SparkContext、Driver初始化完成的時候,通過amClient向ResourceManager注冊ApplicationMaster

    8. 分配并啟動Executeors。在啟動Executeors之前,先要通過yarnAllocator獲取到numExecutors個Container,然后在Container中啟動Executeors。

        那么這個Application將失敗,將Application Status標明為FAILED,并將關閉SparkContext。其實,啟動Executeors是通過ExecutorRunnable實現的,而ExecutorRunnable內部是啟動CoarseGrainedExecutorBackend的。

    9. 最后,Task將在CoarseGrainedExecutorBackend里面運行,然后運行狀況會通過Akka通知CoarseGrainedScheduler,直到作業運行完成。

      Spark節點的概念

      一、Spark驅動器是執行程序中的main()方法的進程。它執行用戶編寫的用來創建SparkContext(初始化)、創建RDD,以及運行RDD的轉化操作和行動操作的代碼。

      驅動器節點driver的職責:

    1. 把用戶程序轉為任務task(driver)

        Spark驅動器程序負責把用戶程序轉化為多個物理執行單元,這些單元也被稱之為任務task(詳解見備注)

    2. 為執行器節點調度任務(executor)

        有了物理計劃之后,Spark驅動器在各個執行器節點進程間協調任務的調度。Spark驅動器程序會根據當前的執行器節點,把所有任務基于數據所在位置分配給合適的執行器進程。當執行任務時,執行器進程會把緩存的數據存儲起來,而驅動器進程同樣會跟蹤這些緩存數據的位置,并利用這些位置信息來調度以后的任務,以盡量減少數據的網絡傳輸。(就是所謂的移動計算,而不移動數據)。

      二、執行器節點

      作用:

    1. 負責運行組成Spark應用的任務,并將結果返回給驅動器進程;

    2. 通過自身的塊管理器(blockManager)為用戶程序中要求緩存的RDD提供內存式存儲。RDD是直接緩存在執行器進程內的,因此任務可以在運行時充分利用緩存數據加快運算。

      驅動器的職責:

      所有的Spark程序都遵循同樣的結構:程序從輸入數據創建一系列RDD,再使用轉化操作派生成新的RDD,最后使用行動操作手機或存儲結果RDD,Spark程序其實是隱式地創建出了一個由操作組成的邏輯上的有向無環圖DAG。當驅動器程序執行時,它會把這個邏輯圖轉為物理執行計劃。

      這樣 Spark就把邏輯計劃轉為一系列步驟(stage),而每個步驟又由多個任務組成。這些任務會被打包送到集群中。

      Spark初始化

    1. 每個Spark應用都由一個驅動器程序來發起集群上的各種并行操作。驅動器程序包含應用的main函數,并且定義了集群上的分布式數據集,以及對該分布式數據集應用了相關操作。

    2. 驅動器程序通過一個SparkContext對象來訪問spark,這個對象代表對計算集群的一個連接。(比如在sparkshell啟動時已經自動創建了一個SparkContext對象,是一個叫做SC的變量。(下圖,查看變量sc)

        

    3. 一旦創建了sparkContext,就可以用它來創建RDD。比如調用sc.textFile()來創建一個代表文本中各行文本的RDD。(比如vallinesRDD = sc.textFile(“yangsy.text”),val spark = linesRDD.filter(line=>line.contains(“spark”),spark.count())

        執行這些操作,驅動器程序一般要管理多個執行器,就是我們所說的executor節點。

    4. 在初始化SparkContext的同時,加載sparkConf對象來加載集群的配置,從而創建sparkContext對象。

        從源碼中可以看到,在啟動thriftserver時,調用了spark- daemon.sh文件,該文件源碼如左圖,加載spark_home下的conf中的文件。

        

        (在執行后臺代碼時,需要首先創建conf對象,加載相應參數, val sparkConf = newSparkConf().setMaster("local").setAppName("cocapp").set("spark.executor.memory","1g"), val sc: SparkContext = new SparkContext(sparkConf))

      RDD工作原理:

      RDD(Resilient DistributedDatasets)[1] ,彈性分布式數據集,是分布式內存的一個抽象概念,RDD提供了一種高度受限的共享內存模型,即RDD是只讀的記錄分區的集合,只能通過在其他RDD執行確定的轉換操作(如map、join和group by)而創建,然而這些限制使得實現容錯的開銷很低。對開發者而言,RDD可以看作是Spark的一個對象,它本身運行于內存中,如讀文件是一個RDD,對文件計算是一個RDD,結果集也是一個RDD ,不同的分片、數據之間的依賴、key-value類型的map數據都可以看做RDD。

      主要分為三部分:創建RDD對象,DAG調度器創建執行計劃,Task調度器分配任務并調度Worker開始運行。

      SparkContext(RDD相關操作)→通過(提交作業)→(遍歷RDD拆分stage→生成作業)DAGScheduler→通過(提交任務集)→任務調度管理(TaskScheduler)→通過(按照資源獲取任務)→任務調度管理(TaskSetManager)

      Transformation返回值還是一個RDD。它使用了鏈式調用的設計模式,對一個RDD進行計算后,變換成另外一個RDD,然后這個RDD又可以進行另外一次轉換。這個過程是分布式的。

      Action返回值不是一個RDD。它要么是一個Scala的普通集合,要么是一個值,要么是空,最終或返回到Driver程序,或把RDD寫入到文件系統中

      轉換(Transformations)(如:map, filter, groupBy, join等),Transformations操作是Lazy的,也就是說從一個RDD轉換生成另一個RDD的操作不是馬上執行,Spark在遇到Transformations操作時只會記錄需要這樣的操作,并不會去執行,需要等到有Actions操作的時候才會真正啟動計算過程進行計算。

      操作(Actions)(如:count, collect, save等),Actions操作會返回結果或把RDD數據寫到存儲系統中。Actions是觸發Spark啟動計算的動因。

      它們本質區別是:Transformation返回值還是一個RDD。它使用了鏈式調用的設計模式,對一個RDD進行計算后,變換成另外一個RDD,然后這個RDD又可以進行另外一次轉換。這個過程是分布式的。Action返回值不是一個RDD。它要么是一個Scala的普通集合,要么是一個值,要么是空,最終或返回到Driver程序,或把RDD寫入到文件系統中。關于這兩個動作,在Spark開發指南中會有就進一步的詳細介紹,它們是基于Spark開發的核心。

      RDD基礎

    1. Spark中的RDD就是一個不可變的分布式對象集合。每個RDD都被分為多個分區,這些分區運行在集群的不同節點上。創建RDD的方法有兩種:一種是讀取一個外部數據集;一種是在群東程序里分發驅動器程序中的對象集合,不如剛才的示例,讀取文本文件作為一個字符串的RDD的示例。

    2. 創建出來后,RDD支持兩種類型的操作:轉化操作和行動操作

        轉化操作會由一個RDD生成一個新的RDD。(比如剛才的根據謂詞篩選)

        行動操作會對RDD計算出一個結果,并把結果返回到驅動器程序中,或把結果存儲到外部存儲系統(比如HDFS)中。比如first()操作就是一個行動操作,會返回RDD的第一個元素。

        注:轉化操作與行動操作的區別在于Spark計算RDD的方式不同。雖然你可以在任何時候定義一個新的RDD,但Spark只會惰性計算這些RDD。它們只有第一個在一個行動操作中用到時,才會真正的計算。之所以這樣設計,是因為比如剛才調用sc.textFile(...)時就把文件中的所有行都讀取并存儲起來,就會消耗很多存儲空間,而我們馬上又要篩選掉其中的很多數據。

        這里還需要注意的一點是,spark會在你每次對它們進行行動操作時重新計算。如果想在多個行動操作中重用同一個RDD,那么可以使用RDD.persist()或RDD.collect()讓Spark把這個RDD緩存下來。(可以是內存,也可以是磁盤)

    3. Spark會使用譜系圖來記錄這些不同RDD之間的依賴關系,Spark需要用這些信息來按需計算每個RDD,也可以依靠譜系圖在持久化的RDD丟失部分數據時用來恢復所丟失的數據。(如下圖,過濾errorsRDD與warningsRDD,最終調用union()函數)

        

      RDD計算方式

      

      RDD的寬窄依賴

      

      窄依賴 (narrowdependencies) 和寬依賴 (widedependencies) 。窄依賴是指 父 RDD 的每個分區都只被子 RDD 的一個分區所使用 。相應的,那么寬依賴就是指父 RDD 的分區被多個子 RDD 的分區所依賴。例如, map 就是一種窄依賴,而 join 則會導致寬依賴

      這種劃分有兩個用處。首先,窄依賴支持在一個結點上管道化執行。例如基于一對一的關系,可以在 filter 之后執行 map 。其次,窄依賴支持更高效的故障還原。因為對于窄依賴,只有丟失的父 RDD 的分區需要重新計算。而對于寬依賴,一個結點的故障可能導致來自所有父 RDD 的分區丟失,因此就需要完全重新執行。因此對于寬依賴,Spark 會在持有各個父分區的結點上,將中間數據持久化來簡化故障還原,就像 MapReduce 會持久化 map 的輸出一樣。

      SparkExample

      

      步驟 1 :創建 RDD 。上面的例子除去最后一個 collect 是個動作,不會創建 RDD 之外,前面四個轉換都會創建出新的 RDD 。因此第一步就是創建好所有 RDD( 內部的五項信息 ) 。

      步驟 2 :創建執行計劃。Spark 會盡可能地管道化,并基于是否要重新組織數據來劃分 階段 (stage) ,例如本例中的 groupBy() 轉換就會將整個執行計劃劃分成兩階段執行。最終會產生一個 DAG(directedacyclic graph ,有向無環圖 ) 作為邏輯執行計劃。

      步驟 3 :調度任務。 將各階段劃分成不同的 任務 (task) ,每個任務都是數據和計算的合體。在進行下一階段前,當前階段的所有任務都要執行完成。因為下一階段的第一個轉換一定是重新組織數據的,所以必須等當前階段所有結果數據都計算出來了才能繼續。

      假設本例中的 hdfs://names 下有四個文件塊,那么 HadoopRDD 中 partitions 就會有四個分區對應這四個塊數據,同時 preferedLocations 會指明這四個塊的最佳位置。現在,就可以創建出四個任務,并調度到合適的集群結點上。

      Spark數據分區

    1. Spark的特性是對數據集在節點間的分區進行控制。在分布式系統中,通訊的代價是巨大的,控制數據分布以獲得最少的網絡傳輸可以極大地提升整體性能。Spark程序可以通過控制RDD分區方式來減少通訊的開銷。

    2. Spark中所有的鍵值對RDD都可以進行分區。確保同一組的鍵出現在同一個節點上。比如,使用哈希分區將一個RDD分成了100個分區,此時鍵的哈希值對100取模的結果相同的記錄會被放在一個節點上。

        (可使用partitionBy(newHashPartitioner(100)).persist()來構造100個分區)

    3. Spark中的許多操作都引入了將數據根據鍵跨界點進行混洗的過程。(比如:join(),leftOuterJoin(),groupByKey(),reducebyKey()等)對于像reduceByKey()這樣只作用于單個RDD的操作,運行在未分區的RDD上的時候會導致每個鍵的所有對應值都在每臺機器上進行本地計算。

      SparkSQL的shuffle過程

      

      Spark SQL的核心是把已有的RDD,帶上Schema信息,然后注冊成類似sql里的”Table”,對其進行sql查詢。這里面主要分兩部分,一是生成SchemaRD,二是執行查詢。

      如果是spark-hive項目,那么讀取metadata信息作為Schema、讀取hdfs上數據的過程交給Hive完成,然后根據這倆部分生成SchemaRDD,在HiveContext下進行hql()查詢。

      SparkSQL結構化數據

    1. 首先說一下ApacheHive,Hive可以在HDFS內或者在其他存儲系統上存儲多種格式的表。SparkSQL可以讀取Hive支持的任何表。要把Spark SQL連接已有的hive上,需要提供Hive的配置文件。hive-site.xml文件復制到spark的conf文件夾下。再創建出HiveContext對象(sparksql的入口),然后就可以使用HQL來對表進行查詢,并以由行足證的RDD的形式拿到返回的數據。

    2. 創建Hivecontext并查詢數據

        importorg.apache.spark.sql.hive.HiveContext

        valhiveCtx = new org.apache.spark.sql.hive.HiveContext(sc)

        valrows = hiveCtx.sql(“SELECT name,age FROM users”)

        valfitstRow – rows.first()

        println(fitstRow.getSgtring(0)) //字段0是name字段

    3. 通過jdbc連接外部數據源更新與加載

        Class.forName("com.mysql.jdbc.Driver")

        val conn =DriverManager.getConnection(mySQLUrl)

        val stat1 =conn.createStatement()

        stat1.execute("UPDATE CI_LABEL_INFO set DATA_STATUS_ID = 2 , DATA_DATE ='" + dataDate +"' where LABEL_ID in ("+allCreatedLabels.mkString(",")+")")

        stat1.close()

        //加載外部數據源數據到內存

        valDIM_COC_INDEX_MODEL_TABLE_CONF =sqlContext.jdbc(mySQLUrl,"DIM_COC_INDEX_MODEL_TABLE_CONF").cache()

        val targets =DIM_COC_INDEX_MODEL_TABLE_CONF.filter("TABLE_DATA_CYCLE ="+TABLE_DATA_CYCLE).collect

      SparkSQL解析

      

      首先說下傳統數據庫的解析,傳統數據庫的解析過程是按Rusult、Data Source、Operation的次序來解析的。傳統數據庫先將讀入的SQL語句進行解析,分辨出SQL語句中哪些詞是關鍵字(如select,from,where),哪些是表達式,哪些是Projection,哪些是Data Source等等。進一步判斷SQL語句是否規范,不規范就報錯,規范則按照下一步過程綁定(Bind)。過程綁定是將SQL語句和數據庫的數據字典(列,表,視圖等)進行綁定,如果相關的Projection、Data Source等都存在,就表示這個SQL語句是可以執行的。在執行過程中,有時候甚至不需要讀取物理表就可以返回結果,比如重新運行剛運行過的SQL語句,直接從數據庫的緩沖池中獲取返回結果。在數據庫解析的過程中SQL語句時,將會把SQL語句轉化成一個樹形結構來進行處理,會形成一個或含有多個節點(TreeNode)的Tree,然后再后續的處理政對該Tree進行一系列的操作。

      Spark SQL對SQL語句的處理和關系數據庫對SQL語句的解析采用了類似的方法,首先會將SQL語句進行解析,然后形成一個Tree,后續如綁定、優化等處理過程都是對Tree的操作,而操作方法是采用Rule,通過模式匹配,對不同類型的節點采用不同的操作。SparkSQL有兩個分支,sqlContext和hiveContext。sqlContext現在只支持SQL語法解析器(Catalyst),hiveContext支持SQL語法和HiveContext語法解析器。

    原文地址:http://mt.sohu.com/20160522/n450849016.shtml

    posted @ 2016-09-08 13:11 三人行,必有我師焉 閱讀(252) | 評論 (0)編輯 收藏

    spark中有partition的概念(和slice是同一個概念,在spark1.2中官網已經做出了說明),一般每個partition對應一個task。在我的測試過程中,如果沒有設置spark.default.parallelism參數,spark計算出來的partition非常巨大,與我的cores非常不搭。我在兩臺機器上(8cores *2 +6g * 2)上,spark計算出來的partition達到2.8萬個,也就是2.9萬個tasks,每個task完成時間都是幾毫秒或者零點幾毫秒,執行起來非常緩慢。在我嘗試設置了 spark.default.parallelism 后,任務數減少到10,執行一次計算過程從minute降到20second。

    參數可以通過spark_home/conf/spark-default.conf配置文件設置。

    eg.

    spark.master  spark://master:7077 

    spark.default.parallelism  10 

    spark.driver.memory  2g 

    spark.serializer  org.apache.spark.serializer.KryoSerializer 

    spark.sql.shuffle.partitions  50

     

    下面是官網的相關描述:

    from:http://spark.apache.org/docs/latest/configuration.html

    Property NameDefaultMeaning
    spark.default.parallelism For distributed shuffle operations like reduceByKey and join, the largest number of partitions in a parent RDD. For operations likeparallelize with no parent RDDs, it depends on the cluster manager:
    • Local mode: number of cores on the local machine
    • Mesos fine grained mode: 8
    • Others: total number of cores on all executor nodes or 2, whichever is larger
    Default number of partitions in RDDs returned by transformations like joinreduceByKey, and parallelize when not set by user.

    from:http://spark.apache.org/docs/latest/tuning.html

    Level of Parallelism

    Clusters will not be fully utilized unless you set the level of parallelism for each operation high enough. Spark automatically sets the number of “map” tasks to run on each file according to its size (though you can control it through optional parameters to SparkContext.textFile, etc), and for distributed “reduce” operations, such as groupByKey and reduceByKey, it uses the largest parent RDD’s number of partitions. You can pass the level of parallelism as a second argument (see the spark.PairRDDFunctions documentation), or set the config propertyspark.default.parallelism to change the default. In general, we recommend 2-3 tasks per CPU core in your cluster.


    原文地址:http://www.cnblogs.com/wrencai/p/4231966.html

    posted @ 2016-09-08 13:07 三人行,必有我師焉 閱讀(2205) | 評論 (0)編輯 收藏

    Eclipse Class Decompiler是一款Eclipse插件,整合了多種反編譯器,和Eclipse Class Viewer無縫集成,能夠很方便的使用插件查看類庫源碼,進行Debug調試。
    同時還提供了在線自動查找源代碼,查看Class二進制字節碼的功能。
     

    Eclipse Class Decompiler對JDK的最低要求為JDK1.6, 能反編譯和debug各版本的Class文件,支持JDK8的Lambda語法,同時支持中文等非Ascii碼字符集的解析,支持Eclipse 3.6及以上所有版本的Eclipse。

    本插件支持Windows,Linux,Macosx 32位及64位操作系統。

    Github項目地址為:https://github.com/cnfree/Eclipse-Class-Decompiler

    請通過以下地址選擇一個可用的源在線安裝:

    http://cnfree.github.io/Eclipse-Class-Decompiler/update
    http://raw.githubusercontent.com/cnfree/eclipse/master/decompiler/update/
    http://www.cpupk.com/decompiler/update/

    離線包下載地址:
    https://github.com/cnfree/Eclipse-Class-Decompiler/releases/download/v2.10.0/eclipse-class-decompiler-update_v2.10.0.zip

     
    插件使用說明:

    下圖為Eclipse Class Decompiler的首選項頁面,可以選擇缺省的反編譯器工具,并進行反編譯器的基本設置。缺省的反編譯工具為JD-Core,JD-Core更為先進一些,支持泛型、Enum、注解等JDK1.5以后才有的新語法。

    首選項配置選項:
    1.重用緩存代碼:只會反編譯一次,以后每次打開該類文件,都顯示的是緩存的反編譯代碼。
    2.忽略已存在的源代碼:若未選中,則查看Class文件是否已綁定了Java源代碼,如果已綁定,則顯示Java源代碼,如果未綁定,則反編譯Class文件。若選中此項,則忽略已綁定的Java源代碼,顯示反編譯結果。
    3.顯示反編譯器報告:顯示反編譯器反編譯后生成的數據報告及異常信息。
    4.使用Eclipse代碼格式化工具:使用Eclipse格式化工具對反編譯結果重新格式化排版,反編譯整個Jar包時,此操作會消耗一些時間。
    5.使用Eclipse成員排序:使用Eclipse成員排序對反編譯結果重新格式化排版,反編譯整個Jar包時,此操作會消耗大量時間。
    6.以注釋方式輸出原始行號信息:如果Class文件包含原始行號信息,則會將行號信息以注釋的方式打印到反編譯結果中。
    7.根據行號對齊源代碼以便于調試:若選中該項,插件會采用AST工具分析反編譯結果,并根據行號信息調整代碼順序,以便于Debug過程中的單步跟蹤調試。
    8.設置類反編譯查看器作為缺省的類文件編輯器:默認為選中,將忽略Eclipse自帶的Class Viewer,每次Eclipse啟動后,默認使用本插件提供的類查看器打開Class文件。



    插件提供了系統菜單,工具欄,當打開了插件提供的類反編譯查看器后,會激活菜單和工具欄選項,可以方便的進行首選項配置,切換反編譯工具重新反編譯,以及導出反編譯結果。






    類反編譯查看器右鍵菜單包含了Eclipse自帶類查看器右鍵菜單的全部選項,并增加了一個“導出反編譯源代碼”菜單項。



    打開項目路徑下的Class文件,如果設置類反編譯查看器為缺省的查看器,直接雙擊Class文件即可,如果沒有設置為缺省查看器,可以使用右鍵菜單進行查看。




    同時插件也支持直接將外部的Class文件拖拽到Eclipse編輯器中進行反編譯。


    Eclipse Class Decompiler插件也提供了反編譯整個Jar文件或者Java包的反編譯。該操作支持Package Explorer對包顯示布局的操作,如果是平鋪模式布局,則導出的源代碼不包含子包,如果是層級模式布局,則導出選中的包及其所有的子包。




    Debug調試:可以在首選項選中對齊行號進行單步跟蹤調試,和普通的包含源代碼時的調試操作完全一致,同樣的也可以設置斷點進行跟蹤。當透視圖為Debug時,插件自動生成行號并進行對齊方便調試代碼,無需進行任何設置。


    博文地址:http://www.tkk7.com/cnfree/archive/2012/10/30/390457.html
    posted @ 2016-05-13 14:23 三人行,必有我師焉 閱讀(1314) | 評論 (5)編輯 收藏

    Java應用定制工廠(以下簡稱為JCB,Java Customization Builder)是一個針對Java輕量級桌面應用進行精簡優化的小工具,使用它可以精簡你的jar包,并自動生成一個精簡的JRE,也可以使用它生成一個Exe啟動引導程序,并且能夠對你的Java應用自動做Pack200和Unpack200處理。使用本工具定制的Java桌面應用通常不會超過10M(包含JRE),SWT客戶端程序相對于Swing客戶端程序更小,一般不會超過5M。

    JCB是一個Java應用,所以目標機器上必須安裝1.5以上版本的JDK用以啟動JCB,但是JCB可以用來精簡1.4版的JRE,并且JRE1.4精簡后的體積遠小于1.5以上的版本。

    1.新建JCB項目
    精簡JRE的步驟比較繁瑣,有可能精簡失敗,為了不重復之前的步驟,JCB提供一個項目文件用來保存精簡配置信息,擴展名為jcprj。這里我們創建一個項目,名為JCB


    Wizard需要輸入一個工程名和指定工程位置,至于下面的應用程序位置和定制JRE位置由JCB自動指定,這兒顯示出來僅供參考。

    此時最好Ctrl+S保存一下項目,否則退出后你之前的配置信息會全部丟失,因為你并沒有制定一個可用的項目配置文件。

    2. 配置JCB項目


    首先指定項目需要的jar文件,然后依次選擇項目的main class,啟動路徑默認為空,一般來說無需指定。然后設定應用程序參數和虛擬機參數。最后選定需要精簡的JRE,JCB當前支持1.4-1.7版本的JRE,未來可能會支持更高版本的JRE。

    右下角有2個單選按鈕:全部重新運行和增量運行。全部重新運行就會放棄之前的運行結果,增量運行就是會保留以前的運行結果。

    然后點擊“以Verbose模式運行”按鈕。Verbose模式運行Java程序,會顯示JVM加載的全部類信息,JCB需要這些類信息進行JRE的精簡,所以請盡可能的把應用所有的功能盡可能的跑一遍,跑的越全面,導致精簡出錯的可能性就越低。



    Verbose運行結果,這個頁面的顯示信息僅供參考,無實際用處。

    3. 分析項目的類依賴項


    分析類依賴模式有2個選項:重新完全分析和增量分析。完全分析會花費較多的時間。當使用verbose模式增量運行后,可以使用增量模式分析類依賴項,這樣可以節約大量的時間。類依賴分析會反編譯所有運行的類,分析類引用關系,但是無法獲取Class.forName這類動態類加載信息,所以需要Verbose模式運行的盡量全面,以避免這些動態加載的類的缺失。

    為什么需要分析類依賴關系呢?因為不同的操作系統,不同的硬件配置,JRE可能會采取策略模式加載不同的類,或者一些異常,Verbose模式一般不會加載,這樣換個硬件環境,僅僅使用Verbose模式的類可能會導致ClassNotFound這樣的異常,導致Java程序崩潰。


    4. 精簡JRE


    精簡JRE有兩種模式:使用Verbose運行結果和使用類依賴分析結果。前者只包含Verbose分析出來的類,精簡出來的JRE包很小,但是基本不具備跨平臺性。所以一般來說推薦選擇后者。

    如果你的程序包含Swing的客戶端,并且比較復雜的話,最好選中包含Swing選項。因為Swing的設計完全是動態化的加載,全部使用Class.forName方式,類依賴分析對Swing是無效的。當然選中該選項后,JRE的體積會增加許多。比較好的解決方案,是使用SWT替代Swing進行開發,或者盡量把你的程序跑全面,包括各種異常界面都跑出來。

    右下角有兩個按鈕,是用來自定義類和資源文件的,比如移除JAR包的MD5文件或者無用的文件。或者測試運行發現ClassNotFound異常,手動把缺少的類加進去,然后JCB會自動運行增量類依賴分析加載所有可能需要的類。

    選擇左上角的“精簡Jar包”按鈕,就可以對JRE進行精簡了,精簡完畢后可以點擊“查看精簡結果”按鈕進行查看。

    5.定制JRE


    上圖顯示了JRE精簡結果,JCB會自動分析所有的Class,生成精簡版JRE,包括需要的JAR,DLL和資源文件。一般來說精簡出來的JRE,普通功能都能正確完成,但是不排除有些功能不能正常使用,比如缺少某個資源文件或者DLL,需要手工添加。

    為了保證精簡的正確性,你需要進行運行測試,這一步是必須的,而且最好和Verbose運行模式一樣,把所有的功能都跑一遍,確認精簡無誤。



    如果測試運行有誤的話,請根據運行錯誤報告進行分析,如果缺少類,請使用Verbose模式重新運行相應的功能,或者在步驟四手工添加需要的類,然后重新生成依賴的JRE。如果缺少相關的DLL或者資源文件,也請手工添加,并且取消步驟四的“清理工作區選項”,否則每次精簡JRE都需要重新手工添加。

    到此為止,精簡JRE部分就算全部完成了,你最好使用Ctrl+S保存一下結果,以避免下次重做項目。

    JCB項目下載地址:http://www.sourceforge.net/projects/jcb
    posted @ 2013-03-03 17:25 三人行,必有我師焉 閱讀(5224) | 評論 (13)編輯 收藏

    1. 40億個無符號整數,找出一個不在這40億個整數中的數。可以換個方向思考, 99個小于100的數,找出一個不在這99個數中的小于100的數。
    首先把這99個數分為10組,按高位為0-9分,然后計算每組的數量,數量最少的那個肯定就是缺失的那個,然后遞歸……找最少的那個,組合起來的數肯定是缺失的。答案是按位運算找,和這個類似。

    2. 43億個無符號整數,找出一個重復的整數。也就是101個小于100的數,找出重復的那個數來。
    首先把這99個數分為10組,按高位為0-9分,然后計算每組的數量,數量最多的那組,肯定有重復的,一次類推找第二位……
    posted @ 2012-11-24 22:21 三人行,必有我師焉 閱讀(403) | 評論 (0)編輯 收藏

    When a object creates a new object, please use the dependency.

    When a object just uses a object, please use the association. 
    posted @ 2012-11-19 13:16 三人行,必有我師焉 閱讀(286) | 評論 (0)編輯 收藏

    comparator 

    Decorator Pattern and Adapter Pattern have the same alias name: wrapper. But they face different aspects. Decorator pattern changes the object function, but the adapter pattern changes the interface.

    The typical decorator pattern is the java OutputStream, you can use the BufferedOutputStream to wrap it, then get the extra function.
    The typical adapter pattern in the BIRT is the ElementAdapter, it can convert any object to an other object.

    Decorator pattern must extend the class which you want to wrap, but the adapter class must implements the interface using by the client.


    FlyWeight pattern extracts the same part of some different objects, and the part doesn't be changed when these objects changed. String class uses the FlyWeight pattern, jface 
    ImageRegistry also uses it. 
    FlyWeight can have a interface to get external data, and change the external data's status, but FlyWeight internal status shouldn't be changed.

    The Collections.sort() method implementation contains template method design pattern and strategy design pattern, but it doesn't contain the visitor design pattern. The Collections.sort() method uses the merge sort algorithm, you can't change it, but you can change the comparator logic, it's one step of the sort algorithm. So it's a template method pattern, but not a classic implementation, it uses the callback method to implement the pattern, but not extending the parent template class. The comparator class use the strategy design pattern, it not a visitor pattern, visitor pattern have a accept method to operate the element to deal some logic. 



    posted @ 2012-11-14 00:22 三人行,必有我師焉 閱讀(327) | 評論 (0)編輯 收藏

    1 歸并排序(MergeSort)

    歸并排序最差運行時間是O(nlogn),它是利用遞歸設計程序的典型例子。

    歸并排序的最基礎的操作就是合并兩個已經排好序的序列。

    假設我們有一個沒有排好序的序列,那么首先我們使用分割的辦法將這個序列分割成一個一個已經排好序的子序列。然后再利用歸并的方法將一個個的子序列合并成排序好的序列。分割和歸并的過程可以看下面的圖例。



    從上圖可以看出,我們首先把一個未排序的序列從中間分割成2部分,再把2部分分成4部分,依次分割下去,直到分割成一個一個的數據,再把這些數據兩兩歸并到一起,使之有序,不停的歸并,最后成為一個排好序的序列。

    如何把兩個已經排序好的子序列歸并成一個排好序的序列呢?可以參看下面的方法。

    假設我們有兩個已經排序好的子序列。
    序列A:1 23 34 65
    序列B:2 13 14 87
    那么可以按照下面的步驟將它們歸并到一個序列中。

    (1)首先設定一個新的數列C[8]。
    (2)A[0]和B[0]比較,A[0] = 1,B[0] = 2,A[0] < B[0],那么C[0] = 1
    (3)A[1]和B[0]比較,A[1] = 23,B[0] = 2,A[1] > B[0],那么C[1] = 2
    (4)A[1]和B[1]比較,A[1] = 23,B[1] = 13,A[1] > B[1],那么C[2] = 13
    (5)A[1]和B[2]比較,A[1] = 23,B[2] = 14,A[1] > B[2],那么C[3] = 14
    (6)A[1]和B[3]比較,A[1] = 23,B[3] = 87,A[1] < B[3],那么C[4] = 23
    (7)A[2]和B[3]比較,A[2] = 34,B[3] = 87,A[2] < B[3],那么C[5] = 34
    (8)A[3]和B[3]比較,A[3] = 65,B[3] = 87,A[3] < B[3],那么C[6] = 65
    (9)最后將B[3]復制到C中,那么C[7] = 87。歸并完成。

    如果我們清楚了上面的分割和歸并過程,那么我們就可以用遞歸的方法得到歸并算法的實現。

        public class MergeSorter
        {
            
    private static int[] myArray;
            
    private static int arraySize;

            
    public static void Sort( int[] a )
            {
                myArray 
    = a;
                arraySize 
    = myArray.Length;
                MergeSort();
            }

            
    /// <summary>
            
    /// 利用歸并的方法排序數組,首先將序列分割
            
    /// 然后將數列歸并,這個算法需要雙倍的存儲空間
            
    /// 時間是O(nlgn)
            
    /// </summary>
            private static void MergeSort()
            {
                
    int[] temp = new int[arraySize];
                MSort( temp, 
    0, arraySize - 1);
            }

            
    private static void MSort(int[] temp, int left, int right)
            {
                
    int mid;

                
    if (right > left)
                {
                    mid 
    = (right + left) / 2;
                    MSort( temp, left, mid); 
    //分割左邊的序列
                    MSort(temp, mid+1, right);//分割右邊的序列
                    Merge(temp, left, mid+1, right);//歸并序列
                }
            }

            
    private static void Merge( int[] temp, int left, int mid, int right)
            {
                
    int i, left_end, num_elements, tmp_pos;

                left_end 
    = mid - 1;
                tmp_pos 
    = left;
                num_elements 
    = right - left + 1;

                
    while ((left <= left_end) && (mid <= right)) 
                {
                    
    if (myArray[left] <= myArray[mid]) //將左端序列歸并到temp數組中
                    {
                        temp[tmp_pos] 
    = myArray[left];
                        tmp_pos 
    = tmp_pos + 1;
                        left 
    = left +1;
                    }
                    
    else//將右端序列歸并到temp數組中
                    {
                        temp[tmp_pos] 
    = myArray[mid];
                        tmp_pos 
    = tmp_pos + 1;
                        mid 
    = mid + 1;
                    }
                }

                
    while (left <= left_end) //拷貝左邊剩余的數據到temp數組中
                {
                    temp[tmp_pos] 
    = myArray[left];
                    left 
    = left + 1;
                    tmp_pos 
    = tmp_pos + 1;
                }
                
    while (mid <= right) //拷貝右邊剩余的數據到temp數組中
                {
                    temp[tmp_pos] 
    = myArray[mid];
                    mid 
    = mid + 1;
                    tmp_pos 
    = tmp_pos + 1;
                }

                
    for (i=0; i < num_elements; i++//將所有元素拷貝到原始數組中
                {
                    myArray[right] 
    = temp[right];
                    right 
    = right - 1;
                }
            }
        }


    歸并排序算法是一種O(nlogn)的算法。它的最差,平均,最好時間都是O(nlogn)。但是它需要額外的存儲空間,這在某些內存緊張的機器上會受到限制。

    歸并算法是又分割和歸并兩部分組成的。對于分割部分,如果我們使用二分查找的話,時間是O(logn),在最后歸并的時候,時間是O(n),所以總的時間是O(nlogn)。

    2 堆排序(HeapSort)

    堆排序屬于百萬俱樂部的成員。它特別適合超大數據量(百萬條記錄以上)的排序。因為它并不使用遞歸(因為超大數據量的遞歸可能會導致堆棧溢出),而且它的時間也是O(nlogn)。還有它并不需要大量的額外存儲空間。

    堆排序的思路是:

    (1)將原始未排序的數據建成一個堆。
    (2)建成堆以后,最大值在堆頂,也就是第0個元素,這時候將第零個元素和最后一個元素交換。
    (3)這時候將從0到倒數第二個元素的所有數據當成一個新的序列,建一個新的堆,再次交換第一個和最后一個元素,依次類推,就可以將所有元素排序完畢。

    建立堆的過程如下面的圖所示:


    堆排序的具體算法如下:

    public class HeapSorter 
        {
            
    private static int[] myArray;
            
    private static int arraySize;

            
    public static void Sort( int[] a )
            {
                myArray 
    = a;
                arraySize 
    = myArray.Length;
                HeapSort();
            }

            
    private static void HeapSort()
            {
                BuildHeap();            
    //將原始序列建成一個堆

                
    while ( arraySize > 1 )
                {
                    arraySize
    --;
                    Exchange ( 
    0, arraySize );//將最大值放在數組的最后
                    DownHeap ( 0 );  //將序列從0到n-1看成一個新的序列,重新建立堆
                } 
            }

            
    private static void BuildHeap()
            {
                
    for (int v=arraySize/2-1; v>=0; v--)
                    DownHeap ( v );
            }

            
    //利用向下遍歷子節點建立堆
            private static void DownHeap( int v )
            {
                
    int w = 2 * v + 1;                     // 節點w是節點v的第一個子節點

                
    while (w < arraySize)
                {
                    
    if ( w+1 < arraySize )        // 如果節點v下面有第二個字節點
                        if ( myArray[w+1> myArray[w] ) 
                            w
    ++;                        // 將子節點w設置成節點v下面值最大的子節點

                     
    // 節點v已經大于子節點w,有了堆的性質,那么返回
                    if ( myArray[v] >= myArray[w] ) 
                        
    return;   
                    
                    Exchange( v, w );     
    // 如果不是,就交換節點v和節點w的值
                    v = w;        
                    w 
    = 2 * v + 1;            // 繼續向下找子節點
                }
            }

            
    //交換數據
            private static void Exchange( int i, int j )
            {
                
    int t = myArray[i];
                myArray[i] 
    = myArray[j];
                myArray[j] 
    = t;
            }
        }    


     

    堆排序主要用于超大規模的數據的排序。因為它不需要額外的存儲空間,也不需要大量的遞歸。

    3 幾種O(nlogn)算法的初步比較

    我們可以從下表看到幾種O(nlogn)算法的效率的區別。所有的數據都使用.Net的Random類產生,每種算法運行100次,時間的單位為毫秒。


    500隨機整數5000隨機整數20000隨機整數
    合并排序0.31251.56257.03125
     Shell排序0.31251.256.875
    堆排序0.468752.18756.71875
    快速排序0.156250.6252.8125

    從上表可以明顯地看出,快速排序是最快的算法。這也就給了我們一個結論,對于一般的應用來說,我們總是選擇快速排序作為我們的排序算法,當數據量非常大(百萬數量級)我們可以使用堆排序,如果內存空間非常緊張,我們可以使用Shell排序。但是這意味著我們不得不損失速度。 

    /******************************************************************************************
     *【Author】:flyingbread
     *【Date】:2007年2月2日
     *【Notice】:
     *1、本文為原創技術文章,首發博客園個人站點(http://flyingbread.cnblogs.com/),轉載和引用請注明作者及出處。
     *2、本文必須全文轉載和引用,任何組織和個人未授權不能修改任何內容,并且未授權不可用于商業。
     *3、本聲明為文章一部分,轉載和引用必須包括在原文中。
     ******************************************************************************************/
    posted @ 2012-11-10 23:18 三人行,必有我師焉 閱讀(615) | 評論 (2)編輯 收藏

    1 快速排序(QuickSort)

    快速排序是一個就地排序,分而治之,大規模遞歸的算法。從本質上來說,它是歸并排序的就地版本。快速排序可以由下面四步組成。

    (1) 如果不多于1個數據,直接返回。
    (2) 一般選擇序列最左邊的值作為支點數據。
    (3) 將序列分成2部分,一部分都大于支點數據,另外一部分都小于支點數據。
    (4) 對兩邊利用遞歸排序數列。

    快速排序比大部分排序算法都要快。盡管我們可以在某些特殊的情況下寫出比快速排序快的算法,但是就通常情況而言,沒有比它更快的了。快速排序是遞歸的,對于內存非常有限的機器來說,它不是一個好的選擇。 

    2 歸并排序(MergeSort)

    歸并排序先分解要排序的序列,從1分成2,2分成4,依次分解,當分解到只有1個一組的時候,就可以排序這些分組,然后依次合并回原來的序列中,這樣就可以排序所有數據。合并排序比堆排序稍微快一點,但是需要比堆排序多一倍的內存空間,因為它需要一個額外的數組。

    3 堆排序(HeapSort)

    堆排序適合于數據量非常大的場合(百萬數據)。

    堆排序不需要大量的遞歸或者多維的暫存數組。這對于數據量非常巨大的序列是合適的。比如超過數百萬條記錄,因為快速排序,歸并排序都使用遞歸來設計算法,在數據量非常大的時候,可能會發生堆棧溢出錯誤。

    堆排序會將所有的數據建成一個堆,最大的數據在堆頂,然后將堆頂數據和序列的最后一個數據交換。接下來再次重建堆,交換數據,依次下去,就可以排序所有的數據。

    4 Shell排序(ShellSort)

    Shell排序通過將數據分成不同的組,先對每一組進行排序,然后再對所有的元素進行一次插入排序,以減少數據交換和移動的次數。平均效率是O(nlogn)。其中分組的合理性會對算法產生重要的影響。現在多用D.E.Knuth的分組方法。

    Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相對比較簡單,它適合于數據量在5000以下并且速度并不是特別重要的場合。它對于數據量較小的數列重復排序是非常好的。

    5 插入排序(InsertSort)

    插入排序通過把序列中的值插入一個已經排序好的序列中,直到該序列的結束。插入排序是對冒泡排序的改進。它比冒泡排序快2倍。一般不用在數據大于1000的場合下使用插入排序,或者重復排序超過200數據項的序列。

    6 冒泡排序(BubbleSort)

    冒泡排序是最慢的排序算法。在實際運用中它是效率最低的算法。它通過一趟又一趟地比較數組中的每一個元素,使較大的數據下沉,較小的數據上升。它是O(n^2)的算法。

    7 交換排序(ExchangeSort)和選擇排序(SelectSort)

    這兩種排序方法都是交換方法的排序算法,效率都是 O(n2)。在實際應用中處于和冒泡排序基本相同的地位。它們只是排序算法發展的初級階段,在實際中使用較少。

    8 基數排序(RadixSort)

    基數排序和通常的排序算法并不走同樣的路線。它是一種比較新穎的算法,但是它只能用于整數的排序,如果我們要把同樣的辦法運用到浮點數上,我們必須了解浮點數的存儲格式,并通過特殊的方式將浮點數映射到整數上,然后再映射回去,這是非常麻煩的事情,因此,它的使用同樣也不多。而且,最重要的是,這樣算法也需要較多的存儲空間。

    9 總結

    下面是一個總的表格,大致總結了我們常見的所有的排序算法的特點。
    排序法 平均時間最差情形穩定度額外空間備注
    冒泡 O(n2)  O(n2) 穩定O(1)n小時較好
    交換  O(n2)  O(n2)不穩定O(1)n小時較好
    選擇 O(n2) O(n2)不穩定O(1)n小時較好
    插入 O(n2) O(n2)穩定O(1)大部分已排序時較好
    基數O(logRB)O(logRB)穩定O(n)

    B是真數(0-9),

    R是基數(個十百)

    ShellO(nlogn)O(ns) 1<2不穩定O(1)s是所選分組
    快速O(nlogn)O(n2)不穩定O(nlogn)n大時較好
    歸并O(nlogn)O(nlogn)穩定O(1)n大時較好
    O(nlogn)O(nlogn)不穩定O(1)n大時較好

    posted @ 2012-11-10 22:30 三人行,必有我師焉 閱讀(336) | 評論 (0)編輯 收藏

    Eclipse Class Decompiler是一款Eclipse插件,整合了多種反編譯器,和Eclipse Class Viewer無縫集成,能夠很方便的使用插件查看類庫源碼,進行Debug調試。
    同時還提供了在線自動查找源代碼,查看Class二進制字節碼的功能。 


    Eclipse Class Decompiler對JDK的最低要求為JDK1.6, 能反編譯和debug各版本的Class文件,支持JDK8的Lambda語法,同時支持中文等非Ascii碼字符集的解析,支持Eclipse 3.6及以上所有版本的Eclipse。

    本插件支持Windows,Linux,Macosx 32位及64位操作系統。

    Github項目地址為:https://github.com/cnfree/Eclipse-Class-Decompiler

    請通過以下地址選擇一個可用的源在線安裝:

    http://cnfree.github.io/Eclipse-Class-Decompiler/update
    http://raw.githubusercontent.com/cnfree/eclipse/master/decompiler/update/
    http://www.cpupk.com/decompiler/update/

    離線包下載地址:
    https://github.com/cnfree/Eclipse-Class-Decompiler/releases/download/v2.10.0/eclipse-class-decompiler-update_v2.10.0.zip
     
    插件使用說明:

    下圖為Eclipse Class Decompiler的首選項頁面,可以選擇缺省的反編譯器工具,并進行反編譯器的基本設置。缺省的反編譯工具為JD-Core,JD-Core更為先進一些,支持泛型、Enum、注解等JDK1.5以后才有的新語法。

    首選項配置選項:
    1.重用緩存代碼:只會反編譯一次,以后每次打開該類文件,都顯示的是緩存的反編譯代碼。
    2.忽略已存在的源代碼:若未選中,則查看Class文件是否已綁定了Java源代碼,如果已綁定,則顯示Java源代碼,如果未綁定,則反編譯Class文件。若選中此項,則忽略已綁定的Java源代碼,顯示反編譯結果。
    3.顯示反編譯器報告:顯示反編譯器反編譯后生成的數據報告及異常信息。
    4.使用Eclipse代碼格式化工具:使用Eclipse格式化工具對反編譯結果重新格式化排版,反編譯整個Jar包時,此操作會消耗一些時間。
    5.使用Eclipse成員排序:使用Eclipse成員排序對反編譯結果重新格式化排版,反編譯整個Jar包時,此操作會消耗大量時間。
    6.以注釋方式輸出原始行號信息:如果Class文件包含原始行號信息,則會將行號信息以注釋的方式打印到反編譯結果中。
    7.根據行號對齊源代碼以便于調試:若選中該項,插件會采用AST工具分析反編譯結果,并根據行號信息調整代碼順序,以便于Debug過程中的單步跟蹤調試。
    8.設置類反編譯查看器作為缺省的類文件編輯器:默認為選中,將忽略Eclipse自帶的Class Viewer,每次Eclipse啟動后,默認使用本插件提供的類查看器打開Class文件。



    插件提供了系統菜單,工具欄,當打開了插件提供的類反編譯查看器后,會激活菜單和工具欄選項,可以方便的進行首選項配置,切換反編譯工具重新反編譯,以及導出反編譯結果。






    類反編譯查看器右鍵菜單包含了Eclipse自帶類查看器右鍵菜單的全部選項,并增加了一個“導出反編譯源代碼”菜單項。



    打開項目路徑下的Class文件,如果設置類反編譯查看器為缺省的查看器,直接雙擊Class文件即可,如果沒有設置為缺省查看器,可以使用右鍵菜單進行查看。




    同時插件也支持直接將外部的Class文件拖拽到Eclipse編輯器中進行反編譯。


    Eclipse Class Decompiler插件也提供了反編譯整個Jar文件或者Java包的反編譯。該操作支持Package Explorer對包顯示布局的操作,如果是平鋪模式布局,則導出的源代碼不包含子包,如果是層級模式布局,則導出選中的包及其所有的子包。




    Debug調試:可以在首選項選中對齊行號進行單步跟蹤調試,和普通的包含源代碼時的調試操作完全一致,同樣的也可以設置斷點進行跟蹤。當透視圖為Debug時,插件自動生成行號并進行對齊方便調試代碼,無需進行任何設置。


    博文地址:http://www.tkk7.com/cnfree/archive/2012/10/30/390457.html
    posted @ 2012-10-30 13:48 三人行,必有我師焉 閱讀(92517) | 評論 (43)編輯 收藏

    The original author of the JadClipse project maintains it no more, and the latest build 3.3.0 doesn't support eclipse 4.x, so I download the source code and update it.

    JadClipse for Eclipse 4.x also support Eclipse 3.x, and provides several new features:
     
    1. Integrate jad.exe into the plugin, don't need to set jad path in the preference page again.
    2. Add two options in the JadClipse main preference page:
        (1) Use Eclipse member sorter
        (2) Show decompiler report
    3. Update the formatting preference default settings, the "Output fields before methods" setting's default value changes to true.

    JadClipse for Eclipse 4.x Update Site: http://feeling.sourceforge.net/update

    Offline Archive Update File Download: 
    1. http://feeling.sourceforge.net/downloads/org.sf.feeling.decompiler_1.0.3.zip
    2. http://www.tkk7.com/Files/cnfree/org.sf.feeling.decompiler_1.0.3.zip
    posted @ 2012-10-15 17:45 三人行,必有我師焉 閱讀(7453) | 評論 (10)編輯 收藏

    http://www.open-open.com/lib/view/1326265166952

    http://blog.chinaunix.net/uid-22342564-id-3183018.html
    posted @ 2012-05-31 02:42 三人行,必有我師焉 閱讀(476) | 評論 (0)編輯 收藏

    com\maxmpz\audioplayer\widget\listwrappers\D800DC00 這個package 主要用于 PlayList 模型的操作。

    com\maxmpz\audioplayer\widget\listwrappers\D800DC00\D803DC04.java

    里面有個
        private static int D801DC01(Activity activity, int i)
        {
            TypedArray typedarray 
    = activity.obtainStyledAttributes(null, com.maxmpz.audioplayer.j.true.p, 00);
            
    int j = typedarray.getResourceId(i, 0);
            typedarray.recycle();
            
    return j;
        }

    Context.obtainStyledAttributes 實現控件屬性與XML定義綁定的代碼。 

    TypedArray其實就是一個存放資源的Array,首先從上下文中獲取到R.styleable。。。這個屬性資源的資源數組。 attrs是構造函數傳進來,應該就是對應attrs.xml文件。 a.getString(R.styleable。。。);這句代碼就是獲取attrs.xml中定義的屬性,并將這個屬性的值傳給本控件的mValue.最后,返回一個綁定結束的信號給資源:a.recycle();綁定結束

    相關學習文章:
    http://blog.csdn.net/aomandeshangxiao/article/details/7449973

    com.maxmpz.audioplayer.widget.listwrappers.0xE9 這個類,用于顯示文件夾列表,右上方有2個自定義的RadioButton,用來設置是平鋪模式顯示還是層級顯示。
    定義了一個ID為:flat_hier_group 的RadioGroup,里面有個2個自定義的RadioButton。

    <RadioGroup android:gravity="right" android:orientation="horizontal" android:id="@id/flat_hier_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true"
      xmlns:android
    ="http://schemas.android.com/apk/res/android">
        
    <RadioButton android:id="@id/flat_folders_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="0.0dip" android:button="@drawable/matte_flat_folders_selector" />
        
    <RadioButton android:id="@id/hier_folders_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="-8.0dip" android:button="@drawable/matte_hier_folders_selector" />
    </RadioGroup>

    matte_flat_folders_selector的XML定義為:
     

    <selector
      
    xmlns:android="http://schemas.android.com/apk/res/android">
        
    <item android:state_checked="true" android:drawable="@drawable/matte_flat_folders_selected" />
        
    <item android:state_checked="false" android:drawable="@drawable/matte_flat_folders" />
    </selector>

    自定義的RadioButton實際上就是張背景透明的圖片罷了。


    播放器列表的Layout布局文件為 list_with_big_header.xml。

    里面有個android:ellipsize屬性:
    EidtText和textview中內容過長的話自動換行,使用android:ellipsize與android:singleine可以解決,使只有一行。EditText不支持marquee

    關于android:ellipsize屬性更詳細的文章:http://www.cnblogs.com/chiao/archive/2011/08/20/2147250.html


    里面還有個 android:textAppearance 屬性,這里涉及到了Android的theme和style設置了,更詳細的文章參見:http://jiayanjujyj.iteye.com/blog/1392541
    posted @ 2012-05-23 11:59 三人行,必有我師焉 閱讀(426) | 評論 (0)編輯 收藏

    獲取屏幕Display: Activity.getWindowManager().getDefaultDisplay();
    獲取擴展存儲目錄:Environment.getExternalStorageDirectory()
    通過文件獲取Uri:Uri.fromFile(File)
    根據文件路徑獲取圖片:BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions)
    獲取相機Intent:new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    獲取相機拍照后的圖片:
    Bundle extras = intent.getExtras();
    Bitmap bmp = (Bitmap) extras.get("data");
    觸摸事件:onTouchEvent(MotionEvent ev)
    媒體播放器:android.media.MediaPlayer
    媒體控制器:android.widget.MediaController(和播放器不在同一個package下)
    SurfaceView是視圖(View)的繼承類,這個視圖里內嵌了一個專門用于繪制的Surface,類似于Canvas,但感覺比Canvas更高級。
    android.provider.MediaStore里包含了相關的Image,Video,Audio信息,可通過managedQuery方法來查詢和遍歷。
    Android中的AdapterView使用Adapter來獲取數據,和JFace中的ContentProvider對應。
    根據字符串路徑獲取Uri:
    Uri.parse((String)Path)
    封裝好的視頻View:android.widget.VideoView
    視頻錄制:android.media.MediaRecorder
    相機高畫質:CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);


    設置透明度(這是窗體本身的透明度,非背景)

    WindowManager.LayoutParams lp=getWindow().getAttributes();
                    lp.alpha=0.3f;
                  getWindow().setAttributes(lp);
                    
    alpha在0.0f到1.0f之間。1.0完全不透明,0.0f完全透明


    設置黑暗度

                    WindowManager.LayoutParams lp=getWindow().getAttributes();
                    lp.dimAmount=0.5f;
                    getWindow().setAttributes(lp);
                    getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

    dimAmount在0.0f和1.0f之間,0.0f完全不暗,1.0f全暗


    設置背景模糊

    getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,     
               WindowManager.LayoutParams.FLAG_BLUR_BEHIND);



    //調用瀏覽器 
    Uri uri = Uri.parse(""); 
    Intent it = new Intent(Intent.ACTION_VIEW,uri); 
    startActivity(it); 

    //顯示某個坐標在地圖上 
    Uri uri = Uri.parse("geo:38.899533,-77.036476"); 
    Intent it = new Intent(Intent.Action_VIEW,uri); 
    startActivity(it); 

    //顯示路徑 
    Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=startLat%20startLng&daddr=endLat%20endLng&hl=en"); 
    Intent it = new Intent(Intent.ACTION_VIEW,URI); 
    startActivity(it); 

    //撥打電話 
    Uri uri = Uri.parse("tel:10086"); 
    Intent it = new Intent(Intent.ACTION_DIAL, uri); 
    startActivity(it); 

    Uri uri = Uri.parse("tel.10086"); 
    Intent it =new Intent(Intent.ACTION_CALL,uri); 
    //需要添加 <uses-permission id="android.permission.CALL_PHONE" /> 這個權限到androidmanifest.xml 

    //發送短信或彩信 
    Intent it = new Intent(Intent.ACTION_VIEW); 
    it.putExtra("sms_body", "The SMS text"); 
    it.setType("vnd.android-dir/mms-sms"); 
    startActivity(it); 

    //發送短信 
    Uri uri = Uri.parse("smsto:10086"); 
    Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
    it.putExtra("sms_body", "cwj"); 
    startActivity(it); 

    //發送彩信 
    Uri uri = Uri.parse("content://media/external/images/media/23"); 
    Intent it = new Intent(Intent.ACTION_SEND); 
    it.putExtra("sms_body", "some text"); 
    it.putExtra(Intent.EXTRA_STREAM, uri); 
    it.setType("image/png"); 
    startActivity(it); 

    //發送郵件 
    Uri uri = Uri.parse("mailto:android123@163.com"); 
    Intent it = new Intent(Intent.ACTION_SENDTO, uri); 
    startActivity(it); 

    Intent it = new Intent(Intent.ACTION_SEND); 
    it.putExtra(Intent.EXTRA_EMAIL, android123@163.com); 
    it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
    it.setType("text/plain"); 
    startActivity(Intent.createChooser(it, "Choose Email Client")); 

    Intent it=new Intent(Intent.ACTION_SEND); 
    String[] tos={"me@abc.com"}; 
    String[] ccs={"you@abc.com"}; 
    it.putExtra(Intent.EXTRA_EMAIL, tos); 
    it.putExtra(Intent.EXTRA_CC, ccs); 
    it.putExtra(Intent.EXTRA_TEXT, "The email body text"); 
    it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
    it.setType("message/rfc822"); 
    startActivity(Intent.createChooser(it, "Choose Email Client")); 

    //播放媒體文件 
    Intent it = new Intent(Intent.ACTION_VIEW); 
    Uri uri = Uri.parse("file:///sdcard/cwj.mp3"); 
    it.setDataAndType(uri, "audio/mp3"); 
    startActivity(it); 

    Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1"); 
    Intent it = new Intent(Intent.ACTION_VIEW, uri); 
    startActivity(it); 

    //卸載APK 
    Uri uri = Uri.fromParts("package", strPackageName, null); 
    Intent it = new Intent(Intent.ACTION_DELETE, uri); 
    startActivity(it); 

    //卸載apk 2 
    Uri uninstallUri = Uri.fromParts("package", "xxx", null); 
    returnIt = new Intent(Intent.ACTION_DELETE, uninstallUri); 

    //安裝APK 
    Uri installUri = Uri.fromParts("package", "xxx", null); 
    returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri); 

    //播放音樂 
    Uri playUri = Uri.parse("file:///sdcard/download/sth.mp3"); 
    returnIt = new Intent(Intent.ACTION_VIEW, playUri); 

    //發送附近 
    Intent it = new Intent(Intent.ACTION_SEND); 
    it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text"); 
    it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/cwj.mp3"); 
    sendIntent.setType("audio/mp3"); 
    startActivity(Intent.createChooser(it, "Choose Email Client")); 

    //market上某個應用信,pkg_name就是應用的packageName 
    Uri uri = Uri.parse("market://search?q=pname:pkg_name"); 
    Intent it = new Intent(Intent.ACTION_VIEW, uri); 
    startActivity(it); 

    //market上某個應用信息,app_id可以通過www網站看下 
    Uri uri = Uri.parse("market://details?id=app_id"); 
    Intent it = new Intent(Intent.ACTION_VIEW, uri); 
    startActivity(it); 

    //調用搜索 
    Intent intent = new Intent(); 
    intent.setAction(Intent.ACTION_WEB_SEARCH); 
    intent.putExtra(SearchManager.QUERY,"android123") 
    startActivity(intent); 

    //調用分享菜單 
    Intent intent=new Intent(Intent.ACTION_SEND); 
    intent.setType("text/plain"); //分享的數據類型 
    intent.putExtra(Intent.EXTRA_SUBJECT, "subject"); //主題 
    intent.putExtra(Intent.EXTRA_TEXT, "content"); //內容 
    startActivity(Intent.createChooser(intent, "title")); //目標應用選擇對話框的標題


    獲取Location:
    Criteria criteria = new Criteria();
    criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    criteria.setPowerRequirement(Criteria.POWER_LOW);
    LocationManager locManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    if(locManager.getBestProvider(criteria, true) != null)
    myLocation = locManager.getLastKnownLocation(locManager.getBestProvider(criteria, true));
    else {
    myLocation = new Location("gps");
    myLocation.setLatitude(47.100301);
    myLocation.setLongitude(-119.982465);
    }
    posted @ 2012-05-05 19:41 三人行,必有我師焉 閱讀(850) | 評論 (0)編輯 收藏


    3.1以下版本升級到最新版最好先還原到初始檔,然后重新備份一下初始檔。

    如果不希望重新開局,以下提供正確的操作步驟:
    1、進入備份與還原界面。
    2、選擇“備份當前游戲數據“進行備份。
    3、選擇“ 還原游戲至初始檔狀態“進行還原。
    4、選擇“設置當前游戲數據作為游戲初始檔”進行備份。
    5、在還原備份數據的列表中選擇步驟2備份的數據存檔進行還原

    就可以正常進入游戲,并且更新了原始檔。


    3.9版更新內容:
    1、修正了若干已知Bug。
    2、象兵及戰車數據使用兵種第二防御數據。
    3、全面更新地圖坐標算法,防止無法進入游戲或者武將位于山地無法移動。
    4、增加了切換游戲勢力功能,可以無需開檔游玩任意勢力。
    5、增加了東州兵和駱駝兵模的防跳補丁。


    3.8版更新內容:
    1、增加了解鎖朝廷、在野、亂軍勢力的功能。
    2、增加了解除諸葛亮外出云游狀態的腳本補丁,玩家可以使用任何勢力收買諸葛亮,并且激活三顧茅廬技能。
    3、增加了全勢力官爵升級的腳本補丁。
    4、增加了部分武將特殊技能全勢力激活的腳本補丁。
    5、增加了創建新兵種功能。


    3.7版更新內容:
    1、修正了一些細節上的bug。
    2、增加了霧隱版呂玲綺衛隊女兵模型的導入。
    3、增加了武將模型作為騎兵模型的導入,并且可自由移除已導入的模型。
    4、步兵的士兵模型可以選擇將軍模型,騎兵的士兵模型可以選擇已導入的將軍模型和霧影女兵模型。

    3.6版更新內容:
    1、修正了導入弩兵陷陣營戰斗跳出的bug。
    2、修正了收買武將修改器發生異常的bug。
    3、修正了更換異族武將勢力游戲跳出的bug。
    4、修改了一些2種勢力都有的武將相關的bug。
    5、新建武將后清空武將編輯頁面狀態。
    6、編輯武將能力頁面新增了編輯武將衛隊經驗選項。
    7、基本修改頁面增加了所有兵種生產回合、費用下調的修改。
    8、基本修改頁面增加了所有城市建筑生產回合、費用下調的修改。

    3.5版更新內容:
    1、修正了兵種修改頁面中兵種名稱顯示錯亂的bug,現在很容易分清雇傭兵和城市招募了。
    2、增加了亂軍刷新概率的修改。
    3、增加導入弩騎高順衛隊和弩兵陷陣營的功能。

    3.4版更新內容:
    1、修正了編輯大眾衛隊武將名字時會改變大眾衛隊名稱的bug。
    2、增加了編輯勢力地圖顏色的功能。
    3、增加了降低敵方所有武將忠誠度的功能。
    4、解決游戲中部分武將心灰意冷狀態下無法被收買的bug。

    3.3版更新內容:
    1、修正了一些bug,比如編輯武將坐標會發生變化的bug。
    2、創建新武將頁面的爵位增加了自定義功能。
    3、難度修改頁面中,增加了禁用電腦驛站加成,禁止電腦生產刺客,以及能夠編輯電腦太守加成幾率的新功能。

    3.2版更新內容:
    1、增加了1.9a中特有的馬匹,1.9a特有的馬匹一般沖量都比較大,老版馬匹沖量較小。
    2、修正了武將地圖坐標自動計算錯誤的bug。我把RGB顏色值寫錯了,另外遺漏了森林顏色。
    3、修正了編輯新武將坐標和兵模無效生效的bug。
    4、增加了孫劉曹中特殊武將不能被交換到其他勢力的注釋。

    3.1版更新內容:
    1、修正了未對掌旗官旗幟,城市旗幟,援軍,盟軍旗幟做修改的bug。
    2、修正了編輯武將人物列傳未繁體化,換行的bug。
    3、增加了修改勢力后代武將姓氏的功能。

    3.0.1版更新內容:
    1、更新了壓縮武將圖片的算法,讓武將圖片顯示的更加清晰。
    2、修正了解壓縮更新包,僅支持GBK編碼的bug。

    3.0版更新內容:
    1、新增編輯勢力功能。
    2、修正編輯武將坐標可能導致游戲異常的bug。
    3、修正禁止電腦驛站暴兵的bug(此處bug是由于1.9和1.7的驛站代碼不一樣導致的)。
    4、增加了添加勢力兵種對兵營的要求,提高游戲的可玩性。
    5、增加了對城墻生命值的修改。
    6、增加了武將身份設置功能,方便玩家自定義君主或者繼承人。
    7、增加了修改器的自動更新功能,3.0及其后續版本若發現修改器有新版本,將會自動更新到最新版本。

    注意事項:
    因為3.0版改動較大,若使用編輯勢力功能,請首先還原游戲數據到初始狀態,重新做一次原始備份檔,否則編輯勢力后,無法還原到游戲原始狀態。


    說明:
    1、修改器安裝文件夾路徑最好不要包含中文或者空格(有個別用戶因為中文和空格路徑問題無法啟動修改器,調試器會提示:
    Error occurred during initialization of VM
    java.lang.UnsatisfiedLinkError: no zip in java.library.path


    2、正常情況下,請使用“三國全面戰爭1.9a修改器”運行修改器。

    3、非正常情況下,比如修改器無法啟動成功,或者一直處于系統初始化狀態,或者彈出錯誤窗口(不包括修改失敗),請使用“三國全面戰爭1.9a修改器(調試器)”運行修改器。調試器啟動時會顯示一個黑色的dos窗口,如運行時發生錯誤,錯誤信息會打印到黑色dos窗口,請截圖或者復制錯誤信息,發送到:http://www.1mod.org/thread-37918-1-1.html,我看見后會及時修正錯誤。

    4、游戲原始備份檔下載地址:http://feeling.sourceforge.net/patch/1.9a/default.zip
    如果你需要恢復原始數據,而又未作原始檔備份,可以從此地址下載。
    恢復原始數據的2種方法:
    1、解壓縮后,復制data目錄下的數據文件到游戲中,替換游戲數據文件。
    2、復制壓縮文件到游戲目錄下的/patch/bak目錄下,替換掉你自己的原始備份檔,然后通過修改器恢復原始備份檔。

    5、關于殺毒軟件誤報問題:
    (1)如果是國產殺毒軟件報病毒,請你不要抱怨修改器,去抱怨那些垃圾殺毒軟件吧,技術不過關,老是誤報。
    (2)如果是國外知名殺毒軟件報病毒,比如卡巴斯基,麥咖啡,微軟MSE等等,你可以截圖發給我。
    (3)推薦使用微軟MSE,口碑不錯,完全免費。


    6、修改需理智,請謹慎修改,方能提高游戲的可玩性。










    下載地址:http://feeling.sourceforge.net/patch/1.9a/patch_1.9a_3.9.zip

    修改器簡易教程:http://tieba.baidu.com/p/1418490788


    小技巧:
    1.如果希望新建武將成為勢力君主,可以在創建后和武將勢力君主交換。
    2.能夠更換所屬勢力的武將不能有后代,也不能是勢力君主或者繼承人,如果希望更換這些武將的勢力,可以先和勢力內的沒有后代的垃圾武將交換一下,讓他們成為自由身,就可以更換武將所屬勢力了。
    posted @ 2012-01-25 22:57 三人行,必有我師焉 閱讀(119598) | 評論 (85)編輯 收藏

    關于PaletteData的生成:
    case Gdip.PixelFormat16bppARGB1555:                                        
    case Gdip.PixelFormat16bppRGB555: 
        paletteData = new PaletteData(0x7C00, 0x3E0, 0x1F); 
    break;
    case Gdip.PixelFormat16bppRGB565: 
        paletteData = new PaletteData(0xF800, 0x7E0, 0x1F); 
    break;
    case Gdip.PixelFormat24bppRGB: 
        paletteData = new PaletteData(0xFF, 0xFF00, 0xFF0000); 
    break;
    case Gdip.PixelFormat32bppRGB:
    case Gdip.PixelFormat32bppARGB: 
        paletteData = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 
    break;

    32位ImageData中的data是以RGBA的順序存儲的。data[0]:red,data[1]:green,data[2]:blue,data[3]:alpha

    從byte[]中讀取RGB pixel:
    public static int getPixelFromRGBA( int depth, byte[] data )
    {
            switch ( depth )
            {
                case 32 :
                    return ( ( data[0] & 0xFF ) << 24 )
                            + ( ( data[1] & 0xFF ) << 16 )
                            + ( ( data[2] & 0xFF ) << 8 )
                            + ( data[3] & 0xFF );
                case 24 :
                    return ( ( data[0] & 0xFF ) << 16 )
                            + ( ( data[1] & 0xFF ) << 8 )
                            + ( data[2] & 0xFF );
                case 16 :
                    return ( ( data[1] & 0xFF ) << 8 ) + ( data[0] & 0xFF );
                case 8 :
                    return data[0] & 0xFF;
            }
            SWT.error( SWT.ERROR_UNSUPPORTED_DEPTH );
            return 0;
    }

    從pixel中取出RGB值:
    RGB rgb = imagedata.palette.getRGB( pixel );

    生成一個空的32位圖片:
    ImageData dest = new ImageData( width,
                    height,
                    32,
                    new PaletteData( 0xFF00, 0xFF0000, 0xFF000000 ) );

    24位透明圖片轉成32位透明圖片:
        public static ImageData convertToRGBA( ImageData src )
        {
            ImageData dest = new ImageData( src.width,
                    src.height,
                    32,
                    new PaletteData( 0xFF00, 0xFF0000, 0xFF000000 ) );

            for ( int x = 0; x < src.width; x++ )
            {
                for ( int y = 0; y < src.height; y++ )
                {
                    int pixel = src.getPixel( x, y );
                    RGB rgb = src.palette.getRGB( pixel );

                    byte[] rgba = new byte[4];

                    rgba[0] = (byte) rgb.red;
                    rgba[1] = (byte) rgb.green;
                    rgba[2] = (byte) rgb.blue;

                    if ( pixel == src.transparentPixel )
                    {
                        rgba[3] = (byte) ( 0 );
                    }
                    else
                    {
                        rgba[3] = (byte) ( 255 );
                    }
                    dest.setPixel( x, y, getPixelFromRGBA( 32, rgba ) );
                }
            }
            return dest;
        }

    posted @ 2012-01-15 13:49 三人行,必有我師焉 閱讀(3566) | 評論 (1)編輯 收藏

    SourceForge最近實在太慢了,忍無可忍,每天浪費我大量時間……終于讓我不得不投向GitHub的懷抱……
    posted @ 2012-01-14 16:33 三人行,必有我師焉 閱讀(2274) | 評論 (0)編輯 收藏

    JDK1.6的File.createTempFile方法有bug,在我的機器上第一次調用該方法需要耗時5秒時間,換了好幾個1.6的版本均有該問題。JDK1.4,1.5則無此問題。

    不一定所有的機器都有此問題,不過這兒肯定是有問題的,起碼在我的機器上有問題。
    posted @ 2012-01-13 15:51 三人行,必有我師焉 閱讀(1633) | 評論 (2)編輯 收藏

    Java應用定制工廠(以下簡稱為JCB,Java Customization Builder)是一個針對Java輕量級桌面應用進行精簡優化的小工具,使用它可以精簡你的jar包,并自動生成一個精簡的JRE,也可以使用它生成一個Exe啟動引導程序,并且能夠對你的Java應用自動做Pack200和Unpack200處理。使用本工具定制的Java桌面應用通常不會超過5M(包含JRE),SWT客戶端程序相對于Swing客戶端程序更小,一般不會超過3M。

    JCB1.0.3主要功能是可以支持
    添加Exe的版本信息,并且能夠更細節的定義Exe的啟動行為,比如是否顯示一個splash窗口,是否優先使用精簡版的jre,以及增加了對unpack操作的優化,讓應用程序第一次運行啟動的更快。同時也增加了對系統權限的支持,不再要求需要管理員權限才能運行軟件,Guest用戶一樣的使用。

    下一個版本考慮增加一個Au3的編輯器,具有語法高亮和智能輔助功能,可以讓高級用戶定制自己的Exe行為。

    軟件主頁:http://jcb.sourceforge.net
    JCB1.0.3下載地址:http://sourceforge.net/projects/jcb/files/JCB_1.0.3.zip/download


    posted @ 2011-12-26 22:13 三人行,必有我師焉 閱讀(1607) | 評論 (3)編輯 收藏

    在一個線程中啟動了一個線程鉤子,然后死活拿不到主線程中的消息,全局鉤子就沒問題。折騰了一下午才發現這個線程鉤子是在子線程中啟動的,GetCurrentThreadId 方法拿到的不是主線程的threadId,自然也就獲取不到主線程的系統消息。Google了好多文章,都沒有提到這一點,真TMD郁悶,完全浪費我時間,還以為是我的類庫寫錯了,鬧了半天是調用的參數傳的不對。
    posted @ 2011-12-24 18:58 三人行,必有我師焉 閱讀(1789) | 評論 (1)編輯 收藏

    同樣的API, IShellFolder遍歷控制面板里面節點的children,所有的.net代碼都能獲取,所有的非.net代碼都無法獲取???

    本來還以為是代碼的問題,debug一天死活沒找到問題,最后在codeproject上找了十幾個例子,發現都一樣的結果,why? 

    難道僅僅對.net的才開放遍歷的權限?
    posted @ 2011-12-14 12:35 三人行,必有我師焉 閱讀(1734) | 評論 (1)編輯 收藏

    1、安裝VS2008
    2、安裝 Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1
    3、修改SDK的SetEnv.cmd的第146行 
    Set "VCTools=%VCRoot%\VC" 為 Set "VCTools=%VCRoot%\VC\Bin"
    4、修改build.bat的環境配置
    call "C:\Program Files\Microsoft SDKs\Windows\v6.1\Bin\SetEnv" /xp /x86 /Release (不是%PROGRAMFILES%目錄,編譯字幕為綠色,PROGRAMFILES%目錄編譯出來的dll有400多k。)
    call "%PROGRAMFILES%\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
    posted @ 2011-12-13 13:16 三人行,必有我師焉 閱讀(378) | 評論 (0)編輯 收藏

         摘要: Java應用定制工廠(以下簡稱為JCB,Java Customization Builder)是一個針對Java輕量級桌面應用進行精簡優化的小工具,使用它可以精簡你的jar包,并自動生成一個精簡的JRE,也可以使用它生成一個Exe啟動引導程序,并且能夠對你的Java應用自動做Pack200和Unpack200處理。使用本工具定制的Java桌面應用通常不會超過10M(包含JRE),SWT客戶端程序相對于Swing客戶端程序更小,一般不會超過5M。  閱讀全文
    posted @ 2011-12-12 16:27 三人行,必有我師焉 閱讀(6237) | 評論 (12)編輯 收藏

    GreenJVMMake 是一個精簡JRE的小工具,詳細信息請參見項目:

    http://code.google.com/p/greenvm/

    javaonepackage 是一個集成了GreenJVMMake的IDE,可以方便的生成自定義的JRE,詳細信息請參見項目:

    http://code.google.com/p/javaonepackage/

    比較遺憾的是javaonepackage的作者遺失了代碼,導致項目無法進一步的更新,影響了使用。

    用以上工具生成的精簡JRE通常不超過2M,可是用exe4j將Java應用轉換成exe的時候,卻會拋出Couldn't load main class,原因是因為exe4j使用自己的jar來加載用戶的Jar包,這其中用到了一些反射機制,精簡JRE里面當然是不含有多余的class文件的,所以加載必然失敗。我們需要做的就是把這些相關的class添加到精簡JRE中,這些class包含在 java\lang, java\util, sun\reflect 這三個包中。將這些class添加到精簡jre中,大小也僅僅增加數百K而已,在我們可以的接受范圍之內。

    PS:由于GreenJVMMake的機制是檢查運行時加載的class文件,所以它很可能遺失Jar運行所需要的exception class,這會導致運行時JVM的崩潰,用戶需手動加載所有可能會產生的exception class,包含runtime的和非runtime的。
    posted @ 2010-09-02 10:53 三人行,必有我師焉 閱讀(4028) | 評論 (1)編輯 收藏

    現在網絡上越來越流行.net和java寫的客戶端的小應用程序,而且后綴是exe。本文討論的是如何從exe4j封裝的exe文件中將自己想要的jar抽取出來。

    exe4j一直是一種比較通用的java exe封裝工具,但是其并沒有將jar轉換為本地文件,而是將jar文件通過特殊處理后,封裝成的一個exe文件。因此只要我們了解了exe4j的原理,就可以將jar文件從exe文件中提取出來,并通過反編譯工具來查看程序代碼。

    1. 分析Exe4J,得知其在添加文件到.exe時,使用0x88將文件內容Xor,所以第一步,我們需要將原始的數據提取出來:
    import java.io.*;
    import java.util.*;

    public class gen {
        
    public static void main(String args[]) throws IOException {
            FileInputStream fin 
    = new FileInputStream(args[0]); // 可以將整個exe文件解碼
            FileOutputStream fout = new FileOutputStream(args[1]);
            BufferedInputStream bin 
    = new BufferedInputStream(fin);
            BufferedOutputStream bout 
    = new BufferedOutputStream(fout);
            
    int in = 0;
            
    do {
                in 
    = bin.read();
                
    if (in == -1)
                    
    break;
                in 
    ^= 0x88;
                bout.write(in);
            } 
    while (true);
            bin.close();
            fin.close();
            bout.close();
            fout.close();
        }
    }

    2.分析提取出來的數據文件,使用WinHex查看其16進制代碼。由于Jar文件的開頭總是PK開頭,并且總包含有manifest.mf文件,并且結尾總是有3個00,同時結尾段有整個Jar包文件的索引,我們可以根據這一特性來分析我們需要的片段。

    1、搜索Jar的manifest,然后往前找,找到的第一個PK段,即為一個Jar的開頭。
    2、查看片段里Jar里的每個class信息,直到最后的文件索引片段。
    3、一個Jar的結束片段位于索引片段之后,仍然包含著PK段,并且最后包含著3個00,且這3個00距離PK大概20個字節左右

    根據以上3條準則,足以提取整個Jar數據段,然后導入新文件中,并且以zip字段命名,嘗試用ZIP解壓縮軟件打開,看看是否抽取正確。

    需要注意的是WinHex非注冊版,只能保存280K大小的文件,更大的Jar文件,需要注冊版的WinHex才行。
    posted @ 2010-08-22 01:03 三人行,必有我師焉 閱讀(6813) | 評論 (4)編輯 收藏

    1、調用截圖工具:

    http://iecapt.sourceforge.net/

    2、使用Java類庫,通過Render生成Java2D圖像:

    http://www.ldotc.com/Web+Page+Thumbnails+in+Java.html

    方法1的優點在于,圖像不會失真,速度快,但是缺點是依賴于服務器端的UI,無UI的話,則無法使用。
    方法2的優點是不依賴于服務器端的UI,但是圖像容易失真,且速度相對較慢……
    posted @ 2010-08-17 12:50 三人行,必有我師焉 閱讀(1442) | 評論 (0)編輯 收藏

         摘要: TGA or TARGA format is a format for describing bitmap images, it is capable of representing bitmaps ranging from black and white, indexed colour, and RGB colour, the format also supports various compr...  閱讀全文
    posted @ 2010-03-29 13:02 三人行,必有我師焉 閱讀(1994) | 評論 (0)編輯 收藏

    Eclipse 是一個集成開發環境,同時又是一個產品平臺。這樣有時候我們就會碰到一個問題,在開發Debug項目的時候沒有問題,打包發布的時候就有問題了,這可如何是好?由于Debug時候和發布后plugin的ClassLoader機制不盡相同,出現這個問題的幾率還有會有的。

    Java 在這一點上為我們提供了方法,那就是遠程Debug。遠程Debug一般用于Web開發,或者客戶端無法負載大規模的應用時才會運用到,所以Desktop developer 很少會涉及到這個概念。不過Eclipse 的產品平臺卻讓我再次體會到了Java的強大。

    關于Eclipse Remote Debug的文章,大家可以從此處學習:

    http://www.ibm.com/developerworks/cn/opensource/os-eclipse-javadebug/index.html

    Remote Debug 需要2方面的設置,一個是產品平臺JVM啟動參數的設置,需要讓平臺以遠程Debug的模式啟動。然后是在開發端監聽產品平臺的運行狀態。當產品平臺運行到斷點代碼時,Eclipse開發端就會進入Debug界面,像普通debug一樣正常debug了。

    posted @ 2009-09-10 16:59 三人行,必有我師焉 閱讀(2410) | 評論 (1)編輯 收藏

    網上關于Eclipse Fragment的資料比較少,引用Eclipse Wiki的一段話:

    An Eclipse Fragment is a way of putting your own classes into the "class loader" of another package (basically, it's as though your class was actually in the other package). If you combine this ability of a Fragment with the notion of a plugin's classpath ordering, then you can force your class to load before a like-named class in the original package.

    簡而言之,Fragment可以利用Eclipse平臺的ClassLoader機制替換原有Plugin的某些文件,以便實現自己的功能。如果僅僅是因為Plugin擴展,而需要替換自己項目的某些Plugin,可以參考文章:

    http://wiki.eclipse.org/Steps_to_use_Fragments_to_patch_a_plug-in  (來之不易,感興趣的可以收藏下)

    讀完這篇文章,你大概就應該能夠了解到Fragment的實現分為兩部分:Host 和 Patch。這兩部分對應的plugin的manifest.mf文件都需要做特殊處理,對于Patch的build方式也要特殊處理,那就是build出來的plugin jar里放置的不是松散的class文件,而是一個特殊的jar文件,這個 jar 文件定義在Host plugin的manifest.mf 的classpath里面。

    通常情況下,按照這篇文章的做法是沒有問題的。但是在開發階段,有一種情況可能無法實現class的替換。

    我公司的項目是使用perforce進行項目版本控制的,但是perforce比較傻,有些重要的功能沒有實現,而又很關鍵,因此我想自己針對perforce的eclipse plugin做一個fragment,添加自己想要的功能。但是這個plugin沒有source code,而我自己的hack也是反編譯class文件進行的。所以在我的work space里,并沒有Host plugin的 project。結果按照這篇文章的做法,始終不能在workbench debug的狀態下,正確load我hack過的class。因為在代碼模式下面是可以正確load的,而現在沒有代碼,在數次檢驗無果之后,只能針對ClassLoader去思考了。Host文件里要求一個jar文件,我就用PDE 將 fragment export出來,把Fragment plugin jar 包里包含的那個 jar 文件解壓出來,放到 patch project 里,然后重新Debug, OK,這次果然沒問題了。一個小小的Class Loader問題,真的能夠要人命呀……這應當算是Eclipse的一個bug吧,除非是對一個Plugin進行hack,否則一般也不會碰到這種情況。普通的項目開發,肯定會包含Host Plugin的Project。

    我的經歷權且當做飯后談資,不足為慮。我這兒想說的是Fragment機制非常好用,也易于Plugin擴展。比如你的項目分為Open Source 和 Commercial 2種的話, Commercial 部分也可以通過Fragment來實現,不一定需要走Extension Point路線。由于網上相關文章不多,還需要自己多多研究,了解其機制。

    posted @ 2009-09-10 16:42 三人行,必有我師焉 閱讀(1742) | 評論 (0)編輯 收藏

    自定義控件通常是從一個Composite或者Canvas繼承而來,但是缺省狀態下,這兩個控件都無法通過鍵盤的Tab鍵得到焦點。通過對SWT的debug,我發現要實現該事件,必須滿足一個必要條件:為自定義控件安裝一個KeyEvent的監聽器

    實際上我個人認為這出自于SWT的實現者自己的考慮,可能認為如果沒有KeyListener,也就意味著沒有Key的操作,那么也無需通知Travserse事件,Travserse事件的前提就是Key操作。但是在某些特定情況下我們不需要KeyListener,也可以模擬出KeyEvent的效果,比如通過TraverseListener的keyTraversed方法。總而言之,想通過鍵盤為某一個自定義控件獲取焦點,就老老實實的給控件加一個KeyListener吧。

    此處附加一些和Traverse相關的小知識:

    1、如何通過鍵盤的Tab鍵跳出 Multiple Style 的Text?
            請使用 Ctrl+Tab 組合鍵。

    2、如何通過鍵盤操作讓上一個控件獲取焦點?
            請使用 Shift+Tab 或者 Ctrl+Shift+Tab 組合鍵。

    3、Button 可以通過回車鍵和空格鍵激活。所以如果有些地方無法使用回車鍵(比如按鈕在Dialog中),可以考慮使用空格鍵。

    4、一些特殊的KeyCode:
            回車鍵:SWT.KEYPAD_CR
            小鍵盤的回車鍵:SWT.TRAVERSE_RETURN
            方向鍵:SWT.ARROW_UP,SWT.ARROW_DOWN,SWT.ARROW_LEFT,SWT.ARROW_RIGHT
    posted @ 2009-04-07 11:22 三人行,必有我師焉 閱讀(2246) | 評論 (2)編輯 收藏

    項目地址:http://findbugs.sourceforge.net/

    用于分析項目代碼,自動發現項目潛在Bug,萬中無一的好東西,絕對值得下載一試,有興趣的自己研究。
    TeamLeader和PM 強烈推薦,用于Code Review。
    posted @ 2009-02-16 00:02 三人行,必有我師焉 閱讀(2875) | 評論 (5)編輯 收藏

    做不下去了,Vista快把我逼瘋了,啥都不支持,隨意取消n多API,開發人員能做的事情太有限了,Vista你到底想干什么?

    看一看MSDN,全是抱怨Vista的。管理員給出的答案就是按照兼容XP的方式運行,這算哪門子解決方案呀。

    Have you tried running your application elevated? (Right Click->Run As Administrator) If this doesn't work try applying an XP SP2 Compatibility shim from the Compatibility Tab in the properties dialog. (Right Click->Properties | Compatibility).

    Let me know if this works.

    Thanks!


    怒呀!!!!!!!

    從Win3.1 到 Vista,沒有哪個版本比Vista更失敗的,無論是從用戶角度,還是從開發角度。微軟是不是想倒閉不做了?
    posted @ 2008-12-05 18:16 三人行,必有我師焉 閱讀(2302) | 評論 (5)編輯 收藏

    沉寂了一段時間,現在繼續SWT Win32 Extension的開發,說實話,最近的進展挺失敗的。Black Glossy效果我發現在某些機器上的顯示效果非常的卡,我自己的機器卻沒有任何問題。另外就是我最近在XP下實現了Window Mixer API,用來管理系統聲音。Win98,2000,XP都沒有問題,結果Vista讓我郁悶了,Vista居然取消了Mixer,我哭呀。以下是微軟員工給出的答案:

    That's because the mixer APIs are virtualized on Windows Vista - you don't get to see the real audio hardware by default, only a virtualized version.  We did this because the vast majority of applications that used the mixer APIs were using them to control their own volume, which is quite rude (it says "I own the box, no other sounds on the system matter").

     You have two choices.  The first is to run your application in XP compatibility mode, in which case you'll be able to access the real audio hardware (please note: you'll see exactly what the hardware provides, which may lead to surprising results).

     The other choice is to use the new Vista audio engine APIs.  either the IAudioEndpointVolume API which allows you access to the master volume for each of the audio endpoints on the machine.  If you really need to access the actual audio controls the IDeviceTopology interface will allow you direct access to the various controls on the audio hardware.

    沒脾氣了,只能專門為Vista實現一套簡單的API了。
    posted @ 2008-10-23 18:25 三人行,必有我師焉 閱讀(2387) | 評論 (5)編輯 收藏

    最近做了一個可視化編輯器相關的項目,采用了GMF。現在項目即將進入尾聲,以后可能不再接觸這個東西,so在還沒有忘掉之前,將經驗記錄下來以供大家參考。 當然做這個項目之前,我對GMF,EMF一無所知,只是對GEF有所了解,所以可能會有些囫圇吞棗的感覺,但是相信我的理解還是會對各位有所幫助。

    GMF其實是一個整合了GEF,EMF的自動化生成代碼的項目。使用GMF,可以快速的生成一個包含可視化編輯器的項目,這一點網上有文章介紹:15分鐘學會GMF。15分鐘是夸張了一點,不過15天完成一個可視化項目,對一個熟練的GMF程序員來說,卻絕對不是什么難事。但是既然使用了GMF框架,你就不得不面對以下幾個問題:

    一、既然是框架,自然要遵守框架的規則,GMF是模式驅動設計的,也就是說必須建好模型,才能進行下一步的開發工作。但是國內很多項目,需求總是不斷更新,這種情況下,不要輕易使用GMF。
    二、使用GMF框架,自然不具備GEF的靈活性,很多地方都被限制住了,不適合做靈活性非常大的圖形設計。
    三、不得不忍受GMF里大量的bug。

    我比較過GMF1.0,2.0,2.1三個版本,其中1.0完全不能容忍,2.0比較傻,2.1還過得去,所以GMF還是值得大家期待的,畢竟是越做越好。


    一個比較簡單的GMF流程編輯器

    個人感覺GMF非常適合做流程編輯器,主要是圖形要求簡單,并且適合GMF自動布局,兼之對模型要求不高。

    在學習GMF之前,有必要研究一下GEF和EMF,其中GEF是必須要有所了解的,而對EMF要求不算太高,能建一個ecore模型,了解emf的commandstack就夠了(其實我本人不太喜歡EMF,我更喜歡用自己的模型框架)。

    GMF的學習周期大概2周左右,上手到熟練大概需要1個月的時間(我自己的學習周期),當然這期間會碰到各種各樣的技術問題,針對不同的case,碰到的問題也會不一樣,而我這個系列的文章,主要就是把我所遇到的問題陳列出來,并提供一個解決之道。

    附GMF相關資料:
    八進制:GMF常見問題
    GMF Newsgroup Q and A
    posted @ 2008-09-04 14:52 三人行,必有我師焉 閱讀(2547) | 評論 (4)編輯 收藏

    在Birt Designer中,Binding 是無處不在的,如何正確的是用Birt的Binding呢?首先我們需要知道Birt的Binding Type。

    Birt的Binding type隨著Birt的版本的升級而越來越豐富,早期的Birt版本只有2種類型:為自己創建一個Data Column Binding,和使用Container的Data Binding,隨著CrossTab的出現,進而出現了Cube,ReportItem Reference Binding的概念。

    普通的Binding,一般是通過屬性編輯器的BindingPage來創建,可以set一個Data set,然后自動創建一個Binding列表。Crosstab和Chart兩種類型的Report Item 可以不依賴于Data set,而采用Cube來作為Bingding源。而ReportItem Reference 的概念更是簡便了Binding的生成,我們可以讓一個ReportItem 直接引用另外一個ReportItem的Binding,而非僅僅是Container的Binding,當然既然是引用,那么你是無法編輯這些Binding的,而且被引用的ReportItem必須包含一個名字,有些ReportItem比如Table本身是可以不設名字的,但在這個地方你就要加上了。

    再來說說Binding的設置,我們可以通過Binding Dialog和Binding Page來設置,這兩種設置是不同的,如果在Binding Dialog上添加一個Binding,那么這個Binding是添加到這個Report Item的BindingHolder身上,如果在 Binding Page上設置,則Bindnig會添加到自身,讓自己成為BindingHolder。
    posted @ 2008-07-04 11:47 三人行,必有我師焉 閱讀(2614) | 評論 (1)編輯 收藏

    通過打開Birt透視圖,然后Reset至缺省的Layout,我們能夠看到基本的一些View和一個主要的報表可視化編輯器。

    先來說一下View,Birt主要的View包含7塊:

    左上角包含3個視圖,Palette,Data Explorer和Resource Explorer,Palette里放置了報表常用的可視化組件,直接將這些組件拖到報表設計器的時候,這些組件并沒有作特殊的初始化處理,而從Data Explorer里向設計器拖入一個Dataset會自動生成一個Table,拖入一個Cube會生成一個Crosstab,拖入一個Dataset Column會生成一個DataItem。Data Explorer主要是用來管理和顯示數據源。Resource Explorer 老版本里是Library Explorer,新版本則變更為了Resource Explorer,用來特別顯示Library,CSS文件,其他文件則不進行特殊處理。

    左下角有2個視圖,包含Navigator視圖和Online視圖,Navigator視圖是用來建立Birt項目用的,如果是Birt Rcp版本,我們則看不到這個視圖,這是IDE版本專有的一個視圖,在Rcp版本里沒有Project這個概念,直接以文件的形式進行管理。Outline是Birt里較為重要的視圖,所有的報表部件都會在這個View里顯示并會隨著報表的變化實時刷新。

    右下角包含了Property Editor 和 Problems兩個視圖, Property Editor 用來編輯每個可視化報表元素的屬性,一般比較常用的屬性都會在前幾個Tab頁里,但是有些屬性前幾個Tab頁里都沒有,這時候需要選擇Advanced這個Tab頁,它里面包含了這個元素所有可用的屬性,如果連這兒也沒有,那么說明該元素不存在你想要的屬性。Problems視圖則用來顯示報表收集到的一些問題,如果報表校驗的時候發生錯誤,會在此處顯示出來。

    以上的那些視圖屬于缺省視圖,但還有幾個視圖也比較有用,一個是Error log視圖,一個是Example視圖。Error log視圖主要是開發用的,當你使用Birt進行二次開發的時候,難免會碰到一些bug,當你感覺有問題的時候,不妨打開error log視圖,只要Birt捕捉到了異常,一般都會顯示在這個視圖里。而Example視圖里提供了各種各樣的視圖,可以Open 和 Save, Open的時候會自動幫你在workspace里建立一個項目,以便你瀏覽該項目文件。Save則是把這個Example保存到本地某個目錄。

    說完視圖,再來看看Birt可視化的報表設計器,這個設計器包含了五個部分:Layout,Master Page,Script,XML Source,Preview。

    Layout為設計器的主要部分,只要通過可視化的拖拽,一個報表就會被自動生成出來,當然要想靈活運用報表設計器,就必須對各個組件的屬性了如指掌,Birt提供了豐富靈活的屬性供用戶選擇。MasterPage主要用來設置頁眉頁腳,以及打印顯示之類的功能。Script頁面,當你在Layout頁面里選中一個元素之后,切換到Script頁面,就可以對這個元素進行腳本編碼,主要用來監聽各種事件,使用Javascript,在采用Web顯示里,這些腳本會生效。XML Source則是將這張報表背后的XML source顯示出來,用戶如果覺得自己對Birt很熟,可以直接在這兒手工修改代碼。Preview則是預覽Birt報表,Birt會啟動Tomcat顯示Web運行效果。

    基本上Birt還是比較強大的,基本的功能一應俱全。可能你會發現缺少一些更高級花哨的功能,比如flash之類的,其實怎么說呢,不是Birt沒有,而是開源版的沒有,這個功能在Birt商業版里,可以在 http://www.actuatechina.com/download.php 下載專業版試用。如同IBM,這是這類公司特有的策略,免費上面做收費。喜歡的話,可以試一下專業版,呵呵,可惜網上找不到破解版。

    posted @ 2008-06-20 11:48 三人行,必有我師焉 閱讀(3827) | 評論 (1)編輯 收藏

    Eclipse3.4馬上就要Release了,相信Eclipse的fans都已經開始翹首以待,望穿秋水了。不過現在的RC版本用得很不爽呀,性能非常差,Eclipse的慣例就是最后一個月的工作基本上就是對性能做優化,以達到最佳使用效果。

    隨著Plugin的增多,Eclipse采用了特殊的策略,增加了一個子目錄dropins,用來放用戶新增加的plugin,而原有的plugins目錄,則基本用于系統基本功能,2者的區別就是,前者可以任意添加刪除,后者則基本上是一個ReadOnly的狀態,添加了就不能再作修改了,Eclipse會將每一個添加的plugin記錄下來,以后啟動就不再檢查這些plugin了。

    不過對于我來說,我一直都習慣于使用plugins目錄,下了一個插件直接解壓,就直接覆蓋安裝到plugins目錄了,而且有一些plugin不支持dropins目錄,必須在plugins目錄下才能正常工作。不過一旦插件安裝失敗,想再reset就比較麻煩了。Eclipse不會自動恢復到初始安裝狀態,經過測試,找到了一個解決方案,用原始的eclipse的文件替代2個目錄:configuration和p2目錄。plugins文件位置記錄在configuration\org.eclipse.equinox.simpleconfigurator\bundles.info里,p2目錄里則記錄了更多的初始化信息。要想Reset Eclipse3.4,這兩個目錄必須被恢復到初始化狀態,然后就可以正常使用了。

    posted @ 2008-06-17 22:30 三人行,必有我師焉 閱讀(7818) | 評論 (5)編輯 收藏

    最近的項目需要使用報表,因為是RCP應用,所以選擇了Birt,用了一下,感覺還可以,就是網上資料少了點,不過以前也研究過一些Eclipse相關技術,這些都不重要了,找了SDK版本Debug,啥研究不出來?

    BIRT是一個Eclipse-based開放源代碼報表系統。它主要是用在基于Java與J2EE的Web應用程序上。BIRT主要由兩部分組成:一個是基于Eclipse的報表設計和一個可以加到你應用服務的運行期組件。BIRT同時也提供一個圖形報表制作引擎。

    官方主頁:http://www.eclipse.org/birt
    官方BBS支持:http://www.actuatechina.com/forum2.html

    基本上來說Birt功能還是很強大的,支持時下比較流行的WebService,Ajax技術,既可用于Web,也可以用于桌面,更新也算穩定,基本上遵循Eclipse的開發步驟,一個一個大版本,同時支持腳本調用,debug開發等等。唯一不足的就是中國的國情支持得還不夠完善,畢竟中國比較特殊,我以前給公司做黨務報表,要按照紙質報表畫,一分一毫都不能變差,那個變態呀,在電腦上畫報表還是拿尺子量。

    剛剛開始用,慢慢研究,看了下Birt自帶的Example,的確是很強大,做得也很漂亮,自己試著創建一個報表也很簡單,希望能夠比較快的上手吧。

    在網上找了一些資源:
    http://blogger.org.cn/blog/more.asp?name=sixsun&id=13933 BIRT 中文指南
    http://www.springside.org.cn/docs/reference/Birt.htm BIRT報表
    http://www-128.ibm.com/developerworks/cn/opensource/os-ecl-birt/ Birt的IBM DW的中文教程
    http://download.eclipse.org/birt/downloads/demos/FirstReport/MyFirstReport.html Birt Flash Demo.
    posted @ 2008-06-12 12:02 三人行,必有我師焉 閱讀(6203) | 評論 (8)編輯 收藏

      最近很多人問我SWT Extension 項目上的那個不需要的JREExample是如何做出來的。我以前也會執著于這個問題,畢竟如果不依賴于JRE的話,就不需要為用戶準備一個容量極大的安裝包,但是這種做法看似有利,實則有利有弊。

    就我所知,目前把Java程序編譯成本機可執行程序的方法有兩種,一種是GCJ,免費的,一種是Excelsior JET,商業的。我已經很久沒有碰過GCJ了,因為當初用起來實在是非常麻煩,現在的版本如何,我不太清楚。我自己使用的是Excelsior JET,版本為3.7。有一點要注意的的是,Excelsior JET的后續版本好像已經不支持這個功能了,3.7是我所知的最后一個版本,能支持當前所有的Win32平臺和早期的Linux(當前比較流行的Ubuntu不支持,因為內核版本過高,不過企業版Redhat沒有問題)。不過我是很久以前從0day當下來的,由于0day倉儲只保留一年,故現在已經找不到了,我自己的機器上也沒有安裝包了(有一次大意之下,把整個Download目錄全給刪掉了,事后悔之晚矣)。

    Excelsior JET無非就是用自己的Runtime來代替JRE,只是比JRE更加靈活,根據Java程序具體的依賴來生成對應的Runtime。其實這個Runtime也挺大的,通常10M左右,不過比起JRE,那要小很多了。SWT Extension上的那個例子只有6M,是因為我用ASPack把所有的DLL文件全部壓縮過了,體積小了一半。

    就我的感覺,Excelsior JETGCJ更加靈活,也更好用,畢竟是商業版的東西,它的網站上曾經有例子將Eclipse 3.0編譯成本機程序,不過我當初照著例子試了一遍,沒有成功。Excelsior JET的編譯過程極為耗時,我上大學的時候,當時機器只有128M內存,編譯了一天JRE也沒有完成,后來找同學借了根256的內存,這才得以完成。

    JAVA代碼編譯成本機程序的弊端也是有的,那意味著你將無法在線升級,GCJ也許可以,但是Excelsior JET是絕對不行的,這是因為它最后一步要對所有DLL進行鏈接,如果更換了DLL文件,它會檢測出來并報錯。

    各位看官如果哪位有興趣,可以自行在網上查找Excelsior JET3.7或其他版本。由于安裝包我自己也沒有,故無法提供下載,見諒。

    posted @ 2008-05-18 15:38 三人行,必有我師焉 閱讀(6829) | 評論 (7)編輯 收藏

    GitHub |  開源中國社區 |  maven倉庫 |  文件格式轉換 
    主站蜘蛛池模板: 亚洲麻豆精品果冻传媒| 国产大片91精品免费看3| 永久在线免费观看| 久久青青草原国产精品免费| 成人免费区一区二区三区| 久久国产乱子精品免费女| 鲁丝片一区二区三区免费| 久久久久免费看黄a级试看| 3344在线看片免费| 一级毛片**不卡免费播| 精品无码国产污污污免费网站| 中文字幕在线观看免费视频 | 亚洲免费在线视频播放| 91亚洲国产成人久久精品| 亚洲人成片在线观看| 亚洲综合激情五月色一区| 亚洲hairy多毛pics大全| 精品视频免费在线| 国产免费一级高清淫曰本片| 丝瓜app免费下载网址进入ios| 免费成人在线电影| 亚洲一区二区三区免费视频| 国产高清免费视频| 日本高清免费不卡视频| 亚洲精品国产va在线观看蜜芽| 亚洲欧洲成人精品香蕉网| 亚洲美女精品视频| 亚洲欧美aⅴ在线资源| 老司机午夜性生免费福利| 国产中文字幕在线免费观看| 97免费人妻在线视频| 免费网站看v片在线香蕉| 亚洲美女在线国产| 亚洲福利视频一区| 亚洲狠狠成人综合网| 农村寡妇一级毛片免费看视频| 免费久久人人爽人人爽av| 在线观看免费人成视频色| 亚洲第一福利网站在线观看| 亚洲AV电影院在线观看| 亚洲AV男人的天堂在线观看|