概述
由于云技术的日益成熟,越来越多的公司存储文件时会用到云技术,而亚马逊就提供了一个日益成熟的云环境的服务器群方便存储的文件。
Amazon Simple Storage Service (Amazon S3) 是一种对象存储服务,提供行业领先的可扩展性、数据可用性、安全性和性能。这意味着各种规模和行业的客户都可以使用 S3 来存储并保护各种用例(如数据湖、网站、移动应用程序、备份和还原、存档、企业应用程序、IoT 设备和大数据分析)的数据,容量不限。Amazon S3 提供了易于使用的管理功能,因此您可以组织数据并配置精细调整过的使用权限控制,从而满足特定的业务、组织和合规性要求。Amazon S3 可达到 99.999999999%(11 个 9)的持久性,并为全球各地的公司存储数百万个应用程序的数据。
下面介绍下在net环境下如何实现文件上传到AWS。
主要实现方式
1、定义接口IRemoteFile。
public interface IRemoteFile
{
string Upload(string sourceFile, string relativePath, string bucketName = null);
bool Delete(string url);
Stream Download(string relativePath, string bucketName);
long ComputeSize(string relativePath, string[] excludeKeywords);
}
2、实现方法,例如上传Upload方法。
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static IAmazonS3 client;
private string _bucketName = MvcTools.GetAppSetting("AmazonS3Bucket");
// 堆代码 duidaima.com
public string Upload(string sourceFile, string relativePath, string bucketName = null)
{
if (bucketName != null)
{
_bucketName = bucketName;
}
else
{
_bucketName = MvcTools.GetAppSetting("AmazonS3Bucket");
}
string resultUrl = string.Empty;
bool success = false;
using (client = new AmazonS3Client())
{
try
{
PutObjectResponse putObjectResponse = client.PutObject(new PutObjectRequest
{
BucketName = _bucketName,
FilePath = sourceFile,
Grants = new List<S3Grant>() {
new S3Grant()
{
Permission = S3Permission.READ,
Grantee = new S3Grantee { URI = "http://acs.amazonaws.com/groups/global/AllUsers" }
}
},
Key = relativePath,
});
success = putObjectResponse.HttpStatusCode == System.Net.HttpStatusCode.OK;
if (!success)
{
logger.Error(putObjectResponse.ToJsonString());
}
else
{
resultUrl = string.Format("http://{0}.s3.amazonaws.com/{1}"
, _bucketName
, relativePath
);
}
}
catch (AmazonS3Exception ex)
{
logger.Error(ex.Message);
}
}
return ConvertS3Url(resultUrl);
}
3、配置AWS信息。
<!--AWS start-->
<add key="AWSAccessKey" value="xxxx"/>
<add key="AWSSecretKey" value="xxxxx"/>
<add key="AmazonS3WebBucket" value="xxxx"/>
<!--AWS end-->
4、调用上传方法,实现文件上传。
public string UploadRemote(string filePath, Inner_Download_Report model, IRemoteFile remoteFile)
{
var txtRelativePath = GetRelativeFilePath(model.Locale, model.Account, "Report", SetTxtFileName());
return remoteFile.Upload(filePath, txtRelativePath, MvcTools.GetAppSetting("AmazonS3WebBucket"));
}
完整代码
public class AmazonS3 : IRemoteFile
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private static IAmazonS3 client;
private string _bucketName = MvcTools.GetAppSetting("AmazonS3Bucket");
public string Upload(string sourceFile, string relativePath, string bucketName = null)
{
if (bucketName != null)
{
_bucketName = bucketName;
}
else
{
_bucketName = MvcTools.GetAppSetting("AmazonS3Bucket");
}
string resultUrl = string.Empty;
bool success = false;
using (client = new AmazonS3Client())
{
try
{
PutObjectResponse putObjectResponse = client.PutObject(new PutObjectRequest
{
BucketName = _bucketName,
FilePath = sourceFile,
Grants = new List<S3Grant>() {
new S3Grant()
{
Permission = S3Permission.READ,
Grantee = new S3Grantee { URI = "http://acs.amazonaws.com/groups/global/AllUsers" }
}
},
Key = relativePath,
});
success = putObjectResponse.HttpStatusCode == System.Net.HttpStatusCode.OK;
if (!success)
{
logger.Error(putObjectResponse.ToJsonString());
}
else
{
resultUrl = string.Format("http://{0}.s3.amazonaws.com/{1}"
, _bucketName
, relativePath
);
}
}
catch (AmazonS3Exception ex)
{
logger.Error(ex.Message);
}
}
return ConvertS3Url(resultUrl);
}
public bool Delete(string url)
{
bool success = false;
if (url == null)
{
return false;
}
var (isMatchSuccess, bucketName, filePath) = MatchS3Url(url);
if (!isMatchSuccess)
{
logger.Info("regex match fail, remoteUrl: {0}", url);
}
else
{
using (client = new AmazonS3Client())
{
try
{
DeleteObjectResponse deleteObjectResponse = client.DeleteObject(new DeleteObjectRequest
{
BucketName = bucketName,
Key = filePath,
});
success = deleteObjectResponse.HttpStatusCode == System.Net.HttpStatusCode.NoContent;
if (!success)
{
logger.Info(deleteObjectResponse.ToJsonString());
}
}
catch (AmazonS3Exception ex)
{
logger.Error(ex.Message);
}
}
}
return success;
}
public long ComputeSize(string relativePath, string[] excludeKeywords)
{
using (client = new AmazonS3Client())
{
try
{
ListObjectsResponse listObjectsResponse = client.ListObjects(new ListObjectsRequest
{
BucketName = _bucketName,
Prefix = relativePath,
MaxKeys = int.MaxValue
});
if (listObjectsResponse.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
return listObjectsResponse.S3Objects
.Where(r => NotContainKeyword(excludeKeywords, r.Key))
.Sum(r => r.Size);
}
else
{
logger.Info(listObjectsResponse.ToJsonString());
}
}
catch (AmazonS3Exception ex)
{
logger.Error(ex.Message);
}
}
return 0;
}
private bool NotContainKeyword(string[] keywords, string value)
{
if (keywords == null || keywords.Length == 0)
{
return true;
}
else
{
foreach (var key in keywords)
{
if (value.IndexOf(key) >= 0)
{
return false;
}
}
}
return true;
}
public Stream Download(string relativePath, string bucketName)
{
_bucketName = bucketName;
bool success = false;
GetObjectResponse getObjectResponse = new GetObjectResponse();
using (client = new AmazonS3Client())
{
try
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = bucketName,
Key = relativePath
};
getObjectResponse = client.GetObject(request);
// using (responseStream = getObjectResponse.ResponseStream)
success = getObjectResponse.HttpStatusCode == System.Net.HttpStatusCode.OK;
if (!success)
{
logger.Error(getObjectResponse.ToJsonString());
return null;
}
}
catch (AmazonS3Exception ex)
{
logger.Error(ex.Message);
return null;
}
}
return getObjectResponse.ResponseStream;
}
/// <summary>
/// from: http://(bucket).s3.amazonaws.com/(filePath)
/// to: https://s3-us-west-2.amazonaws.com/(bucket)/(filePath)
/// </summary>
/// <param name="url"></param>
/// <param name="awsRegion"></param>
/// <returns></returns>
public static string ConvertS3Url(string url, string awsRegion = "s3-us-west-2")
{
// from: http://amz.file.s3.amazonaws.com/us/67420000/logo/logo.jpg
// to: https://s3-us-west-2.amazonaws.com/amz.file/us/67420000/logo/logo.jpg
if (string.IsNullOrWhiteSpace(url))
{
return url;
}
var (isMatchSuccess, bucketName, filePath) = MatchS3Url(url, awsRegion);
if (isMatchSuccess)
{
return $"https://{awsRegion}.amazonaws.com/{bucketName}/{filePath}";
}
return url;// fail
}
/// <summary>
/// Get [bucketName, filePath] from url
/// </summary>
/// <param name="url">S3 url format: [http://(bucket).s3.amazonaws.com/(filePath) , https://s3-us-west-2.amazonaws.com/(bucket)/(filePath)]</param>
/// <param name="awsRegion"></param>
/// <returns></returns>
public static (bool isMatchSuccess, string bucketName, string filePath) MatchS3Url(string url, string awsRegion = "s3-us-west-2")
{
List<Regex> partternList = new List<Regex>
{
new Regex("http://(?<bucket>.*?).s3.amazonaws.com/(?<filePath>.*)", RegexOptions.IgnoreCase),
new Regex($"http[s]?://{awsRegion}.amazonaws.com/(?<bucket>.*?)/(?<filePath>.*)", RegexOptions.IgnoreCase),
};
foreach (var parttern in partternList)
{
var match = parttern.Match(url);
if (match.Success)
{
string bucket = match.Groups["bucket"].Value;
string filePath = match.Groups["filePath"].Value;
return (true, bucket, filePath);
}
}
logger.Warn("regex match fail, url: {0}", url);
return (false, null, null);
}
}