简体   繁体   English

Java FileInputStream FileOutputStream 在运行中的区别

[英]Java FileInputStream FileOutputStream difference in the run

Could someone tell me why the 1. run is wrong?有人可以告诉我为什么 1. run 是错误的吗? (The return code is 0, but the file written is only half of the original one. (返回码为0,但写入的文件只有原来的一半。

Thanks in advance!提前致谢!

public class FileCopyFisFos {

    public static void main(String[] args) throws IOException {

        FileInputStream fis = new FileInputStream("d:/Test1/OrigFile.MP4");
        FileOutputStream fos = new FileOutputStream("d:/Test2/DestFile.mp4");

// 1. run
//        while (fis.read() != -1){
//            int len = fis.read();
//            fos.write(len);
//        }

// 2. run
//        int len;
//        while ((len = fis.read()) != -1){
//            fos.write(len);
//        }

        fis.close();
        fos.close();
    }
}

FileInputStream 's read() method follows this logic: FileInputStreamread()方法遵循以下逻辑:

Reads a byte of data from this input stream.从此输入 stream读取一个字节的数据 This method blocks if no input is yet available.如果还没有输入可用,则此方法会阻塞。

So assigning the value of its return to a variable, such as:所以将其返回的值赋给一个变量,如:

while((len = fis.read())!= -1) 

Is avoiding the byte of data just read from the stream to be forgotten, as every read() call will be assigned to your len variable.避免忘记刚刚从 stream 读取的数据字节,因为每个read()调用都将分配给您的len变量。


Instead, this code bypasses one of every two bytes from the stream, as the read() executed in the while condition is never assigned to a variable.相反,此代码绕过来自 stream 的每两个字节之一,因为在while条件中执行的read()从未分配给变量。 So the stream advances without half of the bytes being read (assigned to len ):因此 stream 前进而没有读取一半字节(分配给len ):

while (fis.read() != -1) {      // reads a byte of data (but not saved)
   int len = fis.read();        // next byte of data saved
   fos.write(len);              // possible -1 written here    
}

@aran and others already pointed out the solution to your problem. @aran 和其他人已经指出了您的问题的解决方案。

However there are more sides to this, so I extended your example:但是,还有更多方面,因此我扩展了您的示例:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopyFisFos {

    public static void main(final String[] args) throws IOException {
        final File src = new File("d:/Test1/OrigFile.MP4");
        final File sink = new File("d:/Test2/DestFile.mp4");

        {
            final long startMS = System.currentTimeMillis();
            final long bytesCopied = copyFileSimple(src, sink);
            System.out.println("Simple copy transferred " + bytesCopied + " bytes in " + (System.currentTimeMillis() - startMS) + "ms");
        }
        {
            final long startMS = System.currentTimeMillis();
            final long bytesCopied = copyFileSimpleFaster(src, sink);
            System.out.println("Simple+Fast copy transferred " + bytesCopied + " bytes in " + (System.currentTimeMillis() - startMS) + "ms");
        }
        {
            final long startMS = System.currentTimeMillis();
            final long bytesCopied = copyFileFast(src, sink);
            System.out.println("Fast copy transferred " + bytesCopied + " bytes in " + (System.currentTimeMillis() - startMS) + "ms");
        }

        System.out.println("Test completed.");
    }

    static public long copyFileSimple(final File pSourceFile, final File pSinkFile) throws IOException {
        try (
                final FileInputStream fis = new FileInputStream(pSourceFile);
                final FileOutputStream fos = new FileOutputStream(pSinkFile);) {

            long totalBytesTransferred = 0;
            while (true) {
                final int readByte = fis.read();
                if (readByte < 0) break;

                fos.write(readByte);
                ++totalBytesTransferred;
            }
            return totalBytesTransferred;
        }
    }

    static public long copyFileSimpleFaster(final File pSourceFile, final File pSinkFile) throws IOException {
        try (
                final FileInputStream fis = new FileInputStream(pSourceFile);
                final FileOutputStream fos = new FileOutputStream(pSinkFile);
                BufferedInputStream bis = new BufferedInputStream(fis);
                BufferedOutputStream bos = new BufferedOutputStream(fos);) {

            long totalBytesTransferred = 0;
            while (true) {
                final int readByte = bis.read();
                if (readByte < 0) break;

                bos.write(readByte);
                ++totalBytesTransferred;
            }
            return totalBytesTransferred;
        }
    }

    static public long copyFileFast(final File pSourceFile, final File pSinkFile) throws IOException {
        try (
                final FileInputStream fis = new FileInputStream(pSourceFile);
                final FileOutputStream fos = new FileOutputStream(pSinkFile);) {

            long totalBytesTransferred = 0;
            final byte[] buffer = new byte[20 * 1024];
            while (true) {
                final int bytesRead = fis.read(buffer);
                if (bytesRead < 0) break;

                fos.write(buffer, 0, bytesRead);
                totalBytesTransferred += bytesRead;
            }
            return totalBytesTransferred;
        }
    }

}

The hints that come along with that code:该代码附带的提示:

  • There is the java.nio package that usualy does those things a lot faster and in less code.有 java.nio package 通常可以用更少的代码更快地完成这些事情。
  • Copying single bytes is 1'000-40'000 times slower that bulk copy.复制单个字节比批量复制慢 1'000-40'000 倍。
  • Using try/resource/catch is the best way to avoid problems with reserved/locked resources like files etc.使用 try/resource/catch 是避免保留/锁定资源(如文件等)问题的最佳方法。
  • If you solve something that is quite commonplace, I suggest you put it in a utility class of your own or even your own library.如果您解决了一些很常见的问题,我建议您将其放入您自己的实用程序 class 甚至您自己的库中。
  • There are helper classes like BufferedInputStream and BufferedOutputStream that take care of efficiency greatly;有像 BufferedInputStream 和 BufferedOutputStream 这样的辅助类,它们非常注重效率; see example copyFileSimpleFaster().请参见示例 copyFileSimpleFaster()。
  • But as usual, it is the quality of the concept that has the most impact on the implementation;但像往常一样,对实施影响最大的是概念的质量。 see example copyFileFast().请参阅示例 copyFileFast()。
  • There are even more advanced concepts (similar to java.nio), that take into account concepts like OS caching behaviour etc, which will give performance another kick.还有更高级的概念(类似于 java.nio),它们考虑了操作系统缓存行为等概念,这将给性能带来新的提升。

Check my outputs, or run it on your own, to see the differences in performance:检查我的输出,或自己运行它,以查看性能差异:

Simple copy transferred 1608799 bytes in 12709ms
Simple+Fast copy transferred 1608799 bytes in 51ms
Fast copy transferred 1608799 bytes in 4ms
Test completed.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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