我正在尝试将一些大文件从Android设备上传到.Net Web服务。该Web服务已经设置为接受这些文件作为POST参数,并且这些文件必须作为Base64编码的字符串发送。
我能够使用Christian d'Heureuse的这个库将文件转换为Base64字符串,计算字符串大小并在此之前将其发送上去,但我以前使用的方法涉及将整个文件加载到内存中,处理大型文件时会导致内存不足错误,这不是意料之外的事情。
我一直在尝试将文件分块转换为Base64,并在连接中流式传输此数据(使用数据输出流对象)进行转换,因此不需要一次性将整个文件加载到内存中,但是在转换文件之前,我似乎无法准确地计算请求的Content-Length大小-通常会有约10个字节的误差-令人沮丧的是,它偶尔可以工作!
我还发现,有时候当这样做时,服务器会返回以下错误消息“无效的Base64字符数组大小”。我认为这是填充字符的问题,但是我无法看到我的代码哪里出了问题,请给我关于这个问题的建议!
这是生成请求并流式传输数据的代码:
我会非常感激如果有人能指出我的代码中可能导致这个问题的错误,或者建议更好的转换和上传文件的方式。
我能够使用Christian d'Heureuse的这个库将文件转换为Base64字符串,计算字符串大小并在此之前将其发送上去,但我以前使用的方法涉及将整个文件加载到内存中,处理大型文件时会导致内存不足错误,这不是意料之外的事情。
我一直在尝试将文件分块转换为Base64,并在连接中流式传输此数据(使用数据输出流对象)进行转换,因此不需要一次性将整个文件加载到内存中,但是在转换文件之前,我似乎无法准确地计算请求的Content-Length大小-通常会有约10个字节的误差-令人沮丧的是,它偶尔可以工作!
我还发现,有时候当这样做时,服务器会返回以下错误消息“无效的Base64字符数组大小”。我认为这是填充字符的问题,但是我无法看到我的代码哪里出了问题,请给我关于这个问题的建议!
这是生成请求并流式传输数据的代码:
try
{
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
//This is the path to the file
String pathToOurFile = Environment
.getExternalStorageDirectory().getPath()
+ "/path/to/the/file.zip";
String urlServer = "https://www.someserver.com/somewebservice/";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 456;
//The parameters of the POST request - File Data is the file in question as a Base64 String
String params = "Username=foo&Password=bar&FileData=";
File sizeCheck = new File(pathToOurFile);
Integer zipSize = (int) sizeCheck.length();
Integer paddingRequired = ((zipSize * 8) / 6) % 3;
Integer base64ZipSize = ((zipSize * 8) / 6)
+ ((zipSize * 8) / 6) % 3;
Integer paramLength = params.getBytes().length;
//Code to work out the number of lines required, assuming we create a new
//line every 76 characters - this is used t work out the number of
//extra bytes required for new line characters
Integer numberOfLines = base64ZipSize / 76;
Log.i(TAG, "numberOfLines: " + numberOfLines);
Integer newLineLength = System.getProperty("line.separator")
.getBytes().length;
//This works out the total length of the Content
Integer totalLength = paramLength + base64ZipSize
+ (numberOfLines * newLineLength) + paddingRequired;
Log.i(TAG, "total Length: " + totalLength);
FileInputStream fileInputStream = new FileInputStream(new File(
pathToOurFile));
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;");
connection.setRequestProperty("Content-Length", ""
+ totalLength); // number of bytes
outputStream = new DataOutputStream(
connection.getOutputStream());
//Write out the parameters to the data output stream
outputStream.writeBytes(params);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
Integer totalSent = paramLength;
Integer enLen = 0;
//Convert the file to Base64 and Stream the result to the
//Data output stream
while (bytesRead > 0)
{
String convetedBase64 = Base64Coder.encodeLines(buffer);
convetedBase64 = convetedBase64.replace("=", "");
if (totalSent >= (totalLength - 616))
{
Log.i(TAG, "about to send last chunk of data");
convetedBase64 = convetedBase64.substring(0,
convetedBase64.length() - 1);
}
Log.i(TAG,
"next data chunk to send: "
+ convetedBase64.getBytes().length);
Log.i(TAG, "'" + convetedBase64 + "'");
enLen = enLen + convetedBase64.length();
outputStream.writeBytes(convetedBase64);
totalSent = totalSent + convetedBase64.getBytes().length;
Log.i(TAG, "total sent " + totalSent);
Log.i(TAG, "actual size: " + outputStream.size());
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize); // read
// into
// the
// buffer
}
Log.i(TAG, "enLen: " + enLen);
Log.i(TAG, "paddingRequired: " + paddingRequired);
for (int x = 0; x < paddingRequired; x++)
{
outputStream.writeBytes("=");
}
InputStream is2 = connection.getInputStream();
String output = IOUtils.toString(is2);
Log.i(TAG, "Got server response: " + output);
fileInputStream.close();
outputStream.flush();
outputStream.close();
}
catch (Exception ex)
{
Log.e(TAG, "caught an exception:" + ex.getMessage());
}
我会非常感激如果有人能指出我的代码中可能导致这个问题的错误,或者建议更好的转换和上传文件的方式。