使用流复制 Java - 丢失 data/bytes
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 文件或有时是视频文件时出现问题,出现错误 "File sizes mismatch."。当我比较源文件和目标文件大小时,大小确实不匹配,但打开后的图像似乎是完整的,视频也是。可见的问题是文本文件 - 在复制和丢失几个字节后,none 的内容丢失了,但在文件末尾有几行带有某种标记的 "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)
returns 读取的字节数。首先,您必须检查它是否大于或等于零,因为如果缓冲区大小为零,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
class,并避免使用 java.io.File
而使用 Path
,同时Paths
和 Files
.
中可用的操作
我对这种应该使用流复制文件的方法有疑问:
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 文件或有时是视频文件时出现问题,出现错误 "File sizes mismatch."。当我比较源文件和目标文件大小时,大小确实不匹配,但打开后的图像似乎是完整的,视频也是。可见的问题是文本文件 - 在复制和丢失几个字节后,none 的内容丢失了,但在文件末尾有几行带有某种标记的 "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)
returns 读取的字节数。首先,您必须检查它是否大于或等于零,因为如果缓冲区大小为零,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
class,并避免使用 java.io.File
而使用 Path
,同时Paths
和 Files
.