我有一个二进制文件,我上传到云存储。我必须将该文件写入输出流。然后当我想下载文件时,我需要从InputStream中读取它的内容。但是,我没有得到相同的文件。以下是一个完整的工作代码,但有这个bug。排除云和其他代码,因为问题不存在。
我已经阅读了Java文档来构建从流中读取和写入但我无法找到问题所在 - 为什么在写入输出流然后从输入流中读取后,我得到不同的数据。任何建议将不胜感激!
public class TActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create any binary file, e.g., a DB file
String dbName = "bed872bc-bc8f-4429-8126-070a48c13bdf"; // Just a random UUID
try (SQLiteDatabase db = openOrCreateDatabase(dbName, Context.MODE_PRIVATE, null)) { ; };
try {
// Write the binary file into Output stream
File originalFile = getDatabasePath(dbName);
long originalFileLength = originalFile.length();
ByteArrayOutputStream memoryStreamOut = new ByteArrayOutputStream();
WriteFromFile(memoryStreamOut, originalFile.toString());
// Write from the memory stream into the file - expected result is that we end up with identical file content as the original file
ByteArrayInputStream memoryStreamIn = new ByteArrayInputStream(memoryStreamOut.toByteArray());
File againTheSameFile = CreateTemporaryFileSafe(this);
WriteToFile(memoryStreamIn, againTheSameFile);
// Check whether the files have same size - they should have because they should be identical
long newFileLength = againTheSameFile.length();
if (newFileLength != originalFileLength) {
// it ends up here - they don't equal!
}
}
catch (Exception E) {
// Log ...
}
}
public static void WriteFromFile(OutputStream outputStream, String filePath) throws Exception {
try (Writer writer = new OutputStreamWriter(outputStream)) {
try (FileInputStream fileinputstream = new FileInputStream(filePath)) {
byte[] buffer = new byte[64 * 1024];
int length;
while ((length = fileinputstream.read(buffer)) != -1) {
writer.write(new String(buffer, 0, length));
}
}
}
}
public static void WriteToFile(InputStream inputStream, File file) throws Exception {
try (DataInputStream reader = new DataInputStream(inputStream)) {
try (DataOutputStream fileOutputStream = new DataOutputStream(new FileOutputStream(file))) {
byte[] buffer = new byte[64 * 1024];
int length;
while ((length = reader.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, length);
}
}
}
}
public static File CreateTemporaryFileSafe(Context context) {
try { return File.createTempFile(UUID.randomUUID().toString(), "tmp", context.getCacheDir()); }
catch (IOException E) { return null; }
}
}
答案 0 :(得分:1)
简短回答:你的二进制数据被来自bytes-> string然后string->字节的(不必要的)转换破坏了。而只是将其作为字节读取,然后将其写为字节:
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
class Foo {
private static void copyStream(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[64*1024];
int length;
while ((length = input.read(buffer)) != -1) {
output.write(buffer,0,length);
}
}
private static void copyFile(String inputPath, String outputPath) throws IOException {
try (
FileInputStream input = new FileInputStream(inputPath);
FileOutputStream output = new FileOutputStream(outputPath)
) {
copyStream(input, output);
}
}
public static void main(String[] args) throws IOException {
copyFile(args[0], args[1]);
}
}
更长的答案是,当您使用String(bytes,0,len)将字节转换为String时,java将使用JVM的默认字符集(可能是UTF-8)进行转换。但是你的文件不是 UTF-8编码的文本,它是随机字节。而且这些字节中的很多都不是正确的UTF-8。 Java将使用unicode“REPLACEMENT CHARACTER”(\ uFFFD)静默替换每个非法字节。
然后当你把它写回来时,你使用了OutputStreamWriter(OutputStream),它使用默认字符集将你已经损坏的数据转换回字节。假设默认编码为UTF-8,则替换字符的每个实例都将替换为该字符的UTF-8编码,即字节0xef 0xbf 0xbd。即把它变成三个字节。这就是为什么你的文件大小改变了:输入文件中发生的不合法UTF-8的每个字节都被改为输出文件中的三个字节。