[英]Copying in Java using streams - losing data/bytes
我對此方法有問題,該方法應該使用流復制文件:
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.");
}
}
當復制例如圖像,.txt文件或有時復制視頻文件時,會出現問題,錯誤為“文件大小不匹配”。 發生。 當我比較源文件和目標文件的大小時,大小確實不匹配,但是打開后的圖像似乎很完整,視頻也是如此。 文本文件存在明顯的問題-復制並丟失了幾個字節后,沒有丟失任何內容,但是在文件的末尾有幾行帶有某種標記為“ NUL”的標記-使用Notepad ++查看這些內容。
我嘗試使用Files中的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)
返回讀取的字節數。 首先,您必須檢查它是否大於或等於零,因為如果緩沖區的大小為零,則read
的約定允許它讀取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
類,並避免使用支持Path
java.io.File
,而Paths
和Files
提供了操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.