diff --git a/source/gateway/.gitignore b/source/gateway/.gitignore
index 24d64373..4f496dc3 100644
--- a/source/gateway/.gitignore
+++ b/source/gateway/.gitignore
@@ -1 +1,2 @@
/target/
+/.apt_generated_tests/
diff --git a/source/peer/.gitignore b/source/peer/.gitignore
index 24d64373..4f496dc3 100644
--- a/source/peer/.gitignore
+++ b/source/peer/.gitignore
@@ -1 +1,2 @@
/target/
+/.apt_generated_tests/
diff --git a/source/storage/storage-redis/.gitignore b/source/storage/storage-redis/.gitignore
new file mode 100644
index 00000000..da7560e0
--- /dev/null
+++ b/source/storage/storage-redis/.gitignore
@@ -0,0 +1 @@
+/.apt_generated_tests/
diff --git a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnection.java b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnection.java
index 6f3cb19e..d0a7e89d 100644
--- a/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnection.java
+++ b/source/storage/storage-rocksdb/src/main/java/com/jd/blockchain/storage/service/impl/rocksdb/RocksDBConnection.java
@@ -8,6 +8,7 @@ import org.rocksdb.RocksDBException;
import com.jd.blockchain.storage.service.DbConnection;
import com.jd.blockchain.storage.service.KVStorageService;
+import com.jd.blockchain.utils.io.FileUtils;
public class RocksDBConnection implements DbConnection {
@@ -19,6 +20,10 @@ public class RocksDBConnection implements DbConnection {
public RocksDBConnection(String dbPath, Options options) {
try {
+ String parentDir = FileUtils.getParent(dbPath);
+ if (!FileUtils.existDirectory(parentDir)) {
+ FileUtils.makeDirectory(parentDir);
+ }
this.db = RocksDB.open(options, dbPath);
} catch (RocksDBException e) {
throw new IllegalStateException(e.getMessage(), e);
@@ -43,7 +48,7 @@ public class RocksDBConnection implements DbConnection {
this.options = null;
RocksDB db = this.db;
this.db = null;
-
+
if (options != null) {
options.close();
}
diff --git a/source/test/test-consensus-client/.gitignore b/source/test/test-consensus-client/.gitignore
new file mode 100644
index 00000000..da7560e0
--- /dev/null
+++ b/source/test/test-consensus-client/.gitignore
@@ -0,0 +1 @@
+/.apt_generated_tests/
diff --git a/source/test/test-consensus-node/.gitignore b/source/test/test-consensus-node/.gitignore
new file mode 100644
index 00000000..da7560e0
--- /dev/null
+++ b/source/test/test-consensus-node/.gitignore
@@ -0,0 +1 @@
+/.apt_generated_tests/
diff --git a/source/test/test-integration/pom.xml b/source/test/test-integration/pom.xml
index b84a54bd..4901c7d4 100644
--- a/source/test/test-integration/pom.xml
+++ b/source/test/test-integration/pom.xml
@@ -49,7 +49,6 @@
com.jd.blockchain
crypto-classic
${project.version}
- test
diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java
index ec035f22..bb567b9b 100644
--- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java
+++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/LedgerPerformanceTest.java
@@ -110,7 +110,7 @@ public class LedgerPerformanceTest {
dbType = DBType.ROCKSDB;
}
- CryptoAlgorithm hashAlg = ArgumentSet.hasOption(args, "-160") ? Crypto.getAlgorithm("RIPEMD260")
+ CryptoAlgorithm hashAlg = ArgumentSet.hasOption(args, "-160") ? Crypto.getAlgorithm("RIPEMD160")
: Crypto.getAlgorithm("SHA256");
System.out.println(
String.format("----- LedgerPerformanceTest [HashAlgorithm=%s][DBType=%s] ----", hashAlg, dbType));
diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/PerformanceTest.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/PerformanceTest.java
index 38eba982..97124985 100644
--- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/PerformanceTest.java
+++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/PerformanceTest.java
@@ -23,7 +23,8 @@ public class PerformanceTest {
try {
boolean testLedger = !ArgumentSet.hasOption(args, "-test=storage");
if (testLedger) {
- LedgerPerformanceTest.test(new String[]{"-silent", "-contract", "-o"});
+// LedgerPerformanceTest.test(new String[]{"-silent", "-usertest", "-o"});
+ LedgerPerformanceTest.test(new String[]{"-silent", "-o", "-rocksdb"});
return;
}
diff --git a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java
index 27d67e1a..7bd15006 100644
--- a/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java
+++ b/source/test/test-integration/src/main/java/test/com/jd/blockchain/intgr/perf/Utils.java
@@ -39,16 +39,16 @@ public class Utils {
public static final String PASSWORD = "abc";
- public static final String[] PUB_KEYS = { "endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna",
- "endPsK36sC5JdPCDPDAXUwZtS3sxEmqEhFcC4whayAsTTh8Z6eoZ",
- "endPsK36jEG281HMHeh6oSqzqLkT95DTnCM6REDURjdb2c67uR3R",
- "endPsK36nse1dck4uF19zPvAMijCV336Y3zWdgb4rQG8QoRj5ktR" };
+ public static final String[] PUB_KEYS = { "3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu",
+ "3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf",
+ "3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr",
+ "3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS" };
public static final String[] PRIV_KEYS = {
- "177gjsj5PHeCpbAtJE7qnbmhuZMHAEKuMsd45zHkv8F8AWBvTBbff8yRKdCyT3kwrmAjSnY",
- "177gjw9u84WtuCsK8u2WeH4nWqzgEoJWY7jJF9AU6XwLHSosrcNX3H6SSBsfvR53HgX7KR2",
- "177gk2FpjufgEon92mf2oRRFXDBZkRy8SkFci7Jxc5pApZEJz3oeCoxieWatDD3Xg7i1QEN",
- "177gjvv7qvfCAXroFezSn23UFXLVLFofKS3y6DXkJ2DwVWS4LcRNtxRgiqWmQEeWNz4KQ3J" };
+ "177gjyoEUhdD1NkQSxBVvfSyovMd1ha5H46zsb9kyErLNBuQkLRAf2ea6CNjStjCFJQN8S1",
+ "177gjsa6KcyxUpx7T3tvCVMuqHvvguiQFRLmDY9jaMcH6L9R4k7XgANLfY3paC5XaXeASej",
+ "177gju7AgXp371qqprjEN3Lg4Hc4EWHnDH9eWgTttEUoN8PuNpQTbS253uTxdKn5w1zZXUp",
+ "177gjtddYr7CtN6iN6KRgu1kKzFn6quQsx3DQLnUD1xgj5E2QhUTMDnpZKzSKbB7kt35gzj" };
private Map serviceRegisterMap = new ConcurrentHashMap<>();
diff --git a/source/test/test-integration/src/main/resources/bftsmart.config b/source/test/test-integration/src/main/resources/bftsmart.config
new file mode 100644
index 00000000..df811663
--- /dev/null
+++ b/source/test/test-integration/src/main/resources/bftsmart.config
@@ -0,0 +1,178 @@
+
+# Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+############################################
+###### Consensus Commit Block Parameters: transaction count ######
+############################################
+system.block.txsize=15
+
+############################################
+###### Consensus Commit Block Parameters: delay time ######
+############################################
+system.block.maxdelay=500
+
+############################################
+###### Consensus Participant0 ######
+############################################
+system.server.0.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu
+
+system.server.0.network.host=127.0.0.1
+
+system.server.0.network.port=8910
+
+system.server.0.network.secure=false
+
+############################################
+###### #Consensus Participant1 ######
+############################################
+system.server.1.pubkey=3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf
+
+system.server.1.network.host=127.0.0.1
+
+system.server.1.network.port=8920
+
+system.server.1.network.secure=false
+
+############################################
+###### #Consensus Participant2 ######
+############################################
+system.server.2.pubkey=3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr
+
+system.server.2.network.host=127.0.0.1
+
+system.server.2.network.port=8930
+
+system.server.2.network.secure=false
+
+############################################
+###### Consensus Participant3 ######
+############################################
+system.server.3.pubkey=3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS
+
+system.server.3.network.host=127.0.0.1
+
+system.server.3.network.port=8940
+
+system.server.3.network.secure=false
+
+############################################
+####### Communication Configurations #######
+############################################
+
+#HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value)
+#This parameter is not currently being used being used
+#system.authentication.hmacAlgorithm = HmacSHA1
+
+#Specify if the communication system should use a thread to send data (true or false)
+system.communication.useSenderThread = true
+
+#Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments
+#and benchmarks, but must not be used in production systems.
+system.communication.defaultkeys = true
+
+############################################
+### Replication Algorithm Configurations ###
+############################################
+
+#Number of servers in the group
+system.servers.num = 4
+
+#Maximum number of faulty replicas
+#system.servers.f = 1
+
+#Timeout to asking for a client request
+system.totalordermulticast.timeout = 2000
+
+
+#Maximum batch size (in number of messages)
+system.totalordermulticast.maxbatchsize = 400
+
+#Number of nonces (for non-determinism actions) generated
+system.totalordermulticast.nonces = 10
+
+#if verification of leader-generated timestamps are increasing
+#it can only be used on systems in which the network clocks
+#are synchronized
+system.totalordermulticast.verifyTimestamps = false
+
+#Quantity of messages that can be stored in the receive queue of the communication system
+system.communication.inQueueSize = 500000
+
+# Quantity of messages that can be stored in the send queue of each replica
+system.communication.outQueueSize = 500000
+
+#Set to 1 if SMaRt should use signatures, set to 0 if otherwise
+system.communication.useSignatures = 0
+
+#Set to 1 if SMaRt should use MAC's, set to 0 if otherwise
+system.communication.useMACs = 1
+
+#Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise
+system.debug = 0
+
+#Print information about the replica when it is shutdown
+system.shutdownhook = true
+
+############################################
+###### State Transfer Configurations #######
+############################################
+
+#Activate the state transfer protocol ('true' to activate, 'false' to de-activate)
+system.totalordermulticast.state_transfer = true
+
+#Maximum ahead-of-time message not discarded
+system.totalordermulticast.highMark = 10000
+
+#Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered)
+system.totalordermulticast.revival_highMark = 10
+
+#Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs
+system.totalordermulticast.timeout_highMark = 200
+
+############################################
+###### Log and Checkpoint Configurations ###
+############################################
+
+system.totalordermulticast.log = true
+system.totalordermulticast.log_parallel = false
+system.totalordermulticast.log_to_disk = false
+system.totalordermulticast.sync_log = false
+
+#Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol)
+system.totalordermulticast.checkpoint_period = 1000
+system.totalordermulticast.global_checkpoint_period = 120000
+
+system.totalordermulticast.checkpoint_to_disk = false
+system.totalordermulticast.sync_ckp = false
+
+
+############################################
+###### Reconfiguration Configurations ######
+############################################
+
+#Replicas ID for the initial view, separated by a comma.
+# The number of replicas in this parameter should be equal to that specified in 'system.servers.num'
+#system.initial.view = 0,1,2,3
+
+#The ID of the trust third party (TTP)
+system.ttp.id = 7002
+
+#This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults
+system.bft = true
+
+#Custom View Storage;
+#view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage
+
diff --git a/source/test/test-integration/src/main/resources/ledger_init_test_integration.init b/source/test/test-integration/src/main/resources/ledger_init_test_integration.init
index 7744270f..a0b6f736 100644
--- a/source/test/test-integration/src/main/resources/ledger_init_test_integration.init
+++ b/source/test/test-integration/src/main/resources/ledger_init_test_integration.init
@@ -13,26 +13,26 @@ cons_parti.0.name=jd.com
#第0个参与方的公钥文件路径;
cons_parti.0.pubkey-path=keys/jd-com.pub
#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
-cons_parti.0.pubkey=endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna
+cons_parti.0.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu
#第0个参与方的共识服务的主机地址;
cons_parti.0.consensus.host=127.0.0.1
#第0个参与方的共识服务的端口;
cons_parti.0.consensus.port=8900
#第0个参与方的共识服务是否开启安全连接;
-cons_parti.0.consensus.secure=false
+cons_parti.0.consensus.secure=true
#第0个参与方的账本初始服务的主机;
cons_parti.0.initializer.host=127.0.0.1
#第0个参与方的账本初始服务的端口;
-cons_parti.0.initializer.port=10100
+cons_parti.0.initializer.port=8800
#第0个参与方的账本初始服务是否开启安全连接;
-cons_parti.0.initializer.secure=false
+cons_parti.0.initializer.secure=true
#第1个参与方的名称;
cons_parti.1.name=at.com
#第1个参与方的公钥文件路径;
cons_parti.1.pubkey-path=keys/at-com.pub
#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
-cons_parti.1.pubkey=endPsK36sC5JdPCDPDAXUwZtS3sxEmqEhFcC4whayAsTTh8Z6eoZ
+cons_parti.1.pubkey=3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf
#第1个参与方的共识服务的主机地址;
cons_parti.1.consensus.host=127.0.0.1
#第1个参与方的共识服务的端口;
@@ -42,7 +42,7 @@ cons_parti.1.consensus.secure=false
#第1个参与方的账本初始服务的主机;
cons_parti.1.initializer.host=127.0.0.1
#第1个参与方的账本初始服务的端口;
-cons_parti.1.initializer.port=10110
+cons_parti.1.initializer.port=8810
#第1个参与方的账本初始服务是否开启安全连接;
cons_parti.1.initializer.secure=false
@@ -51,7 +51,7 @@ cons_parti.2.name=bt.com
#第2个参与方的公钥文件路径;
cons_parti.2.pubkey-path=keys/bt-com.pub
#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
-cons_parti.2.pubkey=endPsK36jEG281HMHeh6oSqzqLkT95DTnCM6REDURjdb2c67uR3R
+cons_parti.2.pubkey=
#第2个参与方的共识服务的主机地址;
cons_parti.2.consensus.host=127.0.0.1
#第2个参与方的共识服务的端口;
@@ -61,16 +61,16 @@ cons_parti.2.consensus.secure=false
#第2个参与方的账本初始服务的主机;
cons_parti.2.initializer.host=127.0.0.1
#第2个参与方的账本初始服务的端口;
-cons_parti.2.initializer.port=10120
+cons_parti.2.initializer.port=8820
#第2个参与方的账本初始服务是否开启安全连接;
-cons_parti.2.initializer.secure=false
+cons_parti.2.initializer.secure=true
#第3个参与方的名称;
cons_parti.3.name=xt.com
#第3个参与方的公钥文件路径;
cons_parti.3.pubkey-path=keys/xt-com.pub
#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
-cons_parti.3.pubkey=endPsK36nse1dck4uF19zPvAMijCV336Y3zWdgb4rQG8QoRj5ktR
+cons_parti.3.pubkey=3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS
#第3个参与方的共识服务的主机地址;
cons_parti.3.consensus.host=127.0.0.1
#第3个参与方的共识服务的端口;
@@ -80,6 +80,6 @@ cons_parti.3.consensus.secure=false
#第3个参与方的账本初始服务的主机;
cons_parti.3.initializer.host=127.0.0.1
#第3个参与方的账本初始服务的端口;
-cons_parti.3.initializer.port=10130
+cons_parti.3.initializer.port=8830
#第3个参与方的账本初始服务是否开启安全连接;
cons_parti.3.initializer.secure=false
diff --git a/source/test/test-integration/src/main/resources/ledger_init_test_web2.init b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init
new file mode 100644
index 00000000..9b24cbcf
--- /dev/null
+++ b/source/test/test-integration/src/main/resources/ledger_init_test_web2.init
@@ -0,0 +1,61 @@
+
+#账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取;
+ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe
+
+#账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途;
+#ledger.name=
+
+#参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置;
+cons_parti.count=4
+
+#第0个参与方的名称;
+cons_parti.0.name=jd.com
+#第0个参与方的公钥文件路径;
+cons_parti.0.pubkey-path=keys/jd-com.pub
+#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
+cons_parti.0.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu
+#第0个参与方的账本初始服务的主机;
+cons_parti.0.initializer.host=127.0.0.1
+#第0个参与方的账本初始服务的端口;
+cons_parti.0.initializer.port=9800
+#第0个参与方的账本初始服务是否开启安全连接;
+cons_parti.0.initializer.secure=false
+
+#第1个参与方的名称;
+cons_parti.1.name=at.com
+#第1个参与方的公钥文件路径;
+cons_parti.1.pubkey-path=keys/at-com.pub
+#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
+cons_parti.1.pubkey=3snPdw7i7Ph1SYLQt9uqVEqiuvNXjxCdGvEdN6otJsg5rbr7Aze7kf
+#第1个参与方的账本初始服务的主机;
+cons_parti.1.initializer.host=127.0.0.1
+#第1个参与方的账本初始服务的端口;
+cons_parti.1.initializer.port=9810
+#第1个参与方的账本初始服务是否开启安全连接;
+cons_parti.1.initializer.secure=false
+
+#第2个参与方的名称;
+cons_parti.2.name=bt.com
+#第2个参与方的公钥文件路径;
+cons_parti.2.pubkey-path=keys/bt-com.pub
+#第2个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
+cons_parti.2.pubkey=3snPdw7i7PezptA6dNBkotPjmKEbTkY8fmusLBnfj8Cf7eFwhWDwKr
+#第2个参与方的账本初始服务的主机;
+cons_parti.2.initializer.host=127.0.0.1
+#第2个参与方的账本初始服务的端口;
+cons_parti.2.initializer.port=9820
+#第2个参与方的账本初始服务是否开启安全连接;
+cons_parti.2.initializer.secure=false
+
+#第3个参与方的名称;
+cons_parti.3.name=xt.com
+#第3个参与方的公钥文件路径;
+cons_parti.3.pubkey-path=keys/xt-com.pub
+#第3个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数;
+cons_parti.3.pubkey=3snPdw7i7PerZYfRzEB61SAN9tFK4yHm9wUSRtkLSSGXHkQRbB5PkS
+#第3个参与方的账本初始服务的主机;
+cons_parti.3.initializer.host=127.0.0.1
+#第3个参与方的账本初始服务的端口;
+cons_parti.3.initializer.port=9830
+#第3个参与方的账本初始服务是否开启安全连接;
+cons_parti.3.initializer.secure=false
diff --git a/source/test/test-ledger-core/pom.xml b/source/test/test-ledger-core/pom.xml
index 810f2339..131179fe 100644
--- a/source/test/test-ledger-core/pom.xml
+++ b/source/test/test-ledger-core/pom.xml
@@ -20,5 +20,10 @@
storage-redis
${project.version}
+
+ com.jd.blockchain
+ crypto-classic
+ ${project.version}
+
\ No newline at end of file
diff --git a/source/tools/tools-initializer/.gitignore b/source/tools/tools-initializer/.gitignore
new file mode 100644
index 00000000..da7560e0
--- /dev/null
+++ b/source/tools/tools-initializer/.gitignore
@@ -0,0 +1 @@
+/.apt_generated_tests/
diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java
index 1d82d10d..e5ba84f9 100644
--- a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java
+++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/io/FileUtils.java
@@ -41,6 +41,17 @@ public class FileUtils {
throw new IllegalStateException(e.getMessage(), e);
}
}
+
+ /**
+ * 返回父目录的路径;
+ *
+ * @param path path
+ * @return String
+ */
+ public static String getParent(String path) {
+ File file = new File(path);
+ return file.getParent();
+ }
/**
* 以默认字符集(UTF-8)读取指定文件的首行;