========================== **S3 Java SDK手册** ========================== 安装 ----- Java环境 ````````````````` JDK 6及以上版本 Maven项目中使用 ````````````````` 在Maven工程中使用AWS S3 Java SDK只需在pom.xml中加入相应依赖即可 .. code:: xml com.amazonaws aws-java-sdk-s3 1.11.125 org.bouncycastle bcprov-jdk15on 1.55 工程中直接引入jar ````````````````` * 下载包含AWS Java SDK及其依赖的开发包: `aws-java-sdk.zip `_; * 解压该开发包; * 将解压后文件夹下lib文件夹中aws-java-sdk-1.11.254.jar(版本可能不一样)的以及third-party/lib文件夹下的所有jar文件拷贝到您的项目中; * 在Eclipse中选择您的工程,右击 -> Properties -> Java Build Path -> Add JARs * 选中您在第三步拷贝的所有JAR文件 * 在Intellij Idea中,选取所有的JAR文件,右击 -> Add As Library * 如果要使用客户端加密,需要加入 `bcprov-jdk15on `_ 包 前言 ------- Java SDK提供的接口都在AmazonS3中实现,并以成员方法的方式对外提供调用。因此使用Java SDK前必须实例化一个AmazonS3对象。 关于请求参数 ````````````````` AmazonS3中的方法一般都提供两种参数传入方式: * 普通传参方式: example: .. code:: java AmazonS3.createBucket(bucketName); * request对象传参方式: example: .. code:: java CreateBucketRequest request = new CreateBucketRequest(bucketName); request.setCannedAcl(CannedAccessControlList.Private); AmazonS3.createBucket(request); 后面的使用指南只以其中的一种传参方式作为例子。 关于异常 ````````````````` 所有错误异常包装在两个异常类型中,在调用Java SDK接口的时候,捕捉这些异常并打印必要的信息有利于定位问题(ps:在JAVA SDK使用指南的简单示例代码没有重复赘述,使用时注意添加)。 .. code:: java try{ s3Client.XXX("XXX"); //捕捉NOS服务器异常错误 }catch (AmazonServiceException e1){ System.out.println("Error Message: " + e1.getMessage()); //错误描述信息 System.out.println("HTTP Status Code: " + e1.getStatusCode()); //错误http状态码 System.out.println("NOS Error Code: " + e1.getErrorCode()); //服务器定义错误码 System.out.println("Error Type: " + e1.getErrorType()); //客户端的请求错误还是服务端的处理错误 System.out.println("Request ID: " + e1.getRequestId()); //请求ID,非常重要,有利于nos开发人员跟踪异常请求的错误原因 //捕捉客户端错误 }catch(SdkClientException e2){ System.out.println("Error Message: " + e2.getMessage()); //客户端错误信息 } 初始化 ------- 1. 确定Endpoint 目前有效的Endpoint为:nos-eastchina1.126.net 2. 获取密钥对 使用AWS S3 Java SDK前,您需要拥有一个有效的 Access Key(包括Access Key和Access Secret)用来进行签名认证。可以通过如下步骤获得: 1)登录 https://c.163.com/ 注册用户 2)注册后,蜂巢会颁发 Access Key 和 Secret Key 给客户,您可以在蜂巢“用户中心”的“Access Key”查看并管理您的Access Key 3. 在代码中实例化AmazonS3 *S3推荐获取accessKey,secretKey的方式* .. code:: java AWSCredentials credentials = null; try { credentials = new ProfileCredentialsProvider().getCredentials(); } catch (Exception e) { throw new AmazonClientException( "Cannot load the credentials from the credential profiles file. " + "Please make sure that your credentials file is at the correct " + "location (~/.aws/credentials), and is in valid format.", e); } /* credentials文件的目录:~/.aws/credentials credentials文件中的格式: [default] aws_access_key_id = xxxx aws_secret_access_key = xxx */ *推荐使用的方式* .. code:: java String accessKey = "your-accesskey"; String secretKey = "your-secretKey "; AWSCredentials credentials = new BasicAWSCredentials(accessKey,secretKey); AmazonS3 s3 = AmazonS3ClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(credentials)) .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("endpoint","region"))//endpoint,region请指定为NOS支持的(us-east-1:hz,us-east2:bj) .build(); *不推荐使用的方式* .. code:: java String accessKey = "your-accesskey"; String secretKey = "your-secretKey "; AWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey); AmazonS3 s3Client = new AmazonS3Client(credentials);//该方法弃用,不推荐使用 s3Client.setEndpoint(endPoint);//由于s3的sdk默认使用的是s3的服务地址,所以如果要使用NOS的服务,必须显示指定Endpoint *注:AmazonS3是线程安全的,可以并发使用* 4. 配置AmazonS3 如果您需要修改AmazonS3的默认参数,可以在实例化AmazonS3时传入ClientConfiguration实例。ClientConfiguration是AmazonS3的配置类,可配置连接超时、最大连接数等参数。通过ClientConfiguration可以设置的参数见下表: .. list-table:: :widths: 10 40 10 :header-rows: 1 * - 参数 - 描述 - 调用方法 * - connectionTimeout - | 建立连接的超时时间(单位:毫秒) | 默认:50000毫秒 - setConnectionTimeout * - maxConnections - | 允许打开的最大HTTP连接数 | 默认:50 - setMaxConnections * - socketTimeout - | Socket层传输数据超时时间(单位:毫秒) | 默认:50000毫秒 - setSocketTimeout * - maxErrorRetry - | 请求失败后最大的重试次数 | 默认:3次 - setMaxErrorRetry * - protocol - | 使用http协议还是https协议 | 默认:https协议 - setProtocol 带ClientConfiguration参数实例化AmazonS3的示例代码: .. code:: java import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; String accessKey = "your-accesskey"; String secretKey = "your-secretKey "; Credentials credentials = new BasicCredentials(accessKey, secretKey); ClientConfiguration conf = new ClientConfiguration(); // 设置AmazonS3使用的最大连接数 conf.setMaxConnections(200); // 设置socket超时时间 conf.setSocketTimeout(10000); // 设置失败请求重试次数 conf.setMaxErrorRetry(2); // 如果要用https协议,请加上下面语句 conf.setProtocol(Protocol.HTTPS); //AmazonS3 s3Client = new AmazonS3Client(credentials,clientConfiguration); //s3Client.setEndpoint(endPoint); AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withCredentials(new AWSStaticCredentialsProvider(credentials)) .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("endpoint,"region"))//endpoint,region请指定为NOS支持的 .withClientConfiguration(conf) .build(); *注意:后面的示例代码默认您已经实例化了所需的AmazonS3对象* 5. 在代码中实例化AmazonS3Encryption 可以把AmazonS3Encryption当做AmazonS3用,除了StrictAuthenticatedEncryption这个不支持range,且要求JDK必须在1.7及以上,由于NOS目前不支持KMS,所以用户的CMK只能自己管理 .. code:: java String accessKey = "your-accesskey"; String secretKey = "your-secretKey "; //1.获取CMK,客户端主密钥,可以使用对称和分对称两种方式,下述使用的是非对称的 KeyPair keyPair = loadKeyPair(keyDir,"RSA"); // 2. Construct an instance of AmazonS3Encryption. EncryptionMaterials encryptionMaterials = new EncryptionMaterials( keyPair); ClientConfiguration configuration = new ClientConfiguration(); configuration.setProtocol(Protocol.HTTPS); CryptoConfiguration cryptoConfiguration = new CryptoConfiguration(); //支持EncryptionOnly,AuthenticatedEncryption,StrictAuthenticatedEncryption,默认是EncryptionOnly,StrictAuthenticatedEncryption不支持range请求 cryptoConfiguration.setCryptoMode(CryptoMode.StrictAuthenticatedEncryption); //保存加密信息的方式,有两种方式,Instruction模式和Metadata模式,由于NOS分块上传和S3支持上存在一些差异,导致metadata保存的方式大文件下载时由于找不到加密信息而不解密 cryptoConfiguration.setStorageMode(CryptoStorageMode.InstructionFile); EncryptionMaterialsProvider encryptionMaterialsProvider = new StaticEncryptionMaterialsProvider(encryptionMaterials); ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setProtocol(Protocol.HTTPS); AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration("nos-eastchina1.126.net","us-east-1"); AmazonS3Encryption encryptionClient = AmazonS3EncryptionClientBuilder.standard().withCryptoConfiguration(cryptoConfiguration). withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey,secretKey))) .withEncryptionMaterials(encryptionMaterialsProvider).withClientConfiguration(clientConfiguration).withEndpointConfiguration(endpointConfiguration).build(); //loadKeyPair的实现方式,非对称加密algorithm = RSA KeyPair loadKeyPair(String path, String algorithm) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { // read public key from file File filePublicKey = new File(path + "/public.key"); FileInputStream fis = new FileInputStream(filePublicKey); byte[] encodedPublicKey = new byte[(int) filePublicKey.length()]; fis.read(encodedPublicKey); fis.close(); // read private key from file File filePrivateKey = new File(path + "/private.key"); fis = new FileInputStream(filePrivateKey); byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()]; fis.read(encodedPrivateKey); fis.close(); // Convert them into KeyPair KeyFactory keyFactory = KeyFactory.getInstance(algorithm); X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( encodedPublicKey); PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec( encodedPrivateKey); PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec); return new KeyPair(publicKey, privateKey); } //对称加密,algorithm = AES SecretKey loadKeyPair(String path, String algorithm) throws IOException { //Read private key from file. File keyFile = new File(path); FileInputStream keyfis = new FileInputStream(keyFile); byte[] encodedPrivateKey = new byte[(int) keyFile.length()]; keyfis.read(encodedPrivateKey); keyfis.close(); //Generate secret key. return new SecretKeySpec(encodedPrivateKey, algorithm); } //生成Key的方式,非对称加密 public static KeyPair genKeyPair(String algorithm, int bitLength) throws NoSuchAlgorithmException { KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(algorithm); SecureRandom srand = new SecureRandom(); keyGenerator.initialize(bitLength, srand); return keyGenerator.generateKeyPair(); } //生成Key的方式,对称加密 SecretKey generateCMasterKey() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { KeyGenerator symKeyGenerator = null; try { symKeyGenerator = KeyGenerator.getInstance("AES"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } symKeyGenerator.init(256); return symKeyGenerator.generateKey(); } //保存Key,该key只要生成一次就好了,要妥善保管,如果该key丢失了,那么意味着通过该key加密的数据将没法解密 //非对称 public static void saveKeyPair(String dir, KeyPair keyPair) throws IOException { PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec( publicKey.getEncoded()); FileOutputStream fos = new FileOutputStream(dir + "/public.key"); fos.write(x509EncodedKeySpec.getEncoded()); fos.close(); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec( privateKey.getEncoded()); fos = new FileOutputStream(dir + "/private.key"); fos.write(pkcs8EncodedKeySpec.getEncoded()); fos.close(); } //对称 void saveSymmetricKey(String path, SecretKey secretKey) throws IOException { X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec( secretKey.getEncoded()); FileOutputStream keyfos = new FileOutputStream(path); keyfos.write(x509EncodedKeySpec.getEncoded()); keyfos.close(); } *加密模式* ========== ============ ============ ============ ============ ==================== Java SDK CryptoMode Encrypt Decrypt Range Get Multipart Upload ---------- ------------ ------------ ------------ ------------ -------------------- 1.7.8.1+ AE AES‑GCM AES‑GCM Yes YES 1.7.8.1+ SAE AES‑GCM AES‑GCM No YES 1.7.8.1+ EO AES‑CBC AES‑GCM AES-CBC YES ========== ============ ============ ============ ============ ==================== *CryptoMode* * AE : AuthenticatedEncryption * SAE : StrictAuthenticatedEncryption * EO : EncryptionOnly 桶管理 ------- 创建桶 ````````````````` 您可以通过AmazonS3.createBucket创建一个桶。示例代码如下: .. code:: java //设置您要创建桶的名称 CreateBucketRequest request = new CreateBucketRequest(bucketName); //设置桶的权限,如果不设置,默认为Private request.setCannedAcl(CannedAccessControlList.PublicRead); AmazonS3.createBucket(request); *注意:* *1. 桶的命名规范参见API文档* *2. NOS中的桶名是全局唯一的,您或者他人已经创建了同名桶,您无法再创建该名称的桶* 列举桶 ````````````````` 您可以通过AmazonS3.listBuckets列举出当前用户拥有的所有桶。示例代码如下: .. code:: java for (Bucket bucket : s3Client.listBuckets()) { System.out.println(" - " + bucket.getName()); } 删除桶 ````````````````` 您可以通过AmazonS3.deleteBucket删除指定的桶。示例代码如下: .. code:: java s3Client.deleteBucket(bucketName); *注意:* *如果指定的桶不为空(桶中有文件或者未完成的分块上传),则桶无法删除* 查看桶是否存在 ````````````````` 您可以通过AmazonS3.doesBucketExist查看指定的桶是否存在。示例代码如下: .. code:: java boolean exists = s3Client.doesBucketExist(bucketName); *注意:* *您或者他人已经创建了指定名称的桶,doesBucketExist都会返回true。否则返回false* 设置桶的ACL ````````````````` 桶的ACL包含两类:Private(私有), PublicRead(公共读私有写)。您可以通过AmazonS3.setBucketAcl设置桶的权限。 .. list-table:: :widths: 10 10 :header-rows: 1 * - 权限 - SDK中的对应值 * - 私有读写,对应的Permission为WRITE - CannedAccessControlList.Private * - 公共读私有写,对应的Permission为READ - CannedAccessControlList.PublicRead * - 公共读写 - CannedAccessControlList.PublicReadWrite,NOS不支持 示例代码如下: .. code:: java //method 1,使用header的方式 AmazonS3.setBucketAcl(bucketName, CannedAccessControlList.Private); //method 2,使用body的方式 AccessControlList accessControlList1 = new AccessControlList(); Grantee grantee = new CanonicalGrantee("aa"); accessControlList1.setOwner(new Owner()); accessControlList1.grantPermission(grantee,Permission.Write);//授权列表中的第一个值为有效值,其他的值会被忽略 s3Client.setBucketAcl(bucketName,accessControlList1); 查看桶的ACL ````````````````` 您可以通过AmazonS3.getBucketAcl()查看桶的权限。示例代码如下: .. code:: java AccessControlList accessControlList = s3Client.getBucketAcl(bucketName); System.out.println("owner : " + accessControlList.getOwner().getId() + " : " + accessControlList.getOwner().getDisplayName()); for(Grant grant : accessControlList.getGrantsAsList()){//NOS由于权限不能赋值给其他的用户,所以返回值中只有一条记录 System.out.println(grant.getGrantee().getIdentifier() + " : " + grant.getPermission() + " : " + grant.getGrantee().getTypeIdentifier()); } 文件上传 -------- 在NOS中,用户的每个文件都是一个Object(对象)。 NOS提供两种文件上传方式:普通上传(PutObject),上传小于或等于100M的文件;分块上传(MultiUpload),大文件可以采用该方式上传。 AWS Java SDK提供了丰富的文件上传接口与功能,主要有: * 直接内容上传 * 本地文件普通上传 * 支持上传文件时设置文件元数据信息 * 流式上传 * 分块上传 *下述除了分块上传不能直接使用加密client替换外,其他的都是可以直接替换使用* 直接内容上传 ````````````````` 对于一些简单的字符串内容,可以使用putObject进行上传。代码示例如下: .. code:: java //要上传文件的路径 String content = "Object content"; try { s3Client.putObject("your-bucketname","your-objectname",content); }catch (Exception e){ System.out.println(e.getMessage()); } 本地文件普通上传 ````````````````` 对于小对象可以使用putObject接口进行上传,putObject上传支持的最大文件大小为100M,如果上传大于100M的文件需要使用分块上传。本地文件普通上传的示例代码如下: .. code:: java //要上传文件的路径 String filePath = "your-local-file-path"; try { s3Client.putObject("your-bucketname","your-objectname", new File(filePath)); }catch (Exception e){ System.out.println(e.getMessage()); } 上传文件时设置文件元数据信息 ``````````````````````````````` 您可以在上传文件时设置文件元数据信息。可以设置的元数据主要有文件的Content-Type和用户自定义元数据信息。 这里以普通上传为例: .. code:: java String filePath = "your-local-file-path"; ObjectMetadata objectMetadata = new ObjectMetadata(); //设置Content-Type objectMetadata.setContentType("application/xml"); //设置标准http消息头(元数据) objectMetadata.setHeader("Cache-Control", "no-cache"); //设置用户自定义元数据信息 Map userMeta = new HashMap(); userMeta.put("ud", "test"); objectMetadata.setUserMetadata(userMeta); PutObjectRequest putObjectRequest = new PutObjectRequest("your-bucketname","your-objectname", new File(filePath)); putObjectRequest.setMetadata(objectMetadata); s3Client.putObject(putObjectRequest); 流式上传 ````````````````` .. code:: java try { ObjectMetadata objectMetadata = new ObjectMetadata(); //设置流的长度,您还可以设置其他文件元数据信息 objectMetadata.setContentLength(streamLength); s3Client.putObject("your-bucketname","your-objectname", inputStream, objectMetadata) }catch (Exception e){ System.out.println(e.getMessage()); } 分块上传 ````````````````` 对于大于100M的对象必须进行分块上传,分块上传的最小单位单位为16K,最后一块可以小于16K,最大单位为100M,较大文件使用分块上传失败的代价比较小,只需要重新上传失败的分块即可; 在文件已经全部存在情况下可以进行分块并发上传。 * 初始化分块上传 .. code:: java //初始化一个分块上传,获取分块上传ID,桶名 + 对像名 + 分块上传ID 唯一确定一个分块上传 FileInputStream is = new FileInputStream("youFilePath"); InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest("your-bucketname", "your-objectname"); //您还可以在初始化分块上传时,设置文件的Content-Type ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentType("application/xml"); initRequest.setObjectMetadata(objectMetadata); InitiateMultipartUploadResult initResult = s3Client.initiateMultipartUpload(initRequest); String uploadId = initResult.getUploadId(); * 进行分块上传 下面是顺序上传所有分块的示例,您也可以进行并发上传。 .. code:: java long filePosition = 0; for (int i = 1; filePosition < contentLength; i++) { // Last part can be less than 5 MB. Adjust part size. partSize = Math.min(partSize, (contentLength - filePosition)); // Create request to upload a part. UploadPartRequest uploadRequest = new UploadPartRequest() .withBucketName(bucketName).withKey(key) .withUploadId(uploadId).withPartNumber(i) .withFileOffset(filePosition) .withFile(file) //要上传的文件对象 .withPartSize(partSize); //如果是加密的,需要加入这步 if (filePosition + partSize == contentLength){ uploadRequest.setLastPart(true); } // Upload part and add response to our list. partETags.add(encryptionClient.uploadPart(uploadRequest).getPartETag()); ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, initResponse.getUploadId()); encryptionClient.listParts(listPartsRequest); filePosition += partSize; } * 列出所有分块 .. code:: java //这里可以检查分块是否全部上传,分块MD5是否与本地计算相符,如果不符或者缺少可以重新上传 List partETags = new ArrayList(); int nextMarker = 0; while (true) { ListPartsRequest listPartsRequest = new ListPartsRequest("your-bucketname", "your-objectname", uploadId); listPartsRequest.setPartNumberMarker(nextMarker); PartListing partList = s3Client.listParts(listPartsRequest); for (PartSummary ps : partList.getParts()) { nextMarker++; partETags.add(new PartETag(ps.getPartNumber(), ps.getETag())); } if (!partList.isTruncated()) { break; } } * 完成分块上传 .. code:: java CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest( "your-bucketname","your-objectname", uploadId, partETags); CompleteMultipartUploadResult completeResult = s3Client.completeMultipartUpload(completeRequest); * 取消分块上传 .. code:: java s3Client.abortMultipartUpload(new AbortMultipartUploadRequest( bucketName, key, initResponse.getUploadId())); 文件下载 -------- 您可以通过指定桶名和对象名调用getObject接口进行文件下载。AWS S3 Java SDK提供了如下下载方式: * 流式下载 * 下载到本地文件 * Range下载 * 指定If-Modified-Since进行下载 *也是可以直接使用加密client进行替换,除了StrictAuthenticatedEncryption不支持range* 流式下载 ````````````````` .. code:: java S3Object nosObject = AmazonS3.getObject("your-bucketname","your-objectname"); //可以通过NOSObject对象的getObjectMetadata方法获取对象的ContentType等元数据信息 String contentType = nosObject.getObjectMetadata().getContentType(); //流式获取文件内容 InputStream in = nosObject.getObjectContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); while (true) { String line; try { line = reader.readLine(); if (line == null) break; System.out.println("\n" + line); } catch (IOException e) { e.printStackTrace(); } } try { reader.close(); } catch (IOException e) { e.printStackTrace(); } *注意:* * AmazonS3.getObject获取的流一定要显式的close,否则会造成资源泄露。 下载到本地文件 ````````````````` 你可以通过调用AWS S3 Java SDK的getObject接口直接将NOS中的对象下载到本地文件 .. code:: java String destinationFile = "your-local-filepath"; GetObjectRequest getObjectRequest = new GetObjectRequest("your-bucketname","your-objectname"); ObjectMetadata objectMetadata = s3Client.getObject(getObjectRequest, new File(destinationFile)); Range下载 ````````````````` AWS S3 Java SDK支持范围(Range)下载,即下载指定对象的指定范围的数据。 .. code:: java GetObjectRequest getObjectRequest = new GetObjectRequest("your-bucketname","your-objectname"); getObjectRequest.setRange(0, 100); S3Object nosObject = s3Client.getObject(getObjectRequest); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); while (true) { String line; try { line = reader.readLine(); if (line == null) break; System.out.println("\n" + line); } catch (IOException e) { e.printStackTrace(); } } try { reader.close(); } catch (IOException e) { e.printStackTrace(); } 指定If-Modified-Since进行下载 `````````````````````````````````` 下载文件时,您可以指定If-Modified-Since参数,满足文件的最后修改时间小于等于If-Modified-Since参数指定的时间,则不进行下载,否则正常下载文件。 .. code:: java //假设需要下载的文件的最后修改时间为: Date lastModified; //lastModified小于等于指定If-Modified-Since参数 GetObjectRequest getObjectRequest = new GetObjectRequest("your-bucketname","your-objectname"); Date afterTime = new Date(lastModified.getTime() + 1000); getObjectRequest.setModifiedSinceConstraint(afterTime); //此时nosObject等于null S3Object s3Object = client.getObject(getObjectRequest); Date beforeTime = new Date(lastModified.getTime() -1000); getObjectRequest.setModifiedSinceConstraint(beforeTime); //此时s3Object不等于null,可以正常获取文件内容 s3Object = client.getObject(getObjectRequest); BufferedReader reader = new BufferedReader(new InputStreamReader(s3Object.getObjectContent())); while (true) { String line; try { line = reader.readLine(); if (line == null) break; System.out.println("\n" + line); } catch (IOException e) { e.printStackTrace(); } } try { reader.close(); } catch (IOException e) { e.printStackTrace(); } 文件管理 -------- 您可以通过AWS S3 Java SDK进行如下文件管理操作: * 判断文件是否存在 * 文件删除 * 获取文件元数据信息 * 文件复制(copy) * 列举桶内文件 * 生成私有对象可下载的URL链接 判断文件是否存在 `````````````````````````````````` 您可以通过AmazonS3.doesObjectExist判断文件是否存在。 .. code:: java boolean isExist = s3Client.doesObjectExist("your-bucketname","your-objectname"); 文件删除 `````````````````````` 您可以通过AmazonS3.deleteObject删除单个文件 .. code:: java s3Client.deleteObject("your-bucketname","your-objectname"); 您还可以通过AmazonS3.deleteObjects一次删除多个文件 .. code:: java try { DeleteObjectsResult result = s3Client.deleteObjects(deleteObjectsRequest); List deleteObjects = result.getDeletedObjects(); //print the delete results for (DeletedObject items: deleteObjects){ System.out.println(items.getKey()); } // 部分对象删除失败 } catch (MultiObjectDeleteException e) { List deleteErrors = e.getErrors(); for (DeleteError error : deleteErrors) { System.out.println(error.getKey()); } } catch (AmazonServiceException e) { //捕捉nos服务器异常错误 } catch (AmazonClientException ace) { //捕捉客户端错误 } 获取文件元数据信息 `````````````````````` 您可以通过AmazonS3.getObjectMetadata获取文件元数据信息 .. code:: java s3Client.getObjectMetadata("your-bucketname","your-objectname"); 文件复制(copy) `````````````````````` 您可以通过AmazonS3.copyObject接口实现文件拷贝功能。 NOS支持桶内copy以及相同用户的跨桶copy。 .. code:: java s3Client.copyObject("source-bucket", "source-object", "dst-bucket", "dst-object"); 列举桶内文件 `````````````````````` 您可以通过AmazonS3.listObjects列出桶里的文件。listObjects接口如果调用成功,会返回一个ObjectListing对象,列举的结果保持在该对象中。 ObjectListing的具体信息如下表所示: .. list-table:: :widths: 10 10 :header-rows: 1 * - 方法 - 含义 * - List getObjectSummaries() - 返回的文件列表(包含文件的名称、Etag的元数据信息) * - String getPrefix() - 本次查询的文件名前缀 * - String getDelimiter() - 文件分界符 * - String getMarker() - 这次List Objects的起点 * - int getMaxKeys() - 响应请求内返回结果的最大数目 * - String getNextMarker() - 下一次List Object的起点 * - boolean isTruncated() - 是否截断,如果因为设置了limit导致不是所有的数据集都返回,则该值设置为true * - List getCommonPrefixes() - 如果请求中指定了delimiter参数,则返回的包含CommonPrefixes元素。该元素标明以delimiter结尾,并有共同前缀的对象的集合 AmazonS3.listObjects接口提供两种调用方式:简单列举、通过ListObjectsRequest列举 简单列举 :::::::::::: 简单列举只需指定需要列举的桶名,最多返回100条对象记录,建议桶内对象数较少时(小于100)使用。 .. code:: java ObjectListing objectListing = AmazonS3.listObjects("your-bucketname"); List sums = objectListing.getObjectSummaries(); for (S3ObjectSummary s : sums) { System.out.println("\t" + s.getKey()); } 通过ListObjectsRequest列举 :::::::::::::::::::::::::::::::::::: 您还可以通过设置ListObjectsReques参数实现各种灵活的查询功能。ListObjectsReques的可设置的参数如下: .. list-table:: :widths: 10 10 :header-rows: 1 * - 设置方法 - 作用 * - setPrefix(String prefix) - 限定返回的object key必须以prefix作为前缀 * - setDelimiter(String delimiter) - 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素——CommonPrefixes * - setMarker(String marker) - 字典序的起始标记,只列出该标记之后的部分 * - setMaxKeys(Integer maxKeys) - 限定返回的数量,返回的结果小于或等于该值(默认值为100) 1、分页列举桶内的所有文件: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: java List listResult = new ArrayList(); ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); listObjectsRequest.setBucketName("your-bucketname"); listObjectsRequest.setMaxKeys(50); ObjectListing listObjects = AmazonS3.listObjects(listObjectsRequest); do { listResult.addAll(listObjects.getObjectSummaries()); if (listObjects.isTruncated()) { ListObjectsRequest request = new ListObjectsRequest(); request.setBucketName(listObjectsRequest.getBucketName()); request.setMarker(listObjects.getNextMarker()); listObjects = AmazonS3.listObjects(request); } else { break; } } while (listObjects != null); 2、使用Delimiter模拟文件夹功能 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 假设桶内有如下对象:a/1.jpg、a/2.jpg、a/b/1.txt、a/b/2.txt,列举a文件夹下的文件及子文件夹的示例代码如下: .. code:: java ListObjectsRequest listObjectsRequest = new ListObjectsRequest(); listObjectsRequest.setBucketName("your-bucketname"); listObjectsRequest.setDelimiter("/"); listObjectsRequest.setPrefix("a/"); ObjectListing listing = s3Client.listObjects(listObjectsRequest); // 遍历所有Object System.out.println("Objects:"); for (S3ObjectSummary objectSummary : listing.getObjectSummaries()) { System.out.println(objectSummary.getKey()); } // 遍历所有CommonPrefix System.out.println("CommonPrefixs:"); for (String commonPrefix : listing.getCommonPrefixes()) { System.out.println(commonPrefix); } 示例代码的输出如下: Objects: a/1.jpg a/2.jpg CommonPrefixs: a/b/ 生成私有对象可下载的URL链接 ```````````````````````````````` AWS Java SDK支持生成可下载私有对象的URL连接,您可以将该链接提供给第三方进行文件下载: .. code:: java GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key); // 设置可下载URL的过期时间为1天后 generatePresignedUrlRequest.setExpiration(new Date(System.currentTimeMillis()+3600*1000*24)); URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);//生成URL System.out.println(url);//可以用这个url来下载文件 文件上传下载工具类:TransferManager ------------------------------------------------------------ 前文提到的是NOS Java SDK提供的基础接口,为方便用户进行文件上传下载,NOS Java SDK提供了封装更好、使用更方便的工具类:TransferManager。 TransferManager的初始化 ````````````````````````````````` .. code:: java //先实例化一个AmazonS3 String accessKey = "your-accesskey"; String secretKey = "your-secretKey "; Credentials credentials = new BasicCredentials(accessKey, secretKey); AmazonS3 AmazonS3 = new AmazonS3(credentials); AmazonS3.setEndpoint(endPoint); //然后通过AmazonS3对象来初始化TransferManager TransferManager transferManager = new TransferManager(AmazonS3); Download download = transferManager.download(TestConfig.bucketName,key,new File("localFilePath")); try { download.waitForCompletion(); } catch (InterruptedException e) { e.printStackTrace(); } 使用TransferManager进行文件上传 ```````````````````````````````````````` TransferManager会根据文件大小,选择是否进行分块上传。当文件小于等于16M时,TransferManager会自动调用PutObject接口,否则TransferManager会自动对文件进行分块上传。 1、上传本地文件: 如果指定上传的本地文件大于16M,TransferManager会自动对文件进行分块,并发调用分块上传接口进行上传,大大提高上传文件的速度。 .. code:: java //上传文件 Upload upload = transferManager.upload("your-bucketname", "your-objectname", new File("your-file")); try { upload.waitForUploadResult(); } catch (InterruptedException e) { e.printStackTrace(); } 2、流式上传: 您也可以使用TransferManager进行流式上传,但是相比本地文件上传,流式上传无法做到多个分块并发上传,只能一个分块一个分块顺序上传。 .. code:: java //流式上传文件 ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(file.length()); Upload upload = transferManager.upload("your-bucketname", "your-objectname", inputStream, objectMetadata); UploadResult result = upload.waitForUploadResult(); 3、上传目录 您可以使用TransferManager将某个目录下的文件全部上传到NOS,对象名即文件名 3.1 不支持多级目录 .. code:: java MultipleFileUpload result = transferManager.uploadDirectory("your-buckename", null, new File("dirPath"), false); result.waitForCompletion(); 3.2 支持多级目录,会递归的上传目录下的所有文件 .. code:: java MultipleFileUpload result = transferManager.uploadDirectory("your-buckename", null, new File("dirPath"), true); result.waitForCompletion(); 4、下载文件 .. code:: java File file = new File("your-destFile"); Download download = transferManager.download("your-bucketname", "your-objectname", file); download.waitForCompletion();