根据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; } }