将二进制文件保存到OutputStream并返回到InputStream

时间:2018-02-03 15:41:48

标签: java android

我有一个二进制文件,我上传到云存储。我必须将该文件写入输出流。然后当我想下载文件时,我需要从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; }
 }

}

1 个答案:

答案 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的每个字节都被改为输出文件中的三个字节。