在Java中使用流进行复制-丢失数据/字节



我有一个问题,这个方法应该使用流复制文件:

public static void copyFile() {
    String[] paths = readSrcDestFromConsole(); //returns String array with two strings - source and destination file paths
    InputStream is = null; OutputStream os = null;
    File src = null; File dest = null;
    boolean error = false;
    long elapsedTimeSeconds = 0;
    double speed = 0;
    try {
        src = new File(paths[0]);
    }catch(Exception ex){
        System.err.println("File read from could not be opened.");
        error = true;
    }
    if(!error) {
        try {
            dest = new File(paths[1]);
        }catch(Exception ex){
            System.err.println("File written to could not be created.");
            error = true;
        }
        if(src.exists() && !error) {
            if(dest.exists()) {
                System.out.println("File specified already exists. Do you want to overwrite it?");
                if(askForOverwrite()) { // gets Y or N from console using scanner and returns a boolean
                    try {
                        is = new FileInputStream(src);
                        os = new FileOutputStream(dest);
                        System.out.println("Copying from: " + paths[0] + " to: " + paths[1]);
                        byte[] buffer = new byte[4096];
                        double read = 0;
                        long first = 0;
                        long second = 0;
                        long startTime = System.nanoTime();
                        while(is.read(buffer) > 0) {
                            read += buffer.length;
                            os.write(buffer);
                            first = Math.round(read / src.length() * 100);
                            if(first != second) {
                                System.out.println(first + " % copied.");
                            }
                            second = Math.round(read / src.length() * 100);
                        }
                        elapsedTimeSeconds = (System.nanoTime() - startTime) / 1_000_000_000;
                        speed = (src.length() / 1024 / 1024) / elapsedTimeSeconds;
                        is.close(); os.close();
                    }catch(Exception ex){
                        System.err.println("File is or has been corrupted.");
                        error = true;
                    }finally{
                        if(!error) {
                            if(src.length() == dest.length()) {
                                System.out.println("File copied successfully.");
                                System.out.println("Total size copied: " + ((dest.length()) / 1024 / 1024) + " MB");
                                System.out.println("Copying speed: " + speed + " MB/s" + " in " + elapsedTimeSeconds + " seconds.");
                            }else{
                                System.err.println("Error: " + "File sizes mismatch.");
                            }
                        }
                    }
                }else{
                    System.out.println("File has not been rewritten.");
                }
            }else{
                try {
                    is = new FileInputStream(src);
                    os = new FileOutputStream(dest);
                    System.out.println("Copying from: " + paths[0] + " to: " + paths[1]);
                    byte[] buffer = new byte[4096];
                    double read = 0;
                    long first = 0;
                    long second = 0;
                    long startTime = System.nanoTime();
                    while(is.read(buffer) > 0) {
                        read += buffer.length;
                        os.write(buffer);
                        first = Math.round(read / src.length() * 100);
                        if(first != second) {
                            System.out.println(first + " % copied.");
                        }
                        second = Math.round(read / src.length() * 100);
                    }
                    elapsedTimeSeconds = (System.nanoTime() - startTime) / 1_000_000_000;
                    speed = (src.length() / 1024 / 1024) / elapsedTimeSeconds;
                    is.close(); os.close();
                }catch(Exception ex){
                    System.err.println("File is or has been corrupted.");
                    error = true;
                }finally{
                    if(!error) {
                        if(src.length() == dest.length()) {
                            System.out.println("File copied successfully.");
                            System.out.println("Total size copied: " + ((dest.length()) / 1024 / 1024) + " MB");
                            System.out.println("Copying speed: " + speed + " MB/s" + " in " + elapsedTimeSeconds + " seconds.");
                        }else{
                            System.err.println("Error: " + "File sizes mismatch.");
                        }
                    }
                }
            }
        }else{
            System.err.println("File specified does not exist.");
        }
    }else{
        System.err.println("Operation could not be completed.");
    }
}

问题发生时,例如复制图像,文本文件或有时视频文件,错误"文件大小不匹配"发生。当我比较源文件和目标文件的大小时,大小确实不匹配,但打开后的图像似乎是完整的,视频也是如此。可见的问题是文本文件-在复制和丢失几个字节后,没有内容丢失,但在文件的末尾有几行带有某种标记的"NUL"-使用notepad++查看这些。

我尝试使用文件中的copy()方法,它可以正常工作,但我找不到为什么我的方法会丢失字节。

非常感谢你的帮助,我到处都找不到解决办法。

读循环是问题所在:

while(is.read(buffer) > 0) {
    read += buffer.length;
    os.write(buffer);
    first = Math.round(read / src.length() * 100);
    if(first != second) {
        System.out.println(first + " % copied.");
    }
    second = Math.round(read / src.length() * 100);
}

is.read(buffer)返回读取的字节数。首先,你必须检查它是否大于或等于0,因为read的契约允许它读取0字节,如果缓冲区的大小为0。但除此之外,你需要保持这个值,因为你只需要写你读的字节数。

通常,文件的大小不是4096的整数倍。因此,最后一次读取将读取少于4096字节。read合约实际上说,即使在此之前,如果可用字节较少,它也可以读取少于4096的数据。

因此,如果你没有完全写入你所读的内容,那么你所写的缓冲区的一部分将包含前一次读取的值,如果文件小于4096字节,则为零。

所以更正为:

int numRead;
while( (numRead = is.read(buffer)) >= 0) {
    read += numRead;
    os.write(buffer,0,numRead);
    first = Math.round(read / src.length() * 100);
    if(first != second) {
        System.out.println(first + " % copied.");
    }
    second = Math.round(read / src.length() * 100);
}

但是,实际上,每当您的副本涉及至少一个文件时,建议使用Files类,并且避免使用java.io.File而使用Path,并在PathsFiles中提供操作。

相关内容

  • 没有找到相关文章

最新更新