简体   繁体   中英

I'm having trouble writing copy large files

I'm having problems with my code, I'm encrypting a file with more than 300mb in base 64 but my application gives errors when I open the lra encrypt file

this is my code crashes on the byte, i don't understand why

private void encript(final File file) {
    new AsyncTask<Void, Void, Void>() {

        @Override
        protected Void doInBackground(Void[] p) {
            File new_file = null;
            try {
                new_file = new File(file.getAbsolutePath() + ".enc.txt");
                if (!new_file.exists()) {
                    new_file.createNewFile();
                }
                BufferedInputStream mInputStream = new BufferedInputStream(new FileInputStream(file));
                OutputStream mOutputStream = new DataOutputStream(new FileOutputStream(new_file));
                byte[] data = new byte[mInputStream.available()];
                int len = 0;
                
                while (true) {
                    len = mInputStream.read(data);
                    if (len > 0) {
                        mOutputStream.write(Base64.encode(data, 0, len, Base64.DEFAULT));
                    }
                    break;
                }
                mOutputStream.flush();
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
                if (mInputStream != null) {
                    mInputStream.close();
                }
            } catch (Exception io) {
                Toast.makeText(MainActivity.this, io.toString(), Toast.LENGTH_LONG).show();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void res) {
            Toast.makeText(MainActivity.this, "Sucesss", Toast.LENGTH_LONG).show();
        }
    }.execute(new Void[0]);
    
}

Note that what you are doing here is Base64 encoding the file contents. Don't imagine that someone can't trivially crack this (so-called) "encryption".

There are lots of things wrong with your attempt. I shall go through the more important ones:

    @Override
    protected Void doInBackground(Void[] p) {
        File new_file = null;
        try {

Problem: You should be using try with resources to avoid resource leaks.

            new_file = new File(file.getAbsolutePath() + ".enc.txt");
            if (!new_file.exists()) {
                new_file.createNewFile();
            }

Problems:

  1. On the one hand, there is no need to use createNewFile to pre-create an output file. Opening the file using FileOutputStream will create it if it doesn't exist already.

  2. On the other hand, this won't prevent (or report) errors in cases where the file's parent directory doesn't exist, is not writeable and so on.

  3. It would be better to use java.nio.file.Path and java.nio.file.Files from Java 7 / Android API 26. Path and Files are better APIs and they will report problems as exceptions so that you can (hypothetically) report them to the user via your exception handler.

    There are even some Files.copy methods, though they are not directly applicable to your use-case since you are encoding the data as you copy it.

     BufferedInputStream mInputStream = new BufferedInputStream(new FileInputStream(file)); OutputStream mOutputStream = new DataOutputStream(new FileOutputStream(new_file));

Problem:

I don't think you need a DataOutputStream . It won't actually be doing anything.

            byte[] data = new byte[mInputStream.available()];

Problem:

The available() method should not be used for this. It returns the number of bytes that are "available" to be read right now. The value you get is context dependent. For a socket stream it is typically the number of bytes that are currently in the kernel buffers ready to read. For a "regular" file it may be the length of the input file.

So if you are copying a "really big" file, then you may be attempting to allocate a buffer that will hold the entire file. In the worst case, that will cause your app to OOME!

NOTE - Such an OOME might be the "out of nowhere" problem that you are seeing.

The "best" way is debatable, but I would just use a fixed buffer size... if I was doing an explicit read / write copy of a stream. The size of the buffer affects throughput, but if you are looking for ultimate performance you shouldn't be doing it this way.

            int len = 0;
            
            while (true) {
                len = mInputStream.read(data);
                if (len > 0) {
                    mOutputStream.write(
                        Base64.encode(data, 0, len, Base64.DEFAULT));
                }
                break;
            }

Problem: This loop is simply wrong. You are unconditionally breaking on the first iteration. You should be doing something like this:

int len;
while ((len = mInputStream.read(data)) > 0) {
    mOutputStream.write(Base64.encode(data, 0, len, Base64.DEFAULT));
}

In other words, keep reading / writing until read returns a non-positive result.

Note: I'm not sure which Base64 class you are using there. It doesn't appear to be java.util.Base64

            mOutputStream.flush();
            if (mOutputStream != null) {
                mOutputStream.close();
            }
            if (mInputStream != null) {
                mInputStream.close();
            }

Problems:

  1. The flush() is not necessary. Closing the stream will flush. And besides, what happens with your attempted flush if mOutputStream is null .

  2. This version leaks resources (file descriptors). If an exception has been thrown, these statements won't be executed, and the stream objects will not be closed.

  3. This is all unnecessary if you use try with resources instead.

     } catch (Exception io) { Toast.makeText(MainActivity.this, io.toString(), Toast.LENGTH_LONG).show(); } return null; }

Problems:

  1. Catching Exception is a bad idea. A better idea is to catch and handle the expected exceptions, and let the unexpected ones propagate so that they can be handled further up the stack.

    In this case, it looks like you are assuming that the exception will be some sort of I/O exception. In fact, it could also be an unchecked exception such as an NPE. (An OOME is also possible, though this catch wouldn't catch that because OOMEs are Error exceptions.)

  2. You are throwing away the exception details. Unexpected exceptions should be logged so that you can diagnose them via logcat.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM