根据S3的Amazon S3 API Reference 和Amazon S3 Developer Guide,使用JAVA编写的putObject和getObject测试,同时测试了:MD5特性,ETAG,RANGE。
package amazons3;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.util.DateUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import sun.misc.BASE64Encoder;
public class S3ClientSimpleTest {
private static final Logger logger = Logger.getLogger(S3ClientSimpleTest.class);
static String accessKey = "your accessKey";
static String secretKey = "your secretKey";
static String bucket = "your bucket";
public static void main(String[] args) throws Exception {
File localFile = new File("D:/temp/s3testfile.txt");
putObject(localFile);
getObject("s3testfile.txt", "d:/temp/download", null, null, null);
}
public static void putObject(File localFile) throws Exception {
HttpURLConnection conn = null;
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
URL url = new URL("http://" + bucket + ".s3.amazonaws.com/" + localFile.getName());
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
conn.setDoOutput(true);
conn.setDoInput(true);
String contentMD5 = md5file(localFile);
logger.info("ContentMD5: " + contentMD5);
String contentType = "application/xml";
Date date = new Date();
String dateString = DateUtil.formatDate(date, DateUtil.PATTERN_RFC1036);
String sign = sign("PUT", contentMD5, contentType, dateString, "/" + bucket + "/" + localFile.getName(), null);
conn.setRequestProperty("Date", dateString);
conn.setRequestProperty("Authorization", sign);
conn.setRequestProperty("Content-Type", contentType);
conn.setRequestProperty("Content-MD5", contentMD5);
out = new BufferedOutputStream(conn.getOutputStream());
in = new BufferedInputStream(new FileInputStream(localFile));
byte[] buffer = new byte[1024];
int p = 0;
while ((p = in.read(buffer)) != -1) {
out.write(buffer, 0, p);
out.flush();
}
int status = conn.getResponseCode();
logger.info("http status: " + status);
logger.info("after:\n" + conn.getHeaderFields());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
close(in);
close(out);
}
}
public static File getObject(String objectName, String rootPath, Long start, Long end, String etag) {
HttpURLConnection conn = null;
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
URL url = new URL("http://" + bucket + ".s3.amazonaws.com/" + objectName);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setDoOutput(true);
String contentType = "application/xml";
Date date = new Date();
String dateString = DateUtil.formatDate(date, DateUtil.PATTERN_RFC1036);
String sign = sign("GET", "", contentType, dateString, "/" + bucket + "/" + objectName, null);
conn.setRequestProperty("Date", dateString);
conn.setRequestProperty("Authorization", sign);
conn.setRequestProperty("Content-Type", contentType);
// Range 特性
if (start != null && end != null) {
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
}
// Etag 特性
if (StringUtils.isNotBlank(etag)) {
conn.setRequestProperty("If-None-Match", etag);
}
int status = conn.getResponseCode();
logger.info("http status: " + status);
if (status == 304) {
// ETAG未变化,文件未变化,服务器返回空body
logger.info("after:\n" + conn.getHeaderFields());
return null;
}
in = new BufferedInputStream(conn.getInputStream());
File localFile = new File(rootPath + "/" + objectName);
if (!localFile.getParentFile().exists()) {
localFile.getParentFile().mkdirs();
}
out = new BufferedOutputStream(new FileOutputStream(localFile, false));
byte[] buffer = new byte[1024];
int p = 0;
while ((p = in.read(buffer)) != -1) {
out.write(buffer, 0, p);
out.flush();
}
logger.info("after:\n" + conn.getHeaderFields());
return localFile;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
close(in);
close(out);
}
}
private static void close(Closeable c) {
try {
if (c != null) {
c.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* MD5文件
*
* @param file
* @return
* @throws Exception
*/
public static String md5file(File file) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[1024 * 100];
int p = 0;
while ((p = in.read(buf)) != -1) {
messageDigest.update(buf, 0, p);
}
in.close();
byte[] digest = messageDigest.digest();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(digest);
}
/**
* 计算签名
*
* @param httpVerb
* @param contentMD5
* @param contentType
* @param date
* @param resource
* @param metas
* @return
*/
public static String sign(String httpVerb, String contentMD5, String contentType, String date, String resource, Map<String, String> metas) {
String stringToSign = httpVerb + "\n" + StringUtils.trimToEmpty(contentMD5) + "\n" + StringUtils.trimToEmpty(contentType) + "\n" + date + "\n";
if (metas != null) {
for (Map.Entry<String, String> entity : metas.entrySet()) {
stringToSign += StringUtils.trimToEmpty(entity.getKey()) + ":" + StringUtils.trimToEmpty(entity.getValue()) + "\n";
}
}
stringToSign += resource;
try {
Mac mac = Mac.getInstance("HmacSHA1");
byte[] keyBytes = secretKey.getBytes("UTF8");
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
mac.init(signingKey);
byte[] signBytes = mac.doFinal(stringToSign.getBytes("UTF8"));
String signature = encodeBase64(signBytes);
return "AWS" + " " + accessKey + ":" + signature;
} catch (Exception e) {
throw new RuntimeException("MAC CALC FAILED.");
}
}
private static String encodeBase64(byte[] data) {
String base64 = new String(Base64.encodeBase64(data));
if (base64.endsWith("\r\n"))
base64 = base64.substring(0, base64.length() - 2);
if (base64.endsWith("\n"))
base64 = base64.substring(0, base64.length() - 1);
return base64;
}
}