我们正在为应用引擎使用“Google云存储客户端库”,在文件创建时只需“GcsFileOptions.Builder.contentEncoding(”gzip“)”,我们在阅读文件时遇到以下问题:
com.google.appengine.tools.cloudstorage.NonRetriableException: java.lang.RuntimeException: com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl$1@1c07d21: Unexpected cause of ExecutionException
at com.google.appengine.tools.cloudstorage.RetryHelper.doRetry(RetryHelper.java:87)
at com.google.appengine.tools.cloudstorage.RetryHelper.runWithRetries(RetryHelper.java:129)
at com.google.appengine.tools.cloudstorage.RetryHelper.runWithRetries(RetryHelper.java:123)
at com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl.read(SimpleGcsInputChannelImpl.java:81)
...
Caused by: java.lang.RuntimeException: com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl$1@1c07d21: Unexpected cause of ExecutionException
at com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl$1.call(SimpleGcsInputChannelImpl.java:101)
at com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl$1.call(SimpleGcsInputChannelImpl.java:81)
at com.google.appengine.tools.cloudstorage.RetryHelper.doRetry(RetryHelper.java:75)
... 56 more
Caused by: java.lang.IllegalStateException: com.google.appengine.tools.cloudstorage.oauth.OauthRawGcsService$2@1d8c25d: got 46483 > wanted 19823
at com.google.common.base.Preconditions.checkState(Preconditions.java:177)
at com.google.appengine.tools.cloudstorage.oauth.OauthRawGcsService$2.wrap(OauthRawGcsService.java:418)
at com.google.appengine.tools.cloudstorage.oauth.OauthRawGcsService$2.wrap(OauthRawGcsService.java:398)
at com.google.appengine.api.utils.FutureWrapper.wrapAndCache(FutureWrapper.java:53)
at com.google.appengine.api.utils.FutureWrapper.get(FutureWrapper.java:90)
at com.google.appengine.tools.cloudstorage.SimpleGcsInputChannelImpl$1.call(SimpleGcsInputChannelImpl.java:86)
... 58 more
使用“gzip”压缩读取文件还应该添加什么才能读取应用引擎中的内容? (来自客户端的curl云存储URL适用于压缩和未压缩文件)
这是适用于未压缩对象的代码:
byte[] blobContent = new byte[0];
try
{
GcsFileMetadata metaData = gcsService.getMetadata(fileName);
int fileSize = (int) metaData.getLength();
final int chunkSize = BlobstoreService.MAX_BLOB_FETCH_SIZE;
LOG.info("content encoding: " + metaData.getOptions().getContentEncoding()); // "gzip" here
LOG.info("input size " + fileSize); // the size is obviously the compressed size!
for (long offset = 0; offset < fileSize;)
{
if (offset != 0)
{
LOG.info("Handling extra size for " + filePath + " at " + offset);
}
final int size = Math.min(chunkSize, fileSize);
ByteBuffer result = ByteBuffer.allocate(size);
GcsInputChannel readChannel = gcsService.openReadChannel(fileName, offset);
try
{
readChannel.read(result); <<<< here the exception was thrown
}
finally
{
......
现在压缩为:
GcsFilename filename = new GcsFilename(bucketName, filePath);
GcsFileOptions.Builder builder = new GcsFileOptions.Builder().mimeType(image_type);
builder = builder.contentEncoding("gzip");
GcsOutputChannel writeChannel = gcsService.createOrReplace(filename, builder.build());
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(blob_content.length);
try
{
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
try
{
zipStream.write(blob_content);
}
finally
{
zipStream.close();
}
}
finally
{
byteStream.close();
}
byte[] compressedData = byteStream.toByteArray();
writeChannel.write(ByteBuffer.wrap(compressedData));
blob_content从46483字节压缩到19823字节。
我认为这是谷歌代码的错误
Preconditions.checkState(content.length <= want, "%s: got %s > wanted %s", this, content.length, want);
HTTPResponse已经解码了blob,因此这里的Precondition是错误的。
答案 0 :(得分:0)
如果我理解你必须设置mineType:
GcsFileOptions options = new GcsFileOptions.Builder().mimeType("text/html")
Google云端存储不会压缩或解压缩对象: https://developers.google.com/storage/docs/reference-headers?csw=1#contentencoding
我希望这就是你想要做的。
答案 1 :(得分:0)
查看您的代码,似乎存储的内容与读取的内容之间存在不匹配。该文档指定不会为您执行压缩(https://developers.google.com/storage/docs/reference-headers?csw=1#contentencoding)。您需要手动进行实际压缩。
另外,如果你看一下抛出异常(https://code.google.com/p/appengine-gcs-client/source/browse/trunk/java/src/main/java/com/google/appengine/tools/cloudstorage/oauth/OauthRawGcsService.java?r=81&spec=svn134)的类的实现,你会注意到你得到了原始内容,但实际上你正在期待压缩内容。检查上面提到的类中的方法readObjectAsync。
看起来持久化的内容可能不会被gzip压缩或内容长度设置不正确。您应该做的是在将压缩流写入通道之前验证压缩流的长度。您还应验证在执行http请求时是否正确设置了内容长度。查看实际的http请求标头并确保内容长度标头与http响应中的实际内容长度匹配将很有用。
此外,看起来contentEncoding可能设置不正确。尝试使用此{3}}中使用的.contentEncoding("Content-Encoding: gzip")
。虽然最好的办法是检查HTTP请求和响应。您可以使用wireshark轻松完成此操作。
此外,您需要确保GCSOutputChannel在文件完成时关闭。
希望这会让你走上正轨。要抓取您的内容,您可以使用java test。
答案 2 :(得分:0)
我看到同样的问题,可以通过使用&#34; gsutil cp -Z&#34;上传文件轻松重现,然后尝试使用以下内容打开它
environment [var] [value]
这会导致如下异常:
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (GcsInputChannel readChannel = svc.openReadChannel(filename, 0)) {
try (InputStream input = Channels.newInputStream(readChannel))
{
IOUtils.copy(input, output);
}
}
我发现的唯一工作是使用readChannel.read将整个文件读入内存:
java.lang.IllegalStateException:
....oauth.OauthRawGcsService$2@1883798: got 64303 > wanted 4096
at ....Preconditions.checkState(Preconditions.java:199)
at ....oauth.OauthRawGcsService$2.wrap(OauthRawGcsService.java:519)
at ....oauth.OauthRawGcsService$2.wrap(OauthRawGcsService.java:499)
不幸的是,这只有在bytebuffer的大小大于或等于文件的未压缩大小时才有效,这是不可能通过api获得的。
我还发表了对谷歌注册的问题的评论:https://code.google.com/p/googleappengine/issues/detail?id=10445
答案 3 :(得分:0)
这是我读取压缩gzip文件的功能
public byte[] getUpdate(String fileName) throws IOException
{
GcsFilename fileNameObj = new GcsFilename(defaultBucketName, fileName);
try (GcsInputChannel readChannel = gcsService.openReadChannel(fileNameObj, 0))
{
maxSizeBuffer.clear();
readChannel.read(maxSizeBuffer);
}
byte[] result = maxSizeBuffer.array();
return result;
}
核心是您无法使用已保存文件的大小,因为 Google存储空间会以原始尺寸提供给您,因此它会检查您预期的尺寸和实际尺寸,这些是型动物:
Preconditions.checkState(content.length&lt; = want,“%s:得到%s&gt;想要 %s“,this,content.length,want);
所以我解决了使用BlobstoreService.MAX_BLOB_FETCH_SIZE
为这些文件分配最大数量的问题。实际上maxSizeBuffer
只分配一次超出函数
ByteBuffer maxSizeBuffer = ByteBuffer.allocate(BlobstoreService.MAX_BLOB_FETCH_SIZE);
使用maxSizeBuffer.clear();
,所有数据都会再次刷新。